Android: Is it possible to use string/enum in drawable selector? - android

Questions
Q1: Has anyone managed to get custom string/enum attribute working in xml selectors? I got a boolean attribute working by following [1], but not a string attribute.
EDIT: Thanks for answers. Currently android supports only boolean selectors. See accepted answer for the reason.
I'm planning to implement a little complex custom button, whose appearance depends on two variables. Other will be a boolean attribute (true or false) and another category-like attribute (has many different possible values). My plan is to use boolean and string (or maybe enum?) attributes. I was hoping I could define the UI in xml selector using boolean and string attribute.
Q2: Why in [1] the onCreateDrawableState(), boolean attributes are merged only if they are true?
This is what I tested, boolean attribute works, string doesn't
NOTE: This is just a test app to figure out if string/enum attribute is possible in xml selector. I know that I could set button's textcolor without a custom attribute.
In my demo application, I use a boolean attribute to set button background to dark/bright and string attribute to set text color, one of {"red", "green", "blue"}. Attributes are defined in /res/values/attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyCustomButton">
<attr name="make_dark_background" format="boolean" />
<attr name="str_attr" format="string" />
</declare-styleable>
</resources>
Here are the selectors I want to achieve:
#drawable/custom_button_background (which works)
<?xml version="1.0" encoding="utf-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/com.example.customstringattribute">
<item app:make_dark_background="true" android:drawable="#color/dark" />
<item android:drawable="#color/bright" />
</selector>
#color/custom_button_text_color (which does not work)
<selector
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/com.example.customstringattribute">
<item app:str_attr="red" android:color="#color/red" />
<item app:str_attr="green" android:color="#color/green" />
<item app:str_attr="blue" android:color="#color/blue" />
<item android:color="#color/grey" />
</selector>
Here is how custom button background is connected to boolean selector, and text color is connected to string selector.
<com.example.customstringattribute.MyCustomButton
...
android:background="#drawable/custom_button_background"
android:textColor="#color/custom_button_text_color"
...
/>
Here is how attributes are loaded in the init() method:
private void init(AttributeSet attrs) {
TypedArray a = getContext().obtainStyledAttributes(attrs,
R.styleable.MyCustomButton);
final int N = a.getIndexCount();
for (int i = 0; i < N; ++i)
{
int attr = a.getIndex(i);
switch (attr)
{
case R.styleable.MyCustomButton_str_attr:
mStrAttr = a.getString(attr);
break;
case R.styleable.MyCustomButton_make_dark_background:
mMakeDarkBg = a.getBoolean(attr, false);
break;
}
}
a.recycle();
}
I have the int[] arrays for the attributes
private static final int[] MAKE_DARK_BG_SET = { R.attr.make_dark_background };
private static final int[] STR_ATTR_ID = { R.attr.str_attr };
And those int[] arrays are merged to drawable state
#Override
protected int[] onCreateDrawableState(int extraSpace) {
Log.i(TAG, "onCreateDrawableState()");
final int[] drawableState = super.onCreateDrawableState(extraSpace + 2);
if(mMakeDarkBg){
mergeDrawableStates(drawableState, MAKE_DARK_BG_SET);
}
mergeDrawableStates(drawableState, STR_ATTR_ID);
return drawableState;
}
I also have refreshDrawableState() in my attribute setter methods:
public void setMakeDarkBg(boolean makeDarkBg) {
if(mMakeDarkBg != makeDarkBg){
mMakeDarkBg = makeDarkBg;
refreshDrawableState();
}
}
public void setStrAttr(String str) {
if(mStrAttr != str){
mStrAttr = str;
refreshDrawableState();
}
}
[1] : How to add a custom button state

Q1:
When you open the source-code of StateListDrawable.java, you can see this piece of code in the inflate method that reads the drawable xml selector:
https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/graphics/java/android/graphics/drawable/StateListDrawable.java
...
for (i = 0; i < numAttrs; i++) {
final int stateResId = attrs.getAttributeNameResource(i);
if (stateResId == 0) break;
if (stateResId == com.android.internal.R.attr.drawable) {
drawableRes = attrs.getAttributeResourceValue(i, 0);
} else {
states[j++] = attrs.getAttributeBooleanValue(i, false)
? stateResId
: -stateResId;
}
}
...
attrs are the attributes of each <item> element in the <selector>.
In this for-loop it gets the android:drawable, the various android:state_xxxx and custom app:xxxx attributes. All but the android:drawable attributes seem to be interpreted as booleans only: attrs.getAttributeBooleanValue(....) is called.
I think this is the answer, based on the source code:
You can only add custom boolean attributes to your xml, not any other type (including enums).
Q2:
I'm not sure why the state is merged only if it is specifically set to true. I would suspect the code should have looked like this instead:
private static final int[] MAKE_DARK_BG_SET = { R.attr.make_dark_background };
private static final int[] NOT_MAKE_DARK_BG_SET = { -R.attr.make_dark_background };
....
....
#Override
protected int[] onCreateDrawableState(int extraSpace) {
Log.i(TAG, "onCreateDrawableState()");
final int[] drawableState = super.onCreateDrawableState(extraSpace + 2);
mergeDrawableStates(drawableState, mMakeDarkBg? MAKE_DARK_BG_SET : NOT_MAKE_DARK_BG_SET);
//mergeDrawableStates(drawableState, STR_ATTR_ID);
return drawableState;
}

Q1:
I haven't tried this myself, but:
Have you tried placing your #color/custom_button_text_color.xml in the drawable folder? (Just to be sure, there's a bit of folder magic here and there in Android and I'm not sure about this one.)
Q2:
There are two use cases for state sets. One is to explicitly declare selectors for stateful drawables programmatically. In this case, for selectors, you need to be able to tell Android to use this drawable if an attribute is not set. To express this, you can include the negated criteria (preceded by a minus sign) in the int[].
While this is barely mentioned anywhere in the context of selector criteria, it is never mentioned for drawable states themselves (aka the representation of the drawable's state). So one is definitely on the safe side if one does not include negated state IDs in the set; the provided Android implementations also do not includde them.

Sorry, you cannot create custom drawables in xml :
https://groups.google.com/d/msg/android-developers/glpdi0AdMzI/LpW4HGMB3VIJ

Related

How do you create an XML-friendly control based on a layout?

I've created a custom control which is a subclass of LinearLayout. I have also created a layout file on which this control is based. Finally I have defined attributes which I parse in the constructor to set my custom properties on. As an example, one of those properties is called 'text'.
Here's a simplified version of my code (I've stripped out a lot of the other properties and such so we can just focus on the one property 'text'):
First, the class (our custom version of a RadioButton)...
public class RadioButton extends LinearLayout
{
private TextView textView;
public RadioButton(Context context, AttributeSet attrs)
{
super(context, attrs);
initAttributes(attrs, 0);
}
private void initAttributes(AttributeSet attrs, int defStyle)
{
final TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.CheckBoxView, defStyle, 0);
text = a.getString(R.styleable.RadioButton_text);
if(text == null)
text = "Not set";
a.recycle();
}
#Override
protected void onFinishInflate()
{
super.onFinishInflate();
textView = (TextView)findViewById(R.id.textView);
textView.setText(text);
}
private String text;
public String getText() { return text; }
public void setText(String newValue)
{
text = newValue;
if(textView != null)
textView.setText(text);
}
}
Here's the attrs.xml file...
<resources>
<attr name="text" format="string" />
<declare-styleable name="RadioButton">
<attr name="text" />
</declare-styleable>
</resources>
And here's the 'reusable_radiobutton.xml' layout file (Note: the internal RadioButtonView is a custom-rendered View and works fine):
<?xml version="1.0" encoding="utf-8"?>
<com.somedomain.reusable.ui.RadioButton
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical">
<com.somedomain.reusable.ui.RadioButtonView
android:id="#+id/radioButtonView"
style="#style/DefaultRadioButtonView" />
<TextView
android:id="#+id/textView"
style="#style/DefaultRadioButtonText" />
</com.somedomain.reusable.ui.RadioButton>
With the above, users of my control can simply include it in their own layout files, like so...
<include android:id="#+id/someRadioButton"
layout="#layout/reusable_radiobutton" />
The in their code, using the following, they can get that instance and do with it what they wish, like so...
RadioButton someRadioButton = (RadioButton)findViewById(R.id.someRadioButton);
someRadioButton.text = "Woot!";
This works as expected.
However, this doesn't...
<include android:id="#+id/someRadioButton"
layout="#layout/reusable_radiobutton"
app:text="Hello World!" />
It gives me a warning, but otherwise ignores it.
I then tried this...
<com.somedomain.reusable.ui.RadioButton
app:text="Hello World!" />
While this does instantiate my control and does pass 'Hello World!' to my property via the attributes, nothing actually loads or even associates the layout file to my class so nothing appears on the screen!
So how can I create a custom view, based on a layout, which other developers can simply reference in their own layout files while also allowing them to set custom attributes?
Hope that all made sense! :)
Note: The Android documentation talks about exactly what I'm after, 'Compound Controls' as referenced here, but they don't give an example of using a layout to define the compounded control. However, I feel that was pretty close.
Found it here on SO. I didn't realize you could inflate something into yourself. That and using the Merge tag took care of it for me.

Change TapDown Color on ListView

I have a list view and when the user taps down on the item it looks like this.
This is what it looks like noramally:
How do I change this default light blue color?
I need the color to be set programatically in the activity file, as it is not always the same color, and also how do you change the color of the fuzzy stuff that comes up at the bottom of a ListView when you continue to scroll down?
Thanks for the help
EDIT
Also how do you change the tap down color of the action bar back button,
For the row color, you need to create a StateListDrawable and set it as the selector for the ListView.
The states to include should be, at least:
pressed (android.R.attr.state_pressed)
selected (android.R.attr.state_selected)
"normal" (empty state list)
For each state you can set any drawable. If what you need is a plain color, you can programmatically create a ColorDrawable on the spot.
For example:
StateListDrawable selector = new StateListDrawable();
ColorDrawable red = new ColorDrawable(Color.RED);
ColorDrawable transparent = new ColorDrawable(Color.TRANSPARENT);
selector.addState(new int[] { android.R.attr.state_pressed }, red);
selector.addState(new int[] { android.R.attr.state_selected }, red);
selector.addState(new int[] { }, transparent);
listView.setSelector(selector);
As for the "fuzzy stuff that comes up at the bottom", it's slightly more complicated.
Prior to Android 5.0 there was no public API for changing it.
In Lollipop it can be set via the theme, but not programmatically.
For pre-5.0 there is a well-known workaround (described here) which involves tampering with the drawables that are used. However this solution crashes in 5.0, because those resources do not exist anymore.
For Android 5.0, if a static color is acceptable, you can just configure the new theme attribute android:colorEdgeEffect (which is the same as android:colorPrimary by default).
If a programmatic solution for Android 5.0 is necessary, you could alternatively change the EdgeEffect objects that the ListView has internally using reflection. I've tested this and it works, though it's not the prettiest code:
EdgeEffect edgeEffectTop = new EdgeEffect(this);
edgeEffectTop.setColor(Color.RED);
EdgeEffect edgeEffectBottom = new EdgeEffect(this);
edgeEffectBottom.setColor(Color.RED);
try {
Field f1 = AbsListView.class.getDeclaredField("mEdgeGlowTop");
f1.setAccessible(true);
f1.set(listView, edgeEffectTop);
Field f2 = AbsListView.class.getDeclaredField("mEdgeGlowBottom");
f2.setAccessible(true);
f2.set(listView, edgeEffectBottom);
} catch (Exception e) {
e.printStackTrace();
}
Therefore, a full programmatic solution may run something like this:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
// For Android >= 5.0, use setColor() on EdgeEffect
EdgeEffect edgeEffectTop = new EdgeEffect(this);
edgeEffectTop.setColor(Color.RED);
EdgeEffect edgeEffectBottom = new EdgeEffect(this);
edgeEffectBottom.setColor(Color.RED);
try {
Field f1 = AbsListView.class.getDeclaredField("mEdgeGlowTop");
f1.setAccessible(true);
f1.set(listView, edgeEffectTop);
Field f2 = AbsListView.class.getDeclaredField("mEdgeGlowBottom");
f2.setAccessible(true);
f2.set(listView, edgeEffectBottom);
} catch (Exception e) {
e.printStackTrace();
}
}
else
{
// For Android < 5.0, change overscroll_glow and overscroll_edge
int glowDrawableId = getResources().getIdentifier("overscroll_glow", "drawable", "android");
Drawable androidGlow = getResources().getDrawable(glowDrawableId);
androidGlow.setColorFilter(Color.RED, PorterDuff.Mode.MULTIPLY);
int edgeDrawableId = getResources().getIdentifier("overscroll_edge", "drawable", "android");
Drawable androidEdge = getResources().getDrawable(edgeDrawableId);
androidEdge.setColorFilter(Color.RED, PorterDuff.Mode.MULTIPLY);
}
How do I change this default light blue color?
you have to create StateListDrawable and set it as the selector for the ListView. the answer of matiash is good and I do not want to explain it again.
change the color of the fuzzy stuff that comes up at the bottom of a
ListView when you continue to scroll down
setCacheColorHint (int color)
Also how do you change the tap down color of the action bar back
button
<style name="actionbarCustomBackground" parent="#style/Theme.Holo.Light" >
<item name="android:selectableItemBackground">#drawable/actionbar_item_background</item>
</style>
then in the actionbar_item_background:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:exitFadeDuration="#android:integer/config_mediumAnimTime">
<item
android:state_focused="true"
android:state_pressed="true"
android:drawable="#android:color/holo_orange_dark" />
<item
android:state_pressed="true"
android:drawable="#android:color/holo_orange_dark" />
<item
android:drawable="#android:color/transparent" />
</selector>
You can set row's background dynamically in getView(..) method.
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
.......... //your code
view.setBackgroundColor(Color.RED)
return view;
}

Get attr color value based on current set theme

In my activity I'm maintaining a SuperActivity, in which I'm setting the theme.
public class SuperActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTheme(R.style.MyTheme);
}
}
themes.xml
<!-- ImageBackround -->
<style name="Theme.MyTheme" parent="ThemeLight">
<item name="myBgColor">#color/translucent_black</item>
</style>
Now I want to fetch this color in one of my child activity.
As mentioned in this probable answer, I wrote:
int[] attrs = new int[] { R.attr.myBgColor /* index 0 */};
TypedArray ta = ChildActivity.this.obtainStyledAttributes(attrs);
int color = ta.getColor(0, android.R.color.background_light);
String c = getString(color);
ta.recycle();
But everytime I'm getting the value of the default value of android.R.color.background_light & not of R.attr.myBgColor.
Where I'm doing wrong. Am I passing the wrong context of ChildActivity.this?
You have two possible solutions (one is what you actually have but I include both for the sake of completeness):
TypedValue typedValue = new TypedValue();
if (context.getTheme().resolveAttribute(R.attr.xxx, typedValue, true))
return typedValue.data;
else
return Color.TRANSPARENT;
or
int[] attribute = new int[] { R.attr.xxx };
TypedArray array = context.getTheme().obtainStyledAttributes(attribute);
int color = array.getColor(0, Color.TRANSPARENT);
array.recycle();
return color;
Color.TRANSPARENT could be any other default for sure. And yes, as you suspected, the context is very important. If you keep getting the default color instead of the real one, check out what context you are passing. It took me several hours to figure it out, I tried to spare some typing and simply used getApplicationContext() but it doesn't find the colors then...

Using an array reference as an XML attribute for custom android view

This problem has been solved, see comments for details.
I am extending an existing Android View and loading some custom attributes, as described in Declaring a custom android UI element using XML and Defining custom attrs.
Attributes with boolean and integer formats work fine, but when I try to specify a reference to an array resource, the application crashes at launch. I have defined an integer array inside an xml resource file and I'm trying to use it as an attribute for the custom view.
I can use the array resource to set the "entries" attribute of the android Spinner class with no errors, so it seems to be a problem in my implementation. The logcat messages don't seem to supply any specific information about the crash, but I'm still looking so I will update if I find something.
The attributes are declared by (in attrs.xml):
<declare-styleable name="CustomView">
<attr name="values" format="reference"/>
<attr name="isActive" format="boolean"/>
</declare-styleable>
The array is defined as (in arrays.xml):
<integer-array name="nums">
<item>1</item>
<item>2</item>
<item>3</item>
</integer-array>
And I am referencing the array by:
<com.test.CustomView cv:values="#array/nums" />
And this causes the application to crash immediately. In addition, if I reference a color resource instead of an array then the application does not crash. Does anybody know how to deal with this problem?
Just going to piggyback off your question here, since your post shows up first if you google something like "array reference XML attribute custom view", so someone might find this helpful.
If you want your custom view to reference an array of strings, you can use Android's existing android:entries XML attribute, instead of creating a totally new custom attribute.
Just do the following in res/values/attrs.xml:
<resources>
<declare-styleable name="MyCustomView">
<attr name="android:entries" />
</declare-styleable>
</resources>
Then do this in your custom View's constructor:
public MyCustomView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MyCustomView, defStyle, 0);
try
{
CharSequence[] entries = a.getTextArray(R.styleable.MyCustomView_android_entries);
if (entries != null)
{
//do something with the array if you want
}
}
finally
{
a.recycle();
}
}
And then you should be able to reference a string array via the android:entries attribute when you add your custom View to an XML layout file. Example:
<com.example.myapp.MyCustomView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:entries="#array/my_array_of_strings" />
This is exactly how it is done in the ListView class (look in the source, you'll see).
The other answer works well with array of strings. However, arr.getTextArray(...) on array of references, e.g.
<array name="tmp">
<item>#drawable/a</item>
<item>#drawable/b</item>
</array>
will give you res/drawable/a.png as the CharSequence instead of the resource id.
The proper way to parse an array of references is this:
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomView);
int arrayResourceId = typedArray.getResourceId(R.styleable.CustomView_CustomAttr, 0);
if (arrayResourceId != 0) {
final TypedArray resourceArray = getResources().obtainTypedArray(arrayResourceId);
for (int i = 0; i < resourceArray.length(); i++) {
final int resourceId = resourceArray.getResourceId(i, 0);
// do stuff with resourceId, such as getResources().getDrawable(resourceId)
}
resourceArray.recycle();
}
typedArray.recycle();
The question is about obtain an integer array, for my case, I need to read the colors(int) from an array for my custom view, styeable definition as below:
<declare-styleable name="ColorPickerView">
<attr name="colors" format="reference" />
</declare-styleable>
Then I use my custom view like below:
<com.rainliu.colorpicker.ColorPickerView
android:id="#+id/rtePalette"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
colorPickerView:colors="#array/colorPickerColors"
/>
The colors definition is as below:
<resources>
<color name="colorPrimary">#FF9800</color>
<array name="colorPickerColors">
<item>#000000</item>
<item>#E65100</item>
<item>#color/colorPrimary</item>
</array>
</resources>
So I need to obtain the colors in my custom view (ColorPickerView), code as below:
TypedArray ta = context.obtainStyledAttributes(attributeSet, R.styleable.ColorPickerView);
int colorsId = ta.getResourceId(R.styleable.ColorPickerView_colors, 0);
int[] colorsArray = ta.getResources().getIntArray(colorsId);
for (int a : colorsArray) {
Log.e("AA", "color == " + a);
}
ta.recycle();
Here is the print of colorsArray:
03-11 14:25:53.894 15300-15300/com.chinalwb.are E/AA: color == -16777216
03-11 14:25:53.894 15300-15300/com.chinalwb.are E/AA: color == -1683200
03-11 14:25:53.894 15300-15300/com.chinalwb.are E/AA: color == -1683200
Hope this will help some guys.

Android: Want to set custom fonts for whole application not runtime

Is it possible to set any custom font in every control of the application? And not necessarily runtime ? (i.e. from xml if possible or only once for whole application in JAVA file)
I can set the font for one control from this code.
public static void setFont(TextView textView) {
Typeface tf = Typeface.createFromAsset(textView.getContext()
.getAssets(), "fonts/BPreplay.otf");
textView.setTypeface(tf);
}
And the problem with this code is it should be called for every control. And i want to call this or any similar method once, or if possible set the property in xml. Is it possible?
EDIT: So it's been a while, and I'd like to add what I think is the best way to do this, and through XML no less!
So first, you're going to want to make a new class that overrides whatever View you want to customize. (e.g. want a Button with a custom typeface? Extend Button). Let's make an example:
public class CustomButton extends Button {
private final static int ROBOTO = 0;
private final static int ROBOTO_CONDENSED = 1;
public CustomButton(Context context) {
super(context);
}
public CustomButton(Context context, AttributeSet attrs) {
super(context, attrs);
parseAttributes(context, attrs); //I'll explain this method later
}
public CustomButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
parseAttributes(context, attrs);
}
}
Now, if you don't have one, add an XML document under res/values/attrs.xml, and add:
<resources>
<!-- Define the values for the attribute -->
<attr name="typeface" format="enum">
<enum name="roboto" value="0"/>
<enum name="robotoCondensed" value="1"/>
</attr>
<!-- Tell Android that the class "CustomButton" can be styled,
and which attributes it supports -->
<declare-styleable name="CustomButton">
<attr name="typeface"/>
</declare-styleable>
</resources>
Okay, so with that out of the way, let's get back to the parseAttributes() method from earlier:
private void parseAttributes(Context context, AttributeSet attrs) {
TypedArray values = context.obtainStyledAttributes(attrs, R.styleable.CustomButton);
//The value 0 is a default, but shouldn't ever be used since the attr is an enum
int typeface = values.getInt(R.styleable.CustomButton_typeface, 0);
switch(typeface) {
case ROBOTO: default:
//You can instantiate your typeface anywhere, I would suggest as a
//singleton somewhere to avoid unnecessary copies
setTypeface(roboto);
break;
case ROBOTO_CONDENSED:
setTypeface(robotoCondensed);
break;
}
values.recycle();
}
Now you're all set. You can add more attributes for about anything (you could add another one for typefaceStyle -- bold, italic, etc.) but now let's see how to use it:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res/com.yourpackage.name"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<com.yourpackage.name.CustomButton
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Click Me!"
custom:typeface="roboto" />
</LinearLayout>
The xmlns:custom line can really be anything, but the convention is what's shown above. What matters is that it is unique, and that's why the package name is used. Now you just use the custom: prefix for your attributes, and the android: prefix for android attributes.
One last thing: if you want to use this in a style (res/values/styles.xml), you should not add the xmlns:custom line. Just reference the name of the attribute with no prefix:
<style name="MyStyle>
<item name="typeface">roboto</item>
</style>
(PREVIOUS ANSWER)
Using a custom typeface in Android
This should help. Basically, there's no way to do this in XML, and as far as I can tell, no easier way to do it in code. You could always have a setLayoutFont() method that creates the typeface once, then runs setTypeface() for each. You'd just have to update it each time you add a new item to a layout. Something like below:
public void setLayoutFont() {
Typeface tf = Typeface.createFromAsset(
getBaseContext().getAssets(), "fonts/BPreplay.otf");
TextView tv1 = (TextView)findViewById(R.id.tv1);
tv1.setTypeface(tf);
TextView tv2 = (TextView)findViewById(R.id.tv2);
tv2.setTypeface(tf);
TextView tv3 = (TextView)findViewById(R.id.tv3);
tv3.setTypeface(tf);
}
EDIT: So I just got around to implementing something like this myself, and how I ended up doing it was making a function such as this:
public static void setLayoutFont(Typeface tf, TextView...params) {
for (TextView tv : params) {
tv.setTypeface(tf);
}
}
Then, just use this method from onCreate(), and pass all the TextViews you want to update:
Typeface tf = Typeface.createFromAsset(getAssets(), "fonts/BPreplay.otf");
//find views by id...
setLayoutFont(tf, tv1, tv2, tv3, tv4, tv5);
EDIT 9/5/12:
So since this is still getting views and votes, I'd like to add a much better and more complete method:
Typeface mFont = Typeface.createFromAsset(getAssets(), "fonts/BPreplay.otf");
ViewGroup root = (ViewGroup)findViewById(R.id.myrootlayout);
setFont(root, mFont);
/*
* Sets the font on all TextViews in the ViewGroup. Searches
* recursively for all inner ViewGroups as well. Just add a
* check for any other views you want to set as well (EditText,
* etc.)
*/
public void setFont(ViewGroup group, Typeface font) {
int count = group.getChildCount();
View v;
for(int i = 0; i < count; i++) {
v = group.getChildAt(i);
if(v instanceof TextView || v instanceof Button /*etc.*/)
((TextView)v).setTypeface(font);
else if(v instanceof ViewGroup)
setFont((ViewGroup)v, font);
}
}
If you pass it the root of your layout, it will recursively check for TextView or Button views (or any others you add to that if statement) within that layout, and set the font without you having to specify them by ID. This of course is assuming you want to set the font to every view.
There is a fairly easy way to do this via XML. You just need to create your own widget that extends TextView.
First, create a file in res/values/attrs.xml with the following content:
<resources>
<declare-styleable name="TypefacedTextView">
<attr name="typeface" format="string" />
</declare-styleable>
</resources>
After that, create your custom widget:
package your.package.widget;
public class TypefacedTextView extends TextView {
public TypefacedTextView(Context context, AttributeSet attrs) {
super(context, attrs);
//Typeface.createFromAsset doesn't work in the layout editor. Skipping...
if (isInEditMode()) {
return;
}
TypedArray styledAttrs = context.obtainStyledAttributes(attrs, R.styleable.TypefacedTextView);
String fontName = styledAttrs.getString(R.styleable.TypefacedTextView_typeface);
styledAttrs.recycle();
if (fontName != null) {
Typeface typeface = Typeface.createFromAsset(context.getAssets(), fontName);
setTypeface(typeface);
}
}
}
As you can see, the code above will read a font inside the assets/ folder. For this example, I am assuming that there is a file called "custom.ttf" in the assets folder. At last, use the widget in the XMLs:
<your.package.widget.TypefacedTextView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:your_namespace="http://schemas.android.com/apk/res/your.package"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Custom fonts in XML are easy"
android:textColor="#FFF"
android:textSize="14dip"
your_namespace:typeface="custom.ttf" />
Note: You won't be able to see your custom font in Eclipse's layout editor. This is why I put the isInEditMode() check. But if you run your app, the custom font will work like a charm.
Example of TextView with roboto typeface:
attr.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="RobotoTextView">
<attr name="typeface"/>
</declare-styleable>
<attr name="typeface" format="enum">
<enum name="roboto_thin" value="0"/>
<enum name="roboto_thin_italic" value="1"/>
<enum name="roboto_light" value="2"/>
<enum name="roboto_light_italic" value="3"/>
<enum name="roboto_regular" value="4"/>
<enum name="roboto_italic" value="5"/>
<enum name="roboto_medium" value="6"/>
<enum name="roboto_medium_italic" value="7"/>
<enum name="roboto_bold" value="8"/>
<enum name="roboto_bold_italic" value="9"/>
<enum name="roboto_black" value="10"/>
<enum name="roboto_black_italic" value="11"/>
<enum name="roboto_condensed" value="12"/>
<enum name="roboto_condensed_italic" value="13"/>
<enum name="roboto_condensed_bold" value="14"/>
<enum name="roboto_condensed_bold_italic" value="15"/>
</attr>
</resources>
RobotoTextView.java:
public class RobotoTextView extends TextView {
/*
* Permissible values ​​for the "typeface" attribute.
*/
private final static int ROBOTO_THIN = 0;
private final static int ROBOTO_THIN_ITALIC = 1;
private final static int ROBOTO_LIGHT = 2;
private final static int ROBOTO_LIGHT_ITALIC = 3;
private final static int ROBOTO_REGULAR = 4;
private final static int ROBOTO_ITALIC = 5;
private final static int ROBOTO_MEDIUM = 6;
private final static int ROBOTO_MEDIUM_ITALIC = 7;
private final static int ROBOTO_BOLD = 8;
private final static int ROBOTO_BOLD_ITALIC = 9;
private final static int ROBOTO_BLACK = 10;
private final static int ROBOTO_BLACK_ITALIC = 11;
private final static int ROBOTO_CONDENSED = 12;
private final static int ROBOTO_CONDENSED_ITALIC = 13;
private final static int ROBOTO_CONDENSED_BOLD = 14;
private final static int ROBOTO_CONDENSED_BOLD_ITALIC = 15;
/**
* List of created typefaces for later reused.
*/
private final static SparseArray<Typeface> mTypefaces = new SparseArray<Typeface>(16);
/**
* Simple constructor to use when creating a view from code.
*
* #param context The Context the view is running in, through which it can
* access the current theme, resources, etc.
*/
public RobotoTextView(Context context) {
super(context);
}
/**
* Constructor that is called when inflating a view from XML. This is called
* when a view is being constructed from an XML file, supplying attributes
* that were specified in the XML file. This version uses a default style of
* 0, so the only attribute values applied are those in the Context's Theme
* and the given AttributeSet.
* <p/>
* <p/>
* The method onFinishInflate() will be called after all children have been
* added.
*
* #param context The Context the view is running in, through which it can
* access the current theme, resources, etc.
* #param attrs The attributes of the XML tag that is inflating the view.
* #see #RobotoTextView(Context, AttributeSet, int)
*/
public RobotoTextView(Context context, AttributeSet attrs) {
super(context, attrs);
parseAttributes(context, attrs);
}
/**
* Perform inflation from XML and apply a class-specific base style. This
* constructor of View allows subclasses to use their own base style when
* they are inflating.
*
* #param context The Context the view is running in, through which it can
* access the current theme, resources, etc.
* #param attrs The attributes of the XML tag that is inflating the view.
* #param defStyle The default style to apply to this view. If 0, no style
* will be applied (beyond what is included in the theme). This may
* either be an attribute resource, whose value will be retrieved
* from the current theme, or an explicit style resource.
* #see #RobotoTextView(Context, AttributeSet)
*/
public RobotoTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
parseAttributes(context, attrs);
}
/**
* Parse the attributes.
*
* #param context The Context the view is running in, through which it can access the current theme, resources, etc.
* #param attrs The attributes of the XML tag that is inflating the view.
*/
private void parseAttributes(Context context, AttributeSet attrs) {
TypedArray values = context.obtainStyledAttributes(attrs, R.styleable.RobotoTextView);
int typefaceValue = values.getInt(R.styleable.RobotoTextView_typeface, 0);
values.recycle();
setTypeface(obtaintTypeface(context, typefaceValue));
}
/**
* Obtain typeface.
*
* #param context The Context the view is running in, through which it can
* access the current theme, resources, etc.
* #param typefaceValue values ​​for the "typeface" attribute
* #return Roboto {#link Typeface}
* #throws IllegalArgumentException if unknown `typeface` attribute value.
*/
private Typeface obtaintTypeface(Context context, int typefaceValue) throws IllegalArgumentException {
Typeface typeface = mTypefaces.get(typefaceValue);
if (typeface == null) {
typeface = createTypeface(context, typefaceValue);
mTypefaces.put(typefaceValue, typeface);
}
return typeface;
}
/**
* Create typeface from assets.
*
* #param context The Context the view is running in, through which it can
* access the current theme, resources, etc.
* #param typefaceValue values ​​for the "typeface" attribute
* #return Roboto {#link Typeface}
* #throws IllegalArgumentException if unknown `typeface` attribute value.
*/
private Typeface createTypeface(Context context, int typefaceValue) throws IllegalArgumentException {
Typeface typeface;
switch (typefaceValue) {
case ROBOTO_THIN:
typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Thin.ttf");
break;
case ROBOTO_THIN_ITALIC:
typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-ThinItalic.ttf");
break;
case ROBOTO_LIGHT:
typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Light.ttf");
break;
case ROBOTO_LIGHT_ITALIC:
typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-LightItalic.ttf");
break;
case ROBOTO_REGULAR:
typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Regular.ttf");
break;
case ROBOTO_ITALIC:
typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Italic.ttf");
break;
case ROBOTO_MEDIUM:
typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Medium.ttf");
break;
case ROBOTO_MEDIUM_ITALIC:
typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-MediumItalic.ttf");
break;
case ROBOTO_BOLD:
typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Bold.ttf");
break;
case ROBOTO_BOLD_ITALIC:
typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-BoldItalic.ttf");
break;
case ROBOTO_BLACK:
typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Black.ttf");
break;
case ROBOTO_BLACK_ITALIC:
typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-BlackItalic.ttf");
break;
case ROBOTO_CONDENSED:
typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Condensed.ttf");
break;
case ROBOTO_CONDENSED_ITALIC:
typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-CondensedItalic.ttf");
break;
case ROBOTO_CONDENSED_BOLD:
typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-BoldCondensed.ttf");
break;
case ROBOTO_CONDENSED_BOLD_ITALIC:
typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-BoldCondensedItalic.ttf");
break;
default:
throw new IllegalArgumentException("Unknown `typeface` attribute value " + typefaceValue);
}
return typeface;
}
}
Example of use:
<your.package.widget.RobotoTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:typeface="roboto_thin"
android:textSize="22sp"
android:text="Roboto Thin"/>
Resources:
Roboto & Noto fonts
It's too late but my it helps the other
i have created CustomTextView which has an attribute called typeFace and it's care of memory leak problem with typeface loading without caching
Firstly Fonts class which load the fonts from assets for one time only
import android.content.Context;
import android.graphics.Typeface;
import java.util.Hashtable;
/**
* Created by tonyhaddad on 7/19/15.
*/
public class Fonts {
private Context context;
public Fonts(Context context) {
this.context = context;
}
private static Hashtable<String, Typeface> sTypeFaces = new Hashtable<String, Typeface>(
4);
public static Typeface getTypeFace(Context context, String fileName) {
Typeface tempTypeface = sTypeFaces.get(fileName);
if (tempTypeface == null) {
String fontPath=null;
if(fileName=="metabold")
fontPath ="fonts/Meta-Bold.ttf";
else if(fileName=="metanormal")
fontPath="fonts/Meta-Normal.ttf";
else if(fileName=="gsligh")
fontPath="fonts/gesslight.ttf";
else if(fileName=="bold")
fontPath="fonts/Lato-Bold.ttf";
else if(fileName=="rcr")
fontPath="fonts/RobotoCondensed-Regular.ttf";
else if(fileName=="mpr")
fontPath="fonts/MyriadPro-Regular.otf";
else if(fileName=="rr")
fontPath="fonts/Roboto-Regular.ttf";
tempTypeface = Typeface.createFromAsset(context.getAssets(), fontPath);
sTypeFaces.put(fileName, tempTypeface);
}
return tempTypeface;
}
}
then you need to add a custom attribute in the attrs.xml add this
<declare-styleable name="CustomFontTextView">
<attr name="typeFace" format="string" />
</declare-styleable>
then custom class
package package_name;
/**
* Created by tonyhaddad on 8/26/15.
*/
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.widget.TextView;
import package_name.R;
public class CustomFontTextView extends TextView {
String typeFace;
public CustomFontTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
if (isInEditMode()) {
return;
}
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.CustomFontTextView,
0, 0);
try {
typeFace = a.getString(0);
} finally {
a.recycle();
}
if(typeFace!=null && !typeFace.equalsIgnoreCase(""))
{
Typeface tf = Fonts.getTypeFace(context, typeFace);
setTypeface(tf);
}
init();
}
public CustomFontTextView(Context context, AttributeSet attrs) {
super(context, attrs);
if (isInEditMode()) {
return;
}
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.CustomFontTextView,
0, 0);
try {
typeFace = a.getString(0);
} finally {
a.recycle();
}
if(typeFace!=null && !typeFace.equalsIgnoreCase(""))
{
Typeface tf = Fonts.getTypeFace(context, typeFace);
setTypeface(tf);
}
init();
}
public CustomFontTextView(Context context) {
super(context);
if(typeFace!=null && !typeFace.equalsIgnoreCase(""))
{
Typeface tf = Fonts.getTypeFace(context, typeFace);
setTypeface(tf);
}
init();
}
private void init() {
}
public String getTypeFace() {
return typeFace;
}
public void setTypeFace(String typeFace) {
this.typeFace = typeFace;
invalidate();
requestLayout();
}
}
and finally add the text view
<package_name.CustomFontTextView
xmlns:custom="http://schemas.android.com/apk/res-auto/package_name"
android:id="#+id/txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="41dp"
android:gravity="center_vertical"
android:text="text"
android:textColor="#000"
android:textSize="23sp"
custom:typeFace="metanormal"/>
and you can change the font progrmaticlly with setTypeFace method
also you can move the custom namespace to your parent layout if you want to use more than one from this view
Happy Coding :)
The method below, called in onCreate() and passed your outermost ViewGroup, will work for everything but text that is dynamically created (ie dynamic lists, alerts, etc.). An easy way to get the outermost ViewGroup is to use getRootView on any one of your views.
public void onCreate(Bundle savedInstanceState){
//onCreate code...
EditText text = (EditText) findViewById(R.id.editText1);
setTypeFaceForViewGroup((ViewGroup) text.getRootView());
}
private void setTypeFaceForViewGroup(ViewGroup vg){
for (int i = 0; i < vg.getChildCount(); i++) {
if (vg.getChildAt(i) instanceof ViewGroup)
setTypeFaceForViewGroup((ViewGroup) vg.getChildAt(i));
else if (vg.getChildAt(i) instanceof TextView)
((TextView) vg.getChildAt(i)).setTypeface(Typeface.createFromAsset(getAssets(), "fonts/Your_Font.ttf"));
}
}
This should work for dynamic content as well, you'd just have to call it, passing in whatever you created, just after you created it (I haven't tested this, though).
To save memory, you'll probably want to make the typeface a static variable, rather than creating a new one each time the loop runs like I have here.
If you are looking for a more general programatic solution, I created a static class that can be used to set the Typeface of an entire view (Activity UI). Note that I am working with Mono (C#) but you can implement it easily using Java.
You can pass this class a layout or a specific view that you want to customize. If you want to be super efficient you could implement it using the Singleton pattern.
public static class AndroidTypefaceUtility
{
static AndroidTypefaceUtility()
{
}
//Refer to the code block beneath this one, to see how to create a typeface.
public static void SetTypefaceOfView(View view, Typeface customTypeface)
{
if (customTypeface != null && view != null)
{
try
{
if (view is TextView)
(view as TextView).Typeface = customTypeface;
else if (view is Button)
(view as Button).Typeface = customTypeface;
else if (view is EditText)
(view as EditText).Typeface = customTypeface;
else if (view is ViewGroup)
SetTypefaceOfViewGroup((view as ViewGroup), customTypeface);
else
Console.Error.WriteLine("AndroidTypefaceUtility: {0} is type of {1} and does not have a typeface property", view.Id, typeof(View));
}
catch (Exception ex)
{
Console.Error.WriteLine("AndroidTypefaceUtility threw:\n{0}\n{1}", ex.GetType(), ex.StackTrace);
throw ex;
}
}
else
{
Console.Error.WriteLine("AndroidTypefaceUtility: customTypeface / view parameter should not be null");
}
}
public static void SetTypefaceOfViewGroup(ViewGroup layout, Typeface customTypeface)
{
if (customTypeface != null && layout != null)
{
for (int i = 0; i < layout.ChildCount; i++)
{
SetTypefaceOfView(layout.GetChildAt(i), customTypeface);
}
}
else
{
Console.Error.WriteLine("AndroidTypefaceUtility: customTypeface / layout parameter should not be null");
}
}
}
In your activity you will need to create a Typeface object. I create mine in the OnCreate() using a .ttf file placed in my Resources/Assets/ directory. Make sure that the file is marked as an Android Asset in its' properties.
protected override void OnCreate(Bundle bundle)
{
...
LinearLayout rootLayout = (LinearLayout)FindViewById<LinearLayout>(Resource.Id.signInView_LinearLayout);
Typeface allerTypeface = Typeface.CreateFromAsset(base.Assets,"Aller_Rg.ttf");
AndroidTypefaceUtility.SetTypefaceOfViewGroup(rootLayout, allerTypeface);
}
Unfortunately, Android doesn't provide the quick, easy and clean way you're looking for to change the font for your entire app. But recently I've looked into this matter and created some tools that allow you to change the font without any coding (you can do it all through xml, styles and even text appearances). They're based on similar solutions like you see in the other answers here, but allow for far more flexibility. You can read all about it on this blog, and see the github project here.
Here's an example of how to apply these tools. Put all your font files in assets/fonts/. Then, declare those fonts in an xml file (e.g. res/xml/fonts.xml) and load this file early in your app with TypefaceManager.initialize(this, R.xml.fonts); (e.g., in the onCreate of your Application class). The xml file looks like this:
<?xml version="1.0" encoding="utf-8"?>
<familyset>
<!-- Some Font. Can be referenced with 'someFont' or 'aspergit' -->
<family>
<nameset>
<name>aspergit</name>
<name>someFont</name>
</nameset>
<fileset>
<file>Aspergit.ttf</file>
<file>Aspergit Bold.ttf</file>
<file>Aspergit Italic.ttf</file>
<file>Aspergit Bold Italic.ttf</file>
</fileset>
</family>
<!-- Another Font. Can be referenced with 'anotherFont' or 'bodoni' -->
<family>
<nameset>
<name>bodoni</name>
<name>anotherFont</name>
</nameset>
<fileset>
<file>BodoniFLF-Roman.ttf</file>
<file>BodoniFLF-Bold.ttf</file>
</fileset>
</family>
</familyset>
Now you can use these fonts in your style or xml (provided you use the tools I mentioned above), by using the custom UI element com.innovattic.font.FontTextView in your xml layout. Below you can see how you can apply a font to all texts in your entire app, just by editing res/values/styles.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
<!-- Application theme -->
<!-- Use a different parent if you don't want Holo Light -->
<style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
<item name="android:textViewStyle">#style/MyTextViewStyle</item>
</style>
<!-- Style to use for ALL text views (including FontTextView) -->
<!-- Use a different parent if you don't want Holo Light -->
<style name="MyTextViewStyle" parent="#android:style/Widget.Holo.Light.TextView">
<item name="android:textAppearance">#style/MyTextAppearance</item>
</style>
<!-- Text appearance to use for ALL text views (including FontTextView) -->
<!-- Use a different parent if you don't want Holo Light -->
<style name="MyTextAppearance" parent="#android:style/TextAppearance.Holo">
<!-- Alternatively, reference this font with the name "aspergit" -->
<!-- Note that only our own TextView's will use the font attribute -->
<item name="flFont">someFont</item>
<item name="android:textStyle">bold|italic</item>
</style>
<!-- Alternative style, maybe for some other widget -->
<style name="StylishFont">
<item name="flFont">anotherFont</item>
<item name="android:textStyle">normal</item>
</style>
</resources>
With the accompanying res/layout/layout.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<!-- This text view is styled with the app theme -->
<com.innovattic.font.FontTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="This uses my font in bold italic style" />
<!-- This text view is styled here and overrides the app theme -->
<com.innovattic.font.FontTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:flFont="anotherFont"
android:textStyle="normal"
android:text="This uses another font in normal style" />
<!-- This text view is styled with a style and overrides the app theme -->
<com.innovattic.font.FontTextView
style="#style/StylishFont"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="This also uses another font in normal style" />
</LinearLayout>
Don't forget to apply the theme in your Android manifest.
I would like to add a note to the great solution of leocadiotine. It is perfect, but when using this Custom TextView many time slows down the application, since it has to access the assets every time a textview is created. I suggest to use something like the View Holder pattern in the Adapters, i wrote an example:
public class Fonts {
private static final Map<String, Typeface> typefaces = new HashMap<String, Typeface>();
public static Typeface getTypeface(Context ctx, String fontName) {
Typeface typeface = typefaces.get(fontName);
if (typeface == null) {
typeface = Typeface.createFromAsset(ctx.getAssets(), fontName);
typefaces.put(fontName, typeface);
}
return typeface;
}
}
In this way the application access the assets only one time per asset, and it keeps them in memory for further needs.
I don't know if it changes the whole app, but I have managed to change some components that couldn't otherwise be changed by doing this:
Typeface tf = Typeface.createFromAsset(getAssets(), "fonts/Lucida Sans Unicode.ttf");
Typeface.class.getField("DEFAULT").setAccessible(true);
Typeface.class.getField("DEFAULT_BOLD").setAccessible(true);
Typeface.class.getField("DEFAULT").set(null, tf);
Typeface.class.getField("DEFAULT_BOLD").set(null, tf);
I have found step by step information at this link,link: https://github.com/jaydipumaretiya/CustomTypeface/
There are many ways to use typeface correctly in android, you have to put your typeface file in
assets folder under your main directly and can use it run-time.
Other simplest way is use default library to set typeface in your xml file.
I have prefer this custom typeface library to set typeface to TextView, EditText, Button, CheckBox,
RadioButton and AutoCompleteTextView and other wedget in android.
Android 8.0 (API level 26) introduces a new feature, Fonts in XML.You can create a fontfamily file and set it in styles.xml.
To add fonts as resources, perform the following steps in the Android
Studio:
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. Note: The name of the resource directory must be font.
3.Add your font files in the font folder.
To create a font family, perform the following steps :
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 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/lobster_regular" />
<font
android:fontStyle="italic"
android:fontWeight="400"
android:font="#font/lobster_italic" />
</font-family>
Adding fonts to style
Open the styles.xml, and set the fontFamily attribute to the font file
you want to access.
<style name="customfontstyle" parent="#android:style/TextAppearance.Small">
<item name="android:fontFamily">#font/lobster</item>
</style>
Source:Fonts in XML
To use external fonts, first download the font in .tff format
Google font- Roboto
Add the font asset folder as shown in the image below
After the font asset folder is created, copy and paste the downloaded .tff font into the "font" folder. (make sure the name is formatted well. )
Reference the font in your theme.xml or any layout using the android:fontFamily="#font/splashfont" property.
If you want the font to apply to the entire application, set the fontfamily in you theme.xml. This is how you do it in a theme.xml file
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.FishPott" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">#color/color_black_level_1</item>
<item name="colorPrimaryVariant">#color/color_black_level_2</item>
<item name="colorOnPrimary">#color/white</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">#color/color_black_level_1</item>
<item name="colorSecondaryVariant">#color/color_black_level_2</item>
<item name="colorOnSecondary">#color/color_white_level_1</item>
<!-- Status bar color. -->
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
<item name="android:fontFamily">#font/robotoregular</item>
</style>

Categories

Resources