Letter-space in android-text view [duplicate] - java

How can i change letter spacing in a textview?
Will it help if I have HTML text in it (I cannot use webview in my code).
P.S. I'm using my own typeface in the textview with HTML text.

Since API 21 there is an option set letter spacing. You can call method setLetterSpacing or set it in XML with attribute letterSpacing.

More space:
android:letterSpacing="0.1"
Less space:
android:letterSpacing="-0.07"

check out android:textScaleX
Depending on how much spacing you need, this might help. That's the only thing remotely related to letter-spacing in the TextView.
Edit: please see #JerabekJakub's response below for an updated, better method to do this starting with api 21 (Lollipop)

This answer is based on Pedro's answer but adjusted so it also works if text attribute is already set:
package nl.raakict.android.spc.widget;
import android.content.Context;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.ScaleXSpan;
import android.util.AttributeSet;
import android.widget.TextView;
public class LetterSpacingTextView extends TextView {
private float letterSpacing = LetterSpacing.BIGGEST;
private CharSequence originalText = "";
public LetterSpacingTextView(Context context) {
super(context);
}
public LetterSpacingTextView(Context context, AttributeSet attrs){
super(context, attrs);
originalText = super.getText();
applyLetterSpacing();
this.invalidate();
}
public LetterSpacingTextView(Context context, AttributeSet attrs, int defStyle){
super(context, attrs, defStyle);
}
public float getLetterSpacing() {
return letterSpacing;
}
public void setLetterSpacing(float letterSpacing) {
this.letterSpacing = letterSpacing;
applyLetterSpacing();
}
#Override
public void setText(CharSequence text, BufferType type) {
originalText = text;
applyLetterSpacing();
}
#Override
public CharSequence getText() {
return originalText;
}
private void applyLetterSpacing() {
if (this == null || this.originalText == null) return;
StringBuilder builder = new StringBuilder();
for(int i = 0; i < originalText.length(); i++) {
String c = ""+ originalText.charAt(i);
builder.append(c.toLowerCase());
if(i+1 < originalText.length()) {
builder.append("\u00A0");
}
}
SpannableString finalText = new SpannableString(builder.toString());
if(builder.toString().length() > 1) {
for(int i = 1; i < builder.toString().length(); i+=2) {
finalText.setSpan(new ScaleXSpan((letterSpacing+1)/10), i, i+1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
super.setText(finalText, BufferType.SPANNABLE);
}
public class LetterSpacing {
public final static float NORMAL = 0;
public final static float NORMALBIG = (float)0.025;
public final static float BIG = (float)0.05;
public final static float BIGGEST = (float)0.2;
}
}
If you want to use it programatically:
LetterSpacingTextView textView = new LetterSpacingTextView(context);
textView.setSpacing(10); //Or any float. To reset to normal, use 0 or LetterSpacingTextView.Spacing.NORMAL
textView.setText("My text");
//Add the textView in a layout, for instance:
((LinearLayout) findViewById(R.id.myLinearLayout)).addView(textView);

after API >=21 there is inbuild method provided by TextView called setLetterSpacing
check this for more

I built a custom class that extends TextView and solves this problem... Check out my answer here =)

As android doesn't support such a thing, you can do it manually with FontCreator. It has good options for font modifying.
I used this tool to build a custom font, even if it takes some times but you can always use it in your projects.

For embedding HTML text in your textview you can use Html.fromHTML() syntax.
More information you will get from http://developer.android.com/reference/android/text/Html.html#fromHtml%28java.lang.String%29

Related

How to make auto smooth scroll with offset Recycler View?

There is such issue, I have horizontal RecyclerView where each cell less than width of screen.
So I found a solution here
RecyclerVIew auto scroll to display all the elements as in News Feed etc.,
All work excellent if one cell take whole width of the screen otherwise(if each cell take 95% of screen width) every auto swipe place the cell at the beginner of screen (right side) and it is logical. So at the end of one visible cell it is start of another cell
it is doesn't looks good. I need this cell to be at the middle of the screen like this.
I need to see previous cell - current - next one
Now I would like to explain some magic how I make current smooth scroll (as I mentioned at link above)
this method in my CustomLinnearLayoutManager
#Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position)
{
LinearSmoothScroller linearSmoothScroller = new LinearSmoothScroller(recyclerView.getContext())
{
#Override
public PointF computeScrollVectorForPosition(int targetPosition)
{
return SmoothLayoutManager.this.computeScrollVectorForPosition(targetPosition);
}
#Override
protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics)
{
return MILLISECONDS_PER_INCH / displayMetrics.densityDpi;
}
};
linearSmoothScroller.setTargetPosition(position);
startSmoothScroll(linearSmoothScroller);
}
But this method works without offset
I found out one more method that can provide desired offset
scrollToPositionWithOffset(final int position, final int offset)
And it is looks like exactly what I need , but this method works without smooth animation.
So, eventually my question is : how to apply animation logic from first method to second (that with offset)
Feel free to ask
To auto snapping and showing one item at center of RecyclerView, simply you need to use LinearSnapHelper like following:
LinearSnapHelper snapHelper = new LinearSnapHelper();
snapHelper.attachToRecyclerView(recyclerView);
If you want to scroll to a specific item programmatically, LinearSnapHelper handles snapping functionality too.
SmoothScroller smoothScroller = new LinearSmoothScroller(recyclerView.getContext()) {
#Override
protected int getVerticalSnapPreference() {
return LinearSmoothScroller.SNAP_TO_ANY;
}
#Override
protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
return 120f / displayMetrics.densityDpi;
}
};
...
smoothScroller.setTargetPosition(position);
recyclerView.getLayoutManager().startSmoothScroll(smoothScroller);
Here is the visual result:
.
..................Manually Scrolling...........................Programmatically Scrolling..........
Eventually, I found the way thanks a lot to #aminography for his answer and also one more answer help me a lot
https://stackoverflow.com/a/39654328
Actually now I have such implementation
My custom LinnearLayoutManager implementation
public class SmoothLayoutManager extends LinearLayoutManager
{
public static final int X_25 = 25;
public static final int X_200 = 200;
public static final float DEFAULT = X_25;
/**
* !! IMPORTANT !!
* If you need to add new value, don't forget add it here also
*/
#Retention(RetentionPolicy.SOURCE)
#IntDef({X_25, X_200})
private #interface Speed
{
}
private static float MILLISECONDS_PER_INCH = DEFAULT;
public SmoothLayoutManager(Context context)
{
super(context);
}
public SmoothLayoutManager(Context context, int orientation, boolean reverseLayout)
{
super(context, orientation, reverseLayout);
}
public SmoothLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
{
super(context, attrs, defStyleAttr, defStyleRes);
}
public SmoothLayoutManager setSpeedOfSmooth(#Speed int iSpeed)
{
MILLISECONDS_PER_INCH = iSpeed;
return this;
}
#Override
public void scrollToPositionWithOffset(final int position, final int offset)
{
super.scrollToPositionWithOffset(position, offset);
}
#Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position)
{
RecyclerView.SmoothScroller smoothScroller = new LinearSmoothScroller(recyclerView.getContext())
{
#Override
public PointF computeScrollVectorForPosition(int targetPosition)
{
return SmoothLayoutManager.this.computeScrollVectorForPosition(targetPosition);
}
#Override
protected int getVerticalSnapPreference()
{
return LinearSmoothScroller.SNAP_TO_ANY;
}
#Override
protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics)
{
return MILLISECONDS_PER_INCH / displayMetrics.densityDpi;
}
#Override
public int calculateDtToFit(final int viewStart, final int viewEnd, final int boxStart, final int boxEnd, final int snapPreference)
{
return (boxStart + (boxEnd - boxStart) / 2) - (viewStart + (viewEnd - viewStart) / 2);
}
};
smoothScroller.setTargetPosition(position);
startSmoothScroll(smoothScroller);
}
}
And this is how I make set
private void setRv(Context iC)
{
RecyclerView.Adapter adapter = new UpSaleInnerAdapter(mPicasso, mInflater, iLink -> mListener.onButtonClick(iLink));
mRv.setLayoutManager(new SmoothLayoutManager(iC, LinearLayoutManager.HORIZONTAL, false).setSpeedOfSmooth(SmoothLayoutManager.X_200));
mRv.setAdapter(adapter);
SnapHelper snapHelper = new LinearSnapHelper();
snapHelper.attachToRecyclerView(mRv);
}
Note :
I noticed that sometimes if you make fast swipe, so SnapHelper a little bit confused and pass more cells that need... like a turbo mode :)
If someone will find how to fix it, let me know.
Thanks!

Eclipse layout preview can't resolve custom attribute, ok in runtime

I'm coding a simple class to use SVG resource:
public class SvgImageView extends ImageView {
private int svgResourceId = 0;
public SvgImageView(Context context, AttributeSet attrs) {
super(context, attrs);
parseAttributes(context.obtainStyledAttributes(attrs, R.styleable.SvgImageView));
}
private void parseAttributes(TypedArray a) {
this.svgResourceId = a.getResourceId(R.styleable.SvgImageView_svg, 0);
a.recycle();
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
// set correct layer type
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
// set drawable
if (svgResourceId != 0)
setImageDrawable(SvgCache.getSvgPictureDrawable(getContext().getResources(), svgResourceId));
}
}
in the activity XML simply I use it:
<myapp.framework.widget.SvgImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
custom:svg="#raw/lighting" />
Everything works fine in runtime but in editor mode, when opening the Graphical Layout panel, when parsing attributes:
this.svgResourceId = a.getResourceId(R.styleable.SvgImageView_svg, 0);
this.svgResourceId is 0, so I think it can't obtain the resource id. Why?
It may be the same situation as I had recently. To sum it up, it's because the IDE (Eclipse) processes the code with a different output method, resulting in the different display.
Here's a link to the question I had asked, hope it helps. Clearing Screen in C++/XCode

ListView custom adapter for different rows

I am using a ListView to display some JSON data and want to display each result according to its type (Artist, Release, Label...).
I will be using an interface implemented by each type of result :
public interface Result {
public Int getId();
public String getThumb();
// ...
}
I would like to know which of these choices is the best solution (I am open to better things, that's just what I had on the top of my head):
creating an enum ResultType in the interace (so inherited class will have to return their own value like ResultType.ARTIST in a getType() method
checking the instance type using isInstance()
I would like to know what would be the best way to perform something equivalent to this C code (array of function pointer) as I would like to avoid using to many if/else statements.
typedef struct s_func {
const char *type_name;
void* (*func_pointer)(void *result_infos);
} t_func;
static t_func type_array[] = {
{"artist", artist_function},
{"label", label_function},
// ....
{NULL, NULL}
}
void check_type(const char *type_string)
{
int i, j = 0;
char *key_value;
// compare string and array key
while (type_array && type_array[i][0]) {
key_value = type_array[i][0];
// if key match
if (type_string && strncmp(type_string, key_value, strlen(type_string)) == 0) {
type_array[i][1](); // call appropriate function;
}
i++;
}
}
I guess it would be using a HashMap but (I might be wrong) it doesn't seem to have a litteral notation. Is there any easy way to build an HashMap of pairs ?
Thank you
I think you can use an ArrayAdapter.
Take a look at this tutorial to see what I mean.
It'll need some twiddling so that it can deal with the different kinds of items.
Make an interface MyListItem
public interface MyListItem {
public int getLayout();
public void bindToView(View v);
}
Make different layouts for the display of Artist, Release, Label.
Make classes Artist, Release, Label that implement MyListItem.
public class Artist implements MyListItem {
private String Name;
public Artist(String name){
this.name = name;
}
public int getLayout() {
return R.layout.artistlayout;
}
public void bindToView(View v) {
TextView textView = (TextView) rowView.findViewById(R.id.artistLabel);
textView.setText(name);
}
}
Now the adapter only has to call the right methods to fill the view for the selected item.
public class MySimpleArrayAdapter extends ArrayAdapter<MyListItem> {
private final Context context;
private final MyListItem[] values;
public MySimpleArrayAdapter(Context context, MyListItem[] values) {
super(context, android.R.layout.simple_list_item_1, values);
this.context = context;
this.values = values;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
MyListItem item = values[position];
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(item.getLayout(), parent, false);
item.bindTo(view);
return view;
}
}

How to call method from separate package : Android

I am trying to get a method from the file Duality.java to be run in Min.Java when a button is clicked. Below are the two files and what I am currently trying to do, which is not working. How do I get the method duality() to run when the button is clicked within Min.java?
Duality.java
package com.android.control;
import android.util.Log;
import com.map.AppName.R;
public class duality {
public void duality(){
Log.e("Did It Run","Yes it ran");
}
}
Min.java
package com.android.control;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import com.map.AppName.R;
public class Min extends LinearLayout {
Button but;
private final int ELEMENT_HEIGHT = 60;
private final int ELEMENT_WIDTH = 80;;
private final int TEXT_SIZE = 30;
public Min( Context context, AttributeSet attributeSet ) {
super(context, attributeSet);
this.setLayoutParams( new LinearLayout.LayoutParams( LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT ) );
LayoutParams elementParams = new LinearLayout.LayoutParams( ELEMENT_WIDTH, ELEMENT_HEIGHT );
createBut( context );
addView( but, elementParams );
}
private void createButton( Context context){
but = new Button( context );
but.setTextSize( TEXT_SIZE );
but.setText( "Go" );
but.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Duality duality = new duality();
}
});
}
}
You're only constructing an instance of the duality class - you're not calling the duality() method on it.
This might be because you wanted that method to be a constructor - but it's not, because you specified a void return type, so it's just a conventional method.
(By the way, it's conventional in Java to give classes names that start with uppercase characters. If you called your class Duality, there may be less chance that you'd get the two confused; though the problem with accidental non-constructors would still stand.)
Both Min and duality are in the com.android.control package so they should be able to see eachother without imports.
It's recommended to capitalize class names. In fact, since your method has the same name as the class it might be conflicting with the constructor name. I suggest this:
public class Duality {
public void duality(){
Log.e("Did It Run","Yes it ran");
}
}
...
but.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Duality d = new Duality();
d.duality();
}
});
make sure that the class name and file name use same case combination in names.
if u want to call the constructor, remove the void from:
public void duality()
if it is supposed to b a function and not constructor, call it using:
object_name.duality();
u r calling createBut() and have given code for createButton().. is that a mistake in copy pasting?

Custom fonts and XML layouts (Android)

I'm trying to define a GUI layout using XML files in Android. As far as I can find out, there is no way to specify that your widgets should use a custom font (e.g. one you've placed in assets/font/) in XML files and you can only use the system installed fonts.
I know that, in the Java code, I could change the font of each widget manually using unique IDs. Alternatively, I could iterate over all the widgets in Java to make this change, but this would probably be very slow.
What other options do I have? Is there any better ways to making widgets that have a custom look? I don't particularly want to have to manually change the font for every new widget I add.
You can extend TextView to set custom fonts as I learned here.
TextViewPlus.java:
package com.example;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.TextView;
public class TextViewPlus extends TextView {
private static final String TAG = "TextView";
public TextViewPlus(Context context) {
super(context);
}
public TextViewPlus(Context context, AttributeSet attrs) {
super(context, attrs);
setCustomFont(context, attrs);
}
public TextViewPlus(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setCustomFont(context, attrs);
}
private void setCustomFont(Context ctx, AttributeSet attrs) {
TypedArray a = ctx.obtainStyledAttributes(attrs, R.styleable.TextViewPlus);
String customFont = a.getString(R.styleable.TextViewPlus_customFont);
setCustomFont(ctx, customFont);
a.recycle();
}
public boolean setCustomFont(Context ctx, String asset) {
Typeface tf = null;
try {
tf = Typeface.createFromAsset(ctx.getAssets(), asset);
} catch (Exception e) {
Log.e(TAG, "Could not get typeface: "+e.getMessage());
return false;
}
setTypeface(tf);
return true;
}
}
attrs.xml: (in res/values)
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="TextViewPlus">
<attr name="customFont" format="string"/>
</declare-styleable>
</resources>
main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:foo="http://schemas.android.com/apk/res/com.example"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.example.TextViewPlus
android:id="#+id/textViewPlus1"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:text="#string/showingOffTheNewTypeface"
foo:customFont="saxmono.ttf">
</com.example.TextViewPlus>
</LinearLayout>
You would put "saxmono.ttf" in the assets folder.
UPDATE 8/1/13
There are serious memory concerns with this method. See chedabob's comment below.
I'm 3 years late for the party :( However this could be useful for someone who might stumble upon this post.
I've written a library that caches Typefaces and also allow you to specify custom typefaces right from XML. You can find the library here.
Here is how your XML layout would look like, when you use it.
<com.mobsandgeeks.ui.TypefaceTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/hello_world"
geekui:customTypeface="fonts/custom_font.ttf" />
This might be a little late, but you need to create a singleton class that returns the custom typeface to avoid memory leaks.
TypeFace class:
public class OpenSans {
private static OpenSans instance;
private static Typeface typeface;
public static OpenSans getInstance(Context context) {
synchronized (OpenSans.class) {
if (instance == null) {
instance = new OpenSans();
typeface = Typeface.createFromAsset(context.getResources().getAssets(), "open_sans.ttf");
}
return instance;
}
}
public Typeface getTypeFace() {
return typeface;
}
}
Custom TextView:
public class NativelyCustomTextView extends TextView {
public NativelyCustomTextView(Context context) {
super(context);
setTypeface(OpenSans.getInstance(context).getTypeFace());
}
public NativelyCustomTextView(Context context, AttributeSet attrs) {
super(context, attrs);
setTypeface(OpenSans.getInstance(context).getTypeFace());
}
public NativelyCustomTextView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
setTypeface(OpenSans.getInstance(context).getTypeFace());
}
}
By xml:
<com.yourpackage.views.NativelyCustomTextView
android:id="#+id/natively_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_margin="20dp"
android:text="#string/natively"
android:textSize="30sp" />
Programmatically:
TextView programmaticallyTextView = (TextView)
findViewById(R.id.programmatically_text_view);
programmaticallyTextView.setTypeface(OpenSans.getInstance(this)
.getTypeFace());
Old question, but I sure wish I read this answer here before I started my own search for a good solution. Calligraphy extends the android:fontFamily attribute to add support for custom fonts in your asset folder, like so:
<TextView
android:text="#string/hello_world"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="fonts/Roboto-Bold.ttf"/>
The only thing you have to do to activate it is attaching it to the Context of the Activity you're using:
#Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(new CalligraphyContextWrapper(newBase));
}
You can also specify your own custom attribute to replace android:fontFamily
It also works in themes, including the AppTheme.
Using DataBinding :
#BindingAdapter({"bind:font"})
public static void setFont(TextView textView, String fontName){
textView.setTypeface(Typeface.createFromAsset(textView.getContext().getAssets(), "fonts/" + fontName));
}
In XML:
<TextView
app:font="#{`Source-Sans-Pro-Regular.ttf`}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
font file must be in assets/fonts/
If you only have one typeface you would like to add, and want less code to write, you can create a dedicated TextView for your specific font. See code below.
package com.yourpackage;
import android.content.Context;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.widget.TextView;
public class FontTextView extends TextView {
public static Typeface FONT_NAME;
public FontTextView(Context context) {
super(context);
if(FONT_NAME == null) FONT_NAME = Typeface.createFromAsset(context.getAssets(), "fonts/FontName.otf");
this.setTypeface(FONT_NAME);
}
public FontTextView(Context context, AttributeSet attrs) {
super(context, attrs);
if(FONT_NAME == null) FONT_NAME = Typeface.createFromAsset(context.getAssets(), "fonts/FontName.otf");
this.setTypeface(FONT_NAME);
}
public FontTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
if(FONT_NAME == null) FONT_NAME = Typeface.createFromAsset(context.getAssets(), "fonts/FontName.otf");
this.setTypeface(FONT_NAME);
}
}
In main.xml, you can now add your textView like this:
<com.yourpackage.FontTextView
android:id="#+id/tvTimer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="" />
The best way to do it From Android O preview release is this way
1.)Right-click the res folder and go to New > Android resource directory. The New
Resource Directory window appears.
2.)In the Resource type list, select font, and then click OK.
3.)Add your font files in the font folder.The folder structure below generates R.font.dancing_script, R.font.la_la, and R.font.ba_ba.
4.)Double-click a font file to preview the file's fonts in the editor.
Next we must create a font family
1.)Right-click the font folder and go to New > Font resource file. The New Resource File window appears.
2.)Enter the file name, and then click OK. The new font resource XML opens in the editor.
3.)Enclose each font file, style, and weight attribute in the font tag element. The following XML illustrates adding font-related attributes in the font resource XML:
<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:android="http://schemas.android.com/apk/res/android">
<font
android:fontStyle="normal"
android:fontWeight="400"
android:font="#font/hey_regular" />
<font
android:fontStyle="italic"
android:fontWeight="400"
android:font="#font/hey_bababa" />
</font-family>
Adding fonts to a TextView:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
**android:fontFamily="#font/ba_ba"**/>
As from the documentation
Working With Fonts
all the steps are correct.
Extend TextView and give it a custom attribute or just use the android:tag attribute to pass in a String of what font you want to use. You will need to pick a convention and stick to it such as I will put all of my fonts in the res/assets/fonts/ folder so your TextView class knows where to find them. Then in your constructor you just set the font manually after the super call.
The only way to use custom fonts is through the source code.
Just remember that Android runs on devices with very limited resources and fonts might require a good amount of RAM. The built-in Droid fonts are specially made and, if you note, have many characters and decorations missing.
I might have a simple answer for the question without extending the TextView and implementing a long code.
Code :
TextView tv = (TextView) findViewById(R.id.textview1);
tv.setTypeface(Typeface.createFromAsset(getAssets(), "font.ttf"));
Place the custom font file in assets folder as usual and try this. It works for me.
I just dont understand why peter has given such a huge code for this simple thing or he has given his answer in old version.
Also can be defined in the xml without creating custom classes
style.xml
<style name="ionicons" parent="android:TextAppearance">
<!-- Custom Attr-->
<item name="fontPath">fonts/ionicons.ttf</item>
</style>
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="#style/ionicons"
android:text=""/>
</LinearLayout>
A quick note, because I just always forgot where to put the fonts, its that the font must be inside assets and this folder resides in the same level that res and src, in my case its assets/fonts/ionicons.ttf
Updated Added root layout because this method needs xmlns:app="http://schemas.android.com/apk/res-auto" to work
Update 2 Forgot about a library that I've installed before called Calligraphy
Peter's answer is the best, but it can be improved by using the styles.xml from Android to customize your fonts for all textviews in your app.
My code is here
There are two ways to customize fonts :
!!! my custom font in assets/fonts/iran_sans.ttf
Way 1 :
Refrection Typeface.class ||| best way
call FontsOverride.setDefaultFont() in class extends Application, This code will cause all software fonts to be changed, even Toasts fonts
AppController.java
public class AppController extends Application {
#Override
public void onCreate() {
super.onCreate();
//Initial Font
FontsOverride.setDefaultFont(getApplicationContext(), "MONOSPACE", "fonts/iran_sans.ttf");
}
}
FontsOverride.java
public class FontsOverride {
public static void setDefaultFont(Context context, String staticTypefaceFieldName, String fontAssetName) {
final Typeface regular = Typeface.createFromAsset(context.getAssets(), fontAssetName);
replaceFont(staticTypefaceFieldName, regular);
}
private static void replaceFont(String staticTypefaceFieldName, final Typeface newTypeface) {
try {
final Field staticField = Typeface.class.getDeclaredField(staticTypefaceFieldName);
staticField.setAccessible(true);
staticField.set(null, newTypeface);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
Way 2: use setTypeface
for special view just call setTypeface() to change font.
CTextView.java
public class CTextView extends TextView {
public CTextView(Context context) {
super(context);
init(context,null);
}
public CTextView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
init(context,attrs);
}
public CTextView(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context,attrs);
}
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public CTextView(Context context, #Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context,attrs);
}
public void init(Context context, #Nullable AttributeSet attrs) {
if (isInEditMode())
return;
// use setTypeface for change font this view
setTypeface(FontUtils.getTypeface("fonts/iran_sans.ttf"));
}
}
FontUtils.java
public class FontUtils {
private static Hashtable<String, Typeface> fontCache = new Hashtable<>();
public static Typeface getTypeface(String fontName) {
Typeface tf = fontCache.get(fontName);
if (tf == null) {
try {
tf = Typeface.createFromAsset(AppController.getInstance().getApplicationContext().getAssets(), fontName);
} catch (Exception e) {
e.printStackTrace();
return null;
}
fontCache.put(fontName, tf);
}
return tf;
}
}
Here's a tutorial that shows you how to setup a custom font like #peter described: http://responsiveandroid.com/2012/03/15/custom-fonts-in-android-widgets.html
it also has consideration for potential memory leaks ala http://code.google.com/p/android/issues/detail?id=9904 . Also in the tutorial is an example for setting a custom font on a button.
You can make easily custom textview class :-
So what you need to do first, make Custom textview class which extended with AppCompatTextView.
public class CustomTextView extends AppCompatTextView {
private int mFont = FontUtils.FONTS_NORMAL;
boolean fontApplied;
public CustomTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(attrs, context);
}
public CustomTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs, context);
}
public CustomTextView(Context context) {
super(context);
init(null, context);
}
protected void init(AttributeSet attrs, Context cxt) {
if (!fontApplied) {
if (attrs != null) {
mFont = attrs.getAttributeIntValue(
"http://schemas.android.com/apk/res-auto", "Lato-Regular.ttf",
-1);
}
Typeface typeface = getTypeface();
int typefaceStyle = Typeface.NORMAL;
if (typeface != null) {
typefaceStyle = typeface.getStyle();
}
if (mFont > FontUtils.FONTS) {
typefaceStyle = mFont;
}
FontUtils.applyFont(this, typefaceStyle);
fontApplied = true;
}
}
}
Now , every time Custom text view call and we will get int value from attribute int fontValue = attrs.getAttributeIntValue("http://schemas.android.com/apk/res-auto","Lato-Regular.ttf",-1).
Or
We can also get getTypeface() from view which we set in our xml (android:textStyle="bold|normal|italic"). So do what ever you want to do.
Now, we make FontUtils for set any .ttf font into our view.
public class FontUtils {
public static final int FONTS = 1;
public static final int FONTS_NORMAL = 2;
public static final int FONTS_BOLD = 3;
public static final int FONTS_BOLD1 = 4;
private static Map<String, Typeface> TYPEFACE = new HashMap<String, Typeface>();
static Typeface getFonts(Context context, String name) {
Typeface typeface = TYPEFACE.get(name);
if (typeface == null) {
typeface = Typeface.createFromAsset(context.getAssets(), name);
TYPEFACE.put(name, typeface);
}
return typeface;
}
public static void applyFont(TextView tv, int typefaceStyle) {
Context cxt = tv.getContext();
Typeface typeface;
if(typefaceStyle == Typeface.BOLD_ITALIC) {
typeface = FontUtils.getFonts(cxt, "FaktPro-Normal.ttf");
}else if (typefaceStyle == Typeface.BOLD || typefaceStyle == SD_FONTS_BOLD|| typefaceStyle == FONTS_BOLD1) {
typeface = FontUtils.getFonts(cxt, "FaktPro-SemiBold.ttf");
} else if (typefaceStyle == Typeface.ITALIC) {
typeface = FontUtils.getFonts(cxt, "FaktPro-Thin.ttf");
} else {
typeface = FontUtils.getFonts(cxt, "FaktPro-Normal.ttf");
}
if (typeface != null) {
tv.setTypeface(typeface);
}
}
}
It may be useful to know that starting from Android 8.0 (API level 26) you can use a custom font in XML.
You can apply a custom font to the entire application in the following way.
Put the font in the folder res/font.
In res/values/styles.xml use it in the application theme.
<style name="AppTheme" parent="{whatever you like}">
<item name="android:fontFamily">#font/myfont</item>
</style>
Fontinator is an Android-Library make it easy, to use custom Fonts.
https://github.com/svendvd/Fontinator
You can't extend TextView to create a widget or use one in a widgets layout:
http://developer.android.com/guide/topics/appwidgets/index.html

Categories