I want to set font for the "Video" and "Image" tabs in ActionBarSherlock. I have used the following code to do so. Its showing accurately in ICS but not in the lower version device but I have shown accurate output in the other part of this application by setting TYPE FACE like ...
a.settypeface("ab.tttf");
a.settext("VIDEO");
But how to do I set a TypeFace in the ActionBar in this code:
mTabsAdapter.addTab(bar.newTab().setText("IMAGE"), AFragment.class, null);
mTabsAdapter.addTab(bar.newTab().setText("VIDEO"), BFragment.class, null);
Okay . I found it myself some where on SO.
First make an xml file with this in it: tab_title.xml
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/action_custom_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="My Custom title"
android:textColor="#fff"
android:textSize="18sp"
android:paddingTop="5dp" />
Then in the class where you in instantiate your ActionBar use this code to set the text on each of the tabs. (This example is using ActionBarSherlock.)
ActionBar bar = getSupportActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
String[] tabNames = {"Tab 1","Tab 2","Tab 3"};
for(int i = 0; i<bar.getTabCount(); i++){
LayoutInflater inflater = LayoutInflater.from(this);
View customView = inflater.inflate(R.layout.tab_title, null);
TextView titleTV = (TextView) customView.findViewById(R.id.action_custom_title);
titleTV.setText(tabNames[i]);
//Here you can also add any other styling you want.
bar.getTabAt(i).setCustomView(customView);
}
Try this:
String s = "VIDEO";
SpannableString mSS = new SpannableString(s);
mSS.setSpan(new StyleSpan(Typeface.BOLD), 0, s.length(), 0);
mTabsAdapter.addTab(bar.newTab().setText(mSS),
BFragment.class, null);
To solve this you could create a Special Actionbar class.
Simply create a Class myBar extends Sherlockactionbar and put in the settypeface. If you now create that Bar in your view it will have the Typeface as you whish. For example here is an button with a new Typeface.
public class ChangedButton extends Button{
public ChangedButton(Context context, AttributeSet attrs) {
super(context, attrs);
Typeface font = Typeface.createFromAsset(context.getAssets(), "fonts/viking2.TTF");
this.setTypeface(font);
}
}
regards
First create following custom TypefaceSpan class in your project.Bit changed version of Custom TypefaceSpan to enable to use both .otf and .ttf fonts.
import java.util.StringTokenizer;
import android.content.Context;
import android.graphics.Typeface;
import android.support.v4.util.LruCache;
import android.text.TextPaint;
import android.text.style.MetricAffectingSpan;
public class TypefaceSpan extends MetricAffectingSpan{
/*Cache to save loaded fonts*/
private static LruCache<String, Typeface> typeFaceCache= new LruCache<String, Typeface>(12);
private Typeface mTypeface;
public TypefaceSpan(Context context,String typeFaceName)
{
StringTokenizer tokens=new StringTokenizer(typeFaceName,".");
String fontName=tokens.nextToken();
mTypeface=typeFaceCache.get(fontName);
if(mTypeface==null)
{
mTypeface=Constants.getFont(context, typeFaceName);
//cache the loaded font
typeFaceCache.put(fontName, mTypeface);
}
}
#Override
public void updateMeasureState(TextPaint p) {
p.setTypeface(mTypeface);
}
#Override
public void updateDrawState(TextPaint tp) {
tp.setTypeface(mTypeface);
}
}
Now apply code like this:(I used this on one of my Bangla apps successfully)
SpannableString mstKnwTitle=new SpannableString(getString(R.string.e_mustknow_tab));
SpannableString cntctsTitle=new SpannableString(getString(R.string.e_number_tab));
TypefaceSpan span=new TypefaceSpan(this, "solaimanlipi.ttf");
mstKnwTitle.setSpan(span, 0, mstKnwTitle.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
cntctsTitle.setSpan(span, 0, mstKnwTitle.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
Tab tab= actionBar.newTab();
tab.setText(mstKnwTitle);
tab.setTabListener(tabListener);
actionBar.addTab(tab);
tab= actionBar.newTab();
tab.setText(cntctsTitle);
tab.setTabListener(tabListener);
actionBar.addTab(tab);
Original inspiration of my answer was:Styling the Android Action Bar title using a custom typeface
It seems like you are not getting any guidance. I am not sure with my answer's result but yes you can defiantly get idea to make it as you want.
Let me try to help you. I think you have to somewhat play with the in-built default resources of the android sdk.
You have to create custom style:
<style name="MyActionBarTabText" parent="Widget.ActionBar.TabText">
<item name="android:textAppearance">#style/TextAppearance.Holo.Medium</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
<item name="android:textSize">12sp</item>
<item name="android:textStyle">bold</item>
<item name="android:textAllCaps">true</item>
<item name="android:ellipsize">marquee</item>
<item name="android:maxLines">2</item>
</style>
<style name="Widget.ActionBar.TabText" parent="Widget">
<item name="android:textAppearance">#style/TextAppearance.Widget.TextView.PopupMenu</item>
<item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
<item name="android:textSize">18sp</item>
<item name="android:fontFamily">HERE YOU CAN GIVE YOUR FONT</item>
</style>
You can also refer this SO.
Now just apply that theme to your activity and you will get Font of the TabText as you want.
Comment me if have any query.
Enjoy coding... :)
In EXTRA
Another solution could be to modify the tab image to include the text, with GIMP or photoshop something, and then just set those images in the tabs, instead of images and text. It is a bit of an awkward way of doing it but it would work.
Hope this helps!
You can do it with this:
// Set a custom font on all of our ActionBar Tabs
private boolean setCustomFontToActionBarTab(Object root) {
// Found the container, that holds the Tabs. This is the ScrollContainerView to be specific,
// but checking against that class is not possible, since it's part of the hidden API.
// We will check, if root is an instance of HorizontalScrollView instead,
// since ScrollContainerView extends HorizontalScrollView.
if (root instanceof HorizontalScrollView) {
// The Tabs are all wraped in a LinearLayout
root = ((ViewGroup) root).getChildAt(0);
if (root instanceof LinearLayout) {
// Found the Tabs. Now we can set a custom Font to all of them.
for (int i = 0; i < ((ViewGroup) root).getChildCount(); i++) {
LinearLayout child = ((LinearLayout)((ViewGroup) root).getChildAt(i));
TextView actionBarTitle = (TextView) child.getChildAt(0);
Typeface tf = Typeface.createFromAsset(mContext.getAssets(), "font/font.ttf");
actionBarTitle.setTypeface(tf)
}
return true;
}
}
// Search ActionBar and the Tabs. Exclude the content of the app from this search.
else if (root instanceof ViewGroup) {
ViewGroup group = (ViewGroup) root;
if (group.getId() != android.R.id.content) {
// Found a container that isn't the container holding our screen layout.
// The Tabs have to be in here.
for (int i = 0; i < group.getChildCount(); i++) {
if (setCustomFontToActionBarTab(group.getChildAt(i))) {
// Found and done searching the View tree
return true;
}
}
}
}
// Found nothing
return false;
}
Call it with this:
ViewParent root = findViewById(android.R.id.content).getParent();
setCustomFontToActionBarTab(root);
Related
Sorry for the possibly confusing title
So I'm using ViewPagerIndicator, which is a library commonly used for tabs before TabLayout was released in 5.0. In this library, tabs are views that extend TextView, that accepted a custom attribute for styling.
//An inner class of TabPageLayout
private class TabView extends TextView {
private int mIndex;
public TabView(Context context) {
super(context, null, R.attr.vpiTabPageIndicatorStyle); //<--custom attribute
}
// ...
}
vpi__attrs.xml
<resources>
<declare-styleable name="ViewPagerIndicator">
...
<!-- Style of the tab indicator's tabs. -->
<attr name="vpiTabPageIndicatorStyle" format="reference"/>
</declare-styleable>
...
With this setup, when I used TabPageLayout in my own project, I could define the style of the text like this
<!--This is styles.xml of my project -->
<style name="MyStyle.Tabs" parent="MyStyle" >
<item name="vpiTabPageIndicatorStyle">#style/CustomTabPageIndicator</item>
</style>
<style name="CustomTabPageIndicator">
<item name="android:gravity">center</item>
<item name="android:textStyle">bold</item>
<item name="android:textSize">#dimen/secondary_text_size</item>
...
</style>
The following style would be applied to the Activity, and it would override the default vpiTabPageIndicator in the ViewPagerIndicator library.
My problem now is that I needed to make more customization to TabView than a TextView would allow, so I created a new inner class called "TabLayoutWithIcon" that extends LinearLayout and includes a TextView.
private class TabViewWithIcon extends LinearLayout {
private int mIndex;
private TextView mText;
public TabViewWithIcon(Context context) {
super(context, null, R.attr.vpiTabPageIndicatorStyle);
//setBackgroundResource(R.drawable.vpi__tab_indicator);
mText = new TextView(context);
}
...
public void setText(CharSequence text){
mText.setText(Integer.toString(mIndex) + " tab");
addView(mText);
}
public void setImage(int iconResId){
mText.setCompoundDrawablesWithIntrinsicBounds(iconResId, 0, 0, 0);
mText.setCompoundDrawablePadding(8); //Just temporary
}
Now the same custom style is being applied to a LinearLayout, but I also want to style the child TextView. How can I do this?
Of course, I could also just pass in a style for the TextView programatically inside TabViewWithIcon,like
mText.setTextAppearance(context, R.style.CustomTabTextStyle);
but then I would have to write my custom style inside the library, which I shouldn't be doing.
Do I need to redefine some attributes or something? Am I approaching this incorrectly?
Im an idiot, I just have pass the custom TextView style into the TextView
public TabView(Context context) {
super(context, null, R.attr.vpiTabPageIndicatorStyle);
//setBackgroundResource(R.drawable.vpi__tab_indicator);
mText = new TextView(context, null, R.attr.vpiTabPageIndicatorStyle);
}
First of all, this question asks a very similar question. However, my question has a subtle difference.
What I'd like to know is whether it is possible to programmatically change the colorPrimary attribute of a theme to an arbitrary color?
So for example, we have:
<style name="AppTheme" parent="android:Theme.Material.Light">
<item name="android:colorPrimary">#ff0000</item>
<item name="android:colorAccent">#ff0000</item>
</style>
At runtime, the user decides he wants to use #ccffff as a primary color. Ofcourse there's no way I can create themes for all possible colors.
I don't mind if I have to do hacky stuff, like relying on Android's private internals, as long as it works using the public SDK.
My goal is to eventually have the ActionBar and all widgets like a CheckBox to use this primary color.
Themes are immutable, you can't.
I read the comments about contacts app and how it use a theme for each contact.
Probably, contacts app has some predefine themes (for each material primary color from here: http://www.google.com/design/spec/style/color.html).
You can apply a theme before a the setContentView method inside onCreate method.
Then the contacts app can apply a theme randomly to each user.
This method is:
setTheme(R.style.MyRandomTheme);
But this method has a problem, for example it can change the toolbar color, the scroll effect color, the ripple color, etc, but it cant change the status bar color and the navigation bar color (if you want to change it too).
Then for solve this problem, you can use the method before and:
if (Build.VERSION.SDK_INT >= 21) {
getWindow().setNavigationBarColor(getResources().getColor(R.color.md_red_500));
getWindow().setStatusBarColor(getResources().getColor(R.color.md_red_700));
}
This two method change the navigation and status bar color.
Remember, if you set your navigation bar translucent, you can't change its color.
This should be the final code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTheme(R.style.MyRandomTheme);
if (Build.VERSION.SDK_INT >= 21) {
getWindow().setNavigationBarColor(getResources().getColor(R.color.myrandomcolor1));
getWindow().setStatusBarColor(getResources().getColor(R.color.myrandomcolor2));
}
setContentView(R.layout.activity_main);
}
You can use a switch and generate random number to use random themes, or, like in contacts app, each contact probably has a predefine number associated.
A sample of theme:
<style name="MyRandomTheme" parent="Theme.AppCompat.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">#color/myrandomcolor1</item>
<item name="colorPrimaryDark">#color/myrandomcolor2</item>
<item name="android:navigationBarColor">#color/myrandomcolor1</item>
</style>
You can use Theme.applyStyle to modify your theme at runtime by applying another style to it.
Let's say you have these style definitions:
<style name="DefaultTheme" parent="Theme.AppCompat.Light">
<item name="colorPrimary">#color/md_lime_500</item>
<item name="colorPrimaryDark">#color/md_lime_700</item>
<item name="colorAccent">#color/md_amber_A400</item>
</style>
<style name="OverlayPrimaryColorRed">
<item name="colorPrimary">#color/md_red_500</item>
<item name="colorPrimaryDark">#color/md_red_700</item>
</style>
<style name="OverlayPrimaryColorGreen">
<item name="colorPrimary">#color/md_green_500</item>
<item name="colorPrimaryDark">#color/md_green_700</item>
</style>
<style name="OverlayPrimaryColorBlue">
<item name="colorPrimary">#color/md_blue_500</item>
<item name="colorPrimaryDark">#color/md_blue_700</item>
</style>
Now you can patch your theme at runtime like so:
getTheme().applyStyle(R.style.OverlayPrimaryColorGreen, true);
The method applyStylehas to be called before the layout gets inflated! So unless you load the view manually you should apply styles to the theme before calling setContentView in your activity.
Of course this cannot be used to specify an arbitrary color, i.e. one out of 16 million (2563) colors. But if you write a small program that generates the style definitions and the Java code for you then something like one out of 512 (83) should be possible.
What makes this interesting is that you can use different style overlays for different aspects of your theme. Just add a few overlay definitions for colorAccent for example. Now you can combine different values for primary color and accent color almost arbitrarily.
You should make sure that your overlay theme definitions don't accidentally inherit a bunch of style definitions from a parent style definition. For example a style called AppTheme.OverlayRed implicitly inherits all styles defined in AppTheme and all these definitions will also be applied when you patch the master theme. So either avoid dots in the overlay theme names or use something like Overlay.Red and define Overlay as an empty style.
I've created some solution to make any-color themes, maybe this can be useful for somebody. API 9+
1. first create "res/values-v9/" and put there this file: styles.xml
and regular "res/values" folder will be used with your styles.
2. put this code in your res/values/styles.xml:
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light">
<item name="colorPrimary">#000</item>
<item name="colorPrimaryDark">#000</item>
<item name="colorAccent">#000</item>
<item name="android:windowAnimationStyle">#style/WindowAnimationTransition</item>
</style>
<style name="AppThemeDarkActionBar" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="colorPrimary">#000</item>
<item name="colorPrimaryDark">#000</item>
<item name="colorAccent">#000</item>
<item name="android:windowAnimationStyle">#style/WindowAnimationTransition</item>
</style>
<style name="WindowAnimationTransition">
<item name="android:windowEnterAnimation">#android:anim/fade_in</item>
<item name="android:windowExitAnimation">#android:anim/fade_out</item>
</style>
</resources>
3. in to AndroidManifest:
<application android:theme="#style/AppThemeDarkActionBar">
4. create a new class with name "ThemeColors.java"
public class ThemeColors {
private static final String NAME = "ThemeColors", KEY = "color";
#ColorInt
public int color;
public ThemeColors(Context context) {
SharedPreferences sharedPreferences = context.getSharedPreferences(NAME, Context.MODE_PRIVATE);
String stringColor = sharedPreferences.getString(KEY, "004bff");
color = Color.parseColor("#" + stringColor);
if (isLightActionBar()) context.setTheme(R.style.AppTheme);
context.setTheme(context.getResources().getIdentifier("T_" + stringColor, "style", context.getPackageName()));
}
public static void setNewThemeColor(Activity activity, int red, int green, int blue) {
int colorStep = 15;
red = Math.round(red / colorStep) * colorStep;
green = Math.round(green / colorStep) * colorStep;
blue = Math.round(blue / colorStep) * colorStep;
String stringColor = Integer.toHexString(Color.rgb(red, green, blue)).substring(2);
SharedPreferences.Editor editor = activity.getSharedPreferences(NAME, Context.MODE_PRIVATE).edit();
editor.putString(KEY, stringColor);
editor.apply();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) activity.recreate();
else {
Intent i = activity.getPackageManager().getLaunchIntentForPackage(activity.getPackageName());
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
activity.startActivity(i);
}
}
private boolean isLightActionBar() {// Checking if title text color will be black
int rgb = (Color.red(color) + Color.green(color) + Color.blue(color)) / 3;
return rgb > 210;
}
}
5. MainActivity:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new ThemeColors(this);
setContentView(R.layout.activity_main);
}
public void buttonClick(View view){
int red= new Random().nextInt(255);
int green= new Random().nextInt(255);
int blue= new Random().nextInt(255);
ThemeColors.setNewThemeColor(MainActivity.this, red, green, blue);
}
}
To change color, just replace Random with your RGB, Hope this helps.
There is a complete example: ColorTest.zip
You can have a look at this GitHub project from Rumit Patel.
I used the Dahnark's code but I also need to change the ToolBar background:
if (dark_ui) {
this.setTheme(R.style.Theme_Dark);
if (Build.VERSION.SDK_INT >= 21) {
getWindow().setNavigationBarColor(getResources().getColor(R.color.Theme_Dark_primary));
getWindow().setStatusBarColor(getResources().getColor(R.color.Theme_Dark_primary_dark));
}
} else {
this.setTheme(R.style.Theme_Light);
}
setContentView(R.layout.activity_main);
toolbar = (Toolbar) findViewById(R.id.app_bar);
if(dark_ui) {
toolbar.setBackgroundColor(getResources().getColor(R.color.Theme_Dark_primary));
}
You can change define your own themes, or customize existing android themes in res > values > themes, find where it says primary color and point it to the color defined in color.xml you want
<style name="Theme.HelloWorld" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">#color/my_color</item>
<item name="colorPrimaryVariant">#color/my_color</item>
<item name="colorOnPrimary">#color/white</item>
from an activity you can do:
getWindow().setStatusBarColor(i color);
You cannot change the color of colorPrimary, but you can change the theme of your application by adding a new style with a different colorPrimary color
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
</style>
<style name="AppTheme.NewTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">#color/colorOne</item>
<item name="colorPrimaryDark">#color/colorOneDark</item>
</style>
and inside the activity set theme
setTheme(R.style.AppTheme_NewTheme);
setContentView(R.layout.activity_main);
USE A TOOLBAR
You can set a custom toolbar item color dynamically by creating a custom toolbar class:
package view;
import android.app.Activity;
import android.content.Context;
import android.graphics.ColorFilter;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.support.v7.internal.view.menu.ActionMenuItemView;
import android.support.v7.widget.ActionMenuView;
import android.support.v7.widget.Toolbar;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AutoCompleteTextView;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
public class CustomToolbar extends Toolbar{
public CustomToolbar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// TODO Auto-generated constructor stub
}
public CustomToolbar(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
public CustomToolbar(Context context) {
super(context);
// TODO Auto-generated constructor stub
ctxt = context;
}
int itemColor;
Context ctxt;
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
Log.d("LL", "onLayout");
super.onLayout(changed, l, t, r, b);
colorizeToolbar(this, itemColor, (Activity) ctxt);
}
public void setItemColor(int color){
itemColor = color;
colorizeToolbar(this, itemColor, (Activity) ctxt);
}
/**
* Use this method to colorize toolbar icons to the desired target color
* #param toolbarView toolbar view being colored
* #param toolbarIconsColor the target color of toolbar icons
* #param activity reference to activity needed to register observers
*/
public static void colorizeToolbar(Toolbar toolbarView, int toolbarIconsColor, Activity activity) {
final PorterDuffColorFilter colorFilter
= new PorterDuffColorFilter(toolbarIconsColor, PorterDuff.Mode.SRC_IN);
for(int i = 0; i < toolbarView.getChildCount(); i++) {
final View v = toolbarView.getChildAt(i);
doColorizing(v, colorFilter, toolbarIconsColor);
}
//Step 3: Changing the color of title and subtitle.
toolbarView.setTitleTextColor(toolbarIconsColor);
toolbarView.setSubtitleTextColor(toolbarIconsColor);
}
public static void doColorizing(View v, final ColorFilter colorFilter, int toolbarIconsColor){
if(v instanceof ImageButton) {
((ImageButton)v).getDrawable().setAlpha(255);
((ImageButton)v).getDrawable().setColorFilter(colorFilter);
}
if(v instanceof ImageView) {
((ImageView)v).getDrawable().setAlpha(255);
((ImageView)v).getDrawable().setColorFilter(colorFilter);
}
if(v instanceof AutoCompleteTextView) {
((AutoCompleteTextView)v).setTextColor(toolbarIconsColor);
}
if(v instanceof TextView) {
((TextView)v).setTextColor(toolbarIconsColor);
}
if(v instanceof EditText) {
((EditText)v).setTextColor(toolbarIconsColor);
}
if (v instanceof ViewGroup){
for (int lli =0; lli< ((ViewGroup)v).getChildCount(); lli ++){
doColorizing(((ViewGroup)v).getChildAt(lli), colorFilter, toolbarIconsColor);
}
}
if(v instanceof ActionMenuView) {
for(int j = 0; j < ((ActionMenuView)v).getChildCount(); j++) {
//Step 2: Changing the color of any ActionMenuViews - icons that
//are not back button, nor text, nor overflow menu icon.
final View innerView = ((ActionMenuView)v).getChildAt(j);
if(innerView instanceof ActionMenuItemView) {
int drawablesCount = ((ActionMenuItemView)innerView).getCompoundDrawables().length;
for(int k = 0; k < drawablesCount; k++) {
if(((ActionMenuItemView)innerView).getCompoundDrawables()[k] != null) {
final int finalK = k;
//Important to set the color filter in seperate thread,
//by adding it to the message queue
//Won't work otherwise.
//Works fine for my case but needs more testing
((ActionMenuItemView) innerView).getCompoundDrawables()[finalK].setColorFilter(colorFilter);
// innerView.post(new Runnable() {
// #Override
// public void run() {
// ((ActionMenuItemView) innerView).getCompoundDrawables()[finalK].setColorFilter(colorFilter);
// }
// });
}
}
}
}
}
}
}
then refer to it in your layout file. Now you can set a custom color using
toolbar.setItemColor(Color.Red);
Sources:
I found the information to do this here: How to dynamicaly change Android Toolbar icons color
and then I edited it, improved upon it, and posted it here: GitHub:AndroidDynamicToolbarItemColor
This is what you CAN do:
write a file in drawable folder, lets name it background.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<solid android:color="?attr/colorPrimary"/>
</shape>
then set your Layout's (or what so ever the case is) android:background="#drawable/background"
on setting your theme this color would represent the same.
Is there an easy way to make all textviews (and any other text elements in my app) to use a custom font of my own (and not the built-in choices), without having to manually set them via textview.setTypeface()?
I guess extending Textview would do the trick but then building interfaces with the visual editor is kind of a pain. I was thinking of something like styling but can't find how to set a custom font there.
If you need to set one font for all TextViews in android application you can use this solution. It will override ALL TextView's typefaces, includes action bar and other standard components, but EditText's password font won't be overriden.
MyApp.java
public class MyApp extends Application {
#Override
public void onCreate()
{
TypefaceUtil.overrideFont(getApplicationContext(), "SERIF", "fonts/Roboto-Regular.ttf");
}
}
TypefaceUtil.java
public class TypefaceUtil {
/**
* Using reflection to override default typeface
* NOTICE: DO NOT FORGET TO SET TYPEFACE FOR APP THEME AS DEFAULT TYPEFACE WHICH WILL BE OVERRIDDEN
* #param context to work with assets
* #param defaultFontNameToOverride for example "monospace"
* #param customFontFileNameInAssets file name of the font from assets
*/
public static void overrideFont(Context context, String defaultFontNameToOverride, String customFontFileNameInAssets) {
try {
final Typeface customFontTypeface = Typeface.createFromAsset(context.getAssets(), customFontFileNameInAssets);
final Field defaultFontTypefaceField = Typeface.class.getDeclaredField(defaultFontNameToOverride);
defaultFontTypefaceField.setAccessible(true);
defaultFontTypefaceField.set(null, customFontTypeface);
} catch (Exception e) {
Log.e("TypefaceUtil","Can not set custom font " + customFontFileNameInAssets + " instead of " + defaultFontNameToOverride);
}
}
}
themes.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="MyAppTheme" parent="#android:style/Theme.Holo.Light">
<!-- you should set typeface which you want to override with TypefaceUtil -->
<item name="android:typeface">serif</item>
</style>
</resources>
Update for Android 5.0 or greater
As i have investigated and tested on device running api 5.0 or greater this solution is working fine because i am using the single style.xml file and not making other style.xml in values-21 folder
Although
Some users asking me that this solution not working with android 5.0 device (they may be using values-21 style.xml i guess)
So that is because Under API 21, most of the text styles include fontFamily setting, like
<item name="fontFamily">#string/font_family_body_1_material</item>
Which applys the default Roboto Regular font:
<string name="font_family_body_1_material">sans-serif</string>
So the best solution is
If Any one having problem not working for 5.0+. Don't override typeface in your values-v21 styles.
Just override font in values/style.xml and you will good to go :)
You can create a method to set typeface for a textview in a common class and you can set the call that method and send the textview as its attribute.
Yes. Just make a style and set it to a certain font and then set the entire app in that style.
You can do it by creating subclass of TextView and call setTypeFace method within it. For example in constructor.
Make a method in Constants class so that it can be accessed from all fragments and activities:
public static void overrideFonts(final Context context, final View v) {
try {
if (v instanceof ViewGroup) {
ViewGroup vg = (ViewGroup) v;
for (int i = 0; i < vg.getChildCount(); i++) {
View child = vg.getChildAt(i);
overrideFonts(context, child);
}
} else if (v instanceof TextView) {
((TextView) v).setTypeface(Typeface.createFromAsset(context.getAssets(), "font/Lato-Regular.ttf"));
} else if (v instanceof EditText) {
((EditText) v).setTypeface(Typeface.createFromAsset(context.getAssets(), "font/Lato-Regular.ttf"));
} else if (v instanceof Button) {
((Button) v).setTypeface(Typeface.createFromAsset(context.getAssets(), "font/Lato-Regular.ttf"));
}
} catch (Exception e) {
}
}
Call Method in activity as:
Constants.overrideFonts(MainActivity.this, getWindow().getDecorView().getRootView());
Call method in Fragment as:
Constants.overrideFonts(getActivity(), view);
I'm using the Roboto light font in my app. To set the font I've to add the android:fontFamily="sans-serif-light" to every view. Is there any way to declare the Roboto font as default font family to entire app? I've tried like this but it didn't seem to work.
<style name="AppBaseTheme" parent="android:Theme.Light"></style>
<style name="AppTheme" parent="AppBaseTheme">
<item name="android:fontFamily">sans-serif-light</item>
</style>
The answer is yes.
Global Roboto light for TextView and Button classes:
<style name="AppTheme" parent="AppBaseTheme">
<item name="android:textViewStyle">#style/RobotoTextViewStyle</item>
<item name="android:buttonStyle">#style/RobotoButtonStyle</item>
</style>
<style name="RobotoTextViewStyle" parent="android:Widget.TextView">
<item name="android:fontFamily">sans-serif-light</item>
</style>
<style name="RobotoButtonStyle" parent="android:Widget.Holo.Button">
<item name="android:fontFamily">sans-serif-light</item>
</style>
Just select the style you want from list themes.xml, then create your custom style based on the original one. At the end, apply the style as the theme of the application.
<application
android:theme="#style/AppTheme" >
</application>
It will work only with built-in fonts like Roboto, but that was the question. For custom fonts (loaded from assets for example) this method will not work.
EDIT 08/13/15
If you're using AppCompat themes, remember to remove android: prefix. For example:
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="android:textViewStyle">#style/RobotoTextViewStyle</item>
<item name="buttonStyle">#style/RobotoButtonStyle</item>
</style>
Note the buttonStyle doesn't contain android: prefix, but textViewStyle must contain it.
With the release of Android Oreo you can use the support library to reach this goal.
Check in your app build.gradle if you have the support library >=
26.0.0
Add "font" folder to your resources folder and add your fonts there
Reference your default font family in your app main style:
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:fontFamily">#font/your_font</item>
<item name="fontFamily">#font/your_font</item> <!-- target android sdk versions < 26 and > 14 if theme other than AppCompat -->
</style>
Check https://developer.android.com/guide/topics/ui/look-and-feel/fonts-in-xml.html for more detailed information.
To change your app font follow the following steps:
Inside res directory create a new directory and name it font.
Insert your font .ttf/.otf inside the font folder, Make sure the font name is lower case letters and underscore only.
Inside res -> values -> styles.xml inside <resources> -> <style> add your font <item name="android:fontFamily">#font/font_name</item>.
Now all your app text should be in the font that you add.
READ UPDATES BELOW
I had the same issue with embedding a new font and finally got it to work with extending the TextView and set the typefont inside.
public class YourTextView extends TextView {
public YourTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public YourTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public YourTextView(Context context) {
super(context);
init();
}
private void init() {
Typeface tf = Typeface.createFromAsset(context.getAssets(),
"fonts/helveticaneue.ttf");
setTypeface(tf);
}
}
You have to change the TextView Elements later to from to in every element. And if you use the UI-Creator in Eclipse, sometimes he doesn't show the TextViews right. Was the only thing which work for me...
UPDATE
Nowadays I'm using reflection to change typefaces in whole application without extending TextViews. Check out this SO post
UPDATE 2
Starting with API Level 26 and available in 'support library' you can use
android:fontFamily="#font/embeddedfont"
Further information: Fonts in XML
Add this line of code in your res/value/styles.xml
<item name="android:fontFamily">#font/circular_medium</item>
the entire style will look like that
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/colorAccent</item>
<item name="android:fontFamily">#font/circular_medium</item>
</style>
change "circular_medium" to your own font name..
It's very very very easy to do in Android Studio.
In this method you need to verify your minsdkveriosn. It must need minsdkversion >=16
Create "font" folder inside "res" folder. In android studio New > Folder > Font Folder.
Upload your font file to that font folder.
In you style.xml file, Under style in "Base application theme" add this line.
<item name="android:fontFamily">#font/ubuntubold</item>
More Details:
https://coderog.com/community/threads/how-to-set-default-font-family-for-entire-android-app.72/
Not talk about performance, for custom font you can have a recursive method loop through all the views and set typeface if it's a TextView:
public class Font {
public static void setAllTextView(ViewGroup parent) {
for (int i = parent.getChildCount() - 1; i >= 0; i--) {
final View child = parent.getChildAt(i);
if (child instanceof ViewGroup) {
setAllTextView((ViewGroup) child);
} else if (child instanceof TextView) {
((TextView) child).setTypeface(getFont());
}
}
}
public static Typeface getFont() {
return Typeface.createFromAsset(YourApplicationContext.getInstance().getAssets(), "fonts/whateverfont.ttf");
}
}
In all your activity, pass current ViewGroup to it after setContentView and it's done:
ViewGroup group = (ViewGroup) getWindow().getDecorView().findViewById(android.R.id.content);
Font.setAllTextView(group);
For fragment you can do something similar.
Another way to do this for the whole app is using reflection based on this answer
public class TypefaceUtil {
/**
* Using reflection to override default typefaces
* NOTICE: DO NOT FORGET TO SET TYPEFACE FOR APP THEME AS DEFAULT TYPEFACE WHICH WILL BE
* OVERRIDDEN
*
* #param typefaces map of fonts to replace
*/
public static void overrideFonts(Map<String, Typeface> typefaces) {
try {
final Field field = Typeface.class.getDeclaredField("sSystemFontMap");
field.setAccessible(true);
Map<String, Typeface> oldFonts = (Map<String, Typeface>) field.get(null);
if (oldFonts != null) {
oldFonts.putAll(typefaces);
} else {
oldFonts = typefaces;
}
field.set(null, oldFonts);
field.setAccessible(false);
} catch (Exception e) {
Log.e("TypefaceUtil", "Can not set custom fonts");
}
}
public static Typeface getTypeface(int fontType, Context context) {
// here you can load the Typeface from asset or use default ones
switch (fontType) {
case BOLD:
return Typeface.create(SANS_SERIF, Typeface.BOLD);
case ITALIC:
return Typeface.create(SANS_SERIF, Typeface.ITALIC);
case BOLD_ITALIC:
return Typeface.create(SANS_SERIF, Typeface.BOLD_ITALIC);
case LIGHT:
return Typeface.create(SANS_SERIF_LIGHT, Typeface.NORMAL);
case CONDENSED:
return Typeface.create(SANS_SERIF_CONDENSED, Typeface.NORMAL);
case THIN:
return Typeface.create(SANS_SERIF_MEDIUM, Typeface.NORMAL);
case MEDIUM:
return Typeface.create(SANS_SERIF_THIN, Typeface.NORMAL);
case REGULAR:
default:
return Typeface.create(SANS_SERIF, Typeface.NORMAL);
}
}
}
then whenever you want to override the fonts you can just call the method and give it a map of typefaces as follows:
Typeface regular = TypefaceUtil.getTypeface(REGULAR, context);
Typeface light = TypefaceUtil.getTypeface(REGULAR, context);
Typeface condensed = TypefaceUtil.getTypeface(CONDENSED, context);
Typeface thin = TypefaceUtil.getTypeface(THIN, context);
Typeface medium = TypefaceUtil.getTypeface(MEDIUM, context);
Map<String, Typeface> fonts = new HashMap<>();
fonts.put("sans-serif", regular);
fonts.put("sans-serif-light", light);
fonts.put("sans-serif-condensed", condensed);
fonts.put("sans-serif-thin", thin);
fonts.put("sans-serif-medium", medium);
TypefaceUtil.overrideFonts(fonts);
for full example check
This only works for Android SDK 21 and above for earlier versions check the full example
Just use this lib compile it in your grade file
complie'me.anwarshahriar:calligrapher:1.0'
and use it in the onCreate method in the main activity
Calligrapher calligrapher = new Calligrapher(this);
calligrapher.setFont(this, "yourCustomFontHere.ttf", true);
This is the most elegant super fast way to do that.
This is work for my project, source https://gist.github.com/artem-zinnatullin/7749076
Create fonts directory inside Asset Folder and then copy your custom font to fonts directory, example I am using trebuchet.ttf;
Create a class TypefaceUtil.java;
import android.content.Context;
import android.graphics.Typeface;
import android.util.Log;
import java.lang.reflect.Field;
public class TypefaceUtil {
public static void overrideFont(Context context, String defaultFontNameToOverride, String customFontFileNameInAssets) {
try {
final Typeface customFontTypeface = Typeface.createFromAsset(context.getAssets(), customFontFileNameInAssets);
final Field defaultFontTypefaceField = Typeface.class.getDeclaredField(defaultFontNameToOverride);
defaultFontTypefaceField.setAccessible(true);
defaultFontTypefaceField.set(null, customFontTypeface);
} catch (Exception e) {
}
}
}
Edit theme in styles.xml add below
<item name="android:typeface">serif</item>
Example in My styles.xml
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/colorAccent</item>
<item name="android:typeface">serif</item><!-- Add here -->
</style>
<style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="android:windowActionBarOverlay">true</item>
<item name="android:windowFullscreen">true</item>
</style>
</resources>
Finally, in Activity or Fragment onCreate call TypefaceUtil.java
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TypefaceUtil.overrideFont(getContext(), "SERIF", "fonts/trebuchet.ttf");
}
Android does not provide much in the way of support for applying fonts across the whole app (see this issue). You have 4 options to set the font for the entire app:
Option1: Apply reflection to change the system font
Option2: Create and subclass custom View classes for each View that needs a custom font
Option3: Implement a View Crawler which traverses the view
hierarchy for the current screen
Option4: Use a 3rd party library.
Details of these options can be found here.
I know this question is quite old, but I have found a nice solution.
Basically, you pass a container layout to this function, and it will apply the font to all supported views, and recursively cicle in child layouts:
public static void setFont(ViewGroup layout)
{
final int childcount = layout.getChildCount();
for (int i = 0; i < childcount; i++)
{
// Get the view
View v = layout.getChildAt(i);
// Apply the font to a possible TextView
try {
((TextView) v).setTypeface(MY_CUSTOM_FONT);
continue;
}
catch (Exception e) { }
// Apply the font to a possible EditText
try {
((TextView) v).setTypeface(MY_CUSTOM_FONT);
continue;
}
catch (Exception e) { }
// Recursively cicle into a possible child layout
try {
ViewGroup vg = (ViewGroup) v;
Utility.setFont(vg);
continue;
}
catch (Exception e) { }
}
}
to merely set typeface of app to normal, sans, serif or monospace(not to a custom font!), you can do this.
define a theme and set the android:typeface attribute to the typeface you want to use in styles.xml:
<resources>
<!-- custom normal activity theme -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/colorAccent</item>
<!-- other elements -->
<item name="android:typeface">monospace</item>
</style>
</resources>
apply the theme to the whole app in the AndroidManifest.xml file:
<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
<application
android:theme="#style/AppTheme" >
</application>
</manifest>
android reference
Try this library, its lightweight and easy to implement
https://github.com/sunnag7/FontStyler
<com.sunnag.fontstyler.FontStylerView
android:textStyle="bold"
android:text="#string/about_us"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="8dp"
app:fontName="Lato-Bold"
android:textSize="18sp"
android:id="#+id/textView64" />
This is how we do it:
private static void OverrideDefaultFont(string defaultFontNameToOverride, string customFontFileNameInAssets, AssetManager assets)
{
//Load custom Font from File
Typeface customFontTypeface = Typeface.CreateFromAsset(assets, customFontFileNameInAssets);
//Get Fontface.Default Field by reflection
Class typeFaceClass = Class.ForName("android.graphics.Typeface");
Field defaultFontTypefaceField = typeFaceClass.GetField(defaultFontNameToOverride);
defaultFontTypefaceField.Accessible = true;
defaultFontTypefaceField.Set(null, customFontTypeface);
}
The answer is no, you can't.
See Is it possible to set a custom font for entire of application?
for more information.
There are workarounds, but nothing in the lines of "one single line of code here and all my fonts will be this instead of that".
(I kind of thank Google -and Apple- for that). Custom fonts have a place, but making them easy to replace app wide, would have created an entire world of Comic Sans applications)
I have a field where the user can type a search query in the action bar of the application. This is declared in the action bar using a menu inflate in the Activity:
<menu
xmlns:android="http://schemas.android.com/apk/res/android"
>
<item
android:id="#+id/action_search"
android:showAsAction="ifRoom"
android:actionViewClass="android.widget.SearchView"
android:title="#string/search"
></item>
</menu>
I need to customize the appearance of the SearchView (for instance background and text color). So far I could not find a way to do it using XML (using styles or themes).
Is my only option to do it in the code when inflating the menu?
Edit #1: I have tried programmatically but I cannot get a simple way to set the text color. Plus when I do searchView.setBackgroundResource(...) The background is set on the global widget, (also when the SearchView is iconified).
Edit #2: Not much information on the Search Developer Reference either
Seibelj had an answer that is good if you want to change the icons. But you'll need to
do it for every API version. I was using ICS with ActionBarSherlock and it didn't do justice for me but it did push me in the correct direction.
Below I change the text color and hint color. I showed how you might go about changing the
icons too, though I have no interest in that for now (and you probably want to use the default icons anyways to be consistent)
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
// Set up the search menu
SearchView searchView = (SearchView)menu.findItem(R.id.action_search).getActionView();
traverseView(searchView, 0);
return true;
}
private void traverseView(View view, int index) {
if (view instanceof SearchView) {
SearchView v = (SearchView) view;
for(int i = 0; i < v.getChildCount(); i++) {
traverseView(v.getChildAt(i), i);
}
} else if (view instanceof LinearLayout) {
LinearLayout ll = (LinearLayout) view;
for(int i = 0; i < ll.getChildCount(); i++) {
traverseView(ll.getChildAt(i), i);
}
} else if (view instanceof EditText) {
((EditText) view).setTextColor(Color.WHITE);
((EditText) view).setHintTextColor(R.color.blue_trans);
} else if (view instanceof TextView) {
((TextView) view).setTextColor(Color.WHITE);
} else if (view instanceof ImageView) {
// TODO dissect images and replace with custom images
} else {
Log.v("View Scout", "Undefined view type here...");
}
}
adding my take on things which is probably a little more efficient and safe across different android versions.
you can actually get a numeric ID value from a string ID name. using android's hierarchyviewer tool, you can actually find the string IDs of the things you are interested in, and then just use findViewById(...) to look them up.
the code below sets the hint and text color for the edit field itself. you could apply the same pattern for other aspects that you wish to style.
private static synchronized int getSearchSrcTextId(View view) {
if (searchSrcTextId == -1) {
searchSrcTextId = getId(view, "android:id/search_src_text");
}
return searchSrcTextId;
}
private static int getId(View view, String name) {
return view.getContext().getResources().getIdentifier(name, null, null);
}
#TargetApi(11)
private void style(View view) {
ImageView iv;
AutoCompleteTextView actv = (AutoCompleteTextView) view.findViewById(getSearchSrcTextId(view));
if (actv != null) {
actv.setHint(getDecoratedHint(actv,
searchView.getContext().getResources().getString(R.string.titleApplicationSearchHint),
R.drawable.ic_ab_search));
actv.setTextColor(view.getContext().getResources().getColor(R.color.ab_text));
actv.setHintTextColor(view.getContext().getResources().getColor(R.color.hint_text));
}
}
You can use the attribute android:actionLayout instead which lets you specify a layout to be inflated. Just have a layout with your SearchView and you won't have to modify anything really.
As to changing text style on the SearchView that is probably not possible as the SearchView is a ViewGroup. You should probably try changing text color via themes instead.
In case anyone wants to modify the views directly, here is how you can change the colors/fonts/images and customize the search box to your pleasure. It is wrapped in a try/catch in case there are differences between versions or distributions, so it won't crash the app if this fails.
// SearchView structure as we currently understand it:
// 0 => linearlayout
// 0 => textview (not sure what this does)
// 1 => image view (the search icon before it's pressed)
// 2 => linearlayout
// 0 => linearlayout
// 0 => ImageView (Search icon on the left of the search box)
// 1 => SearchView$SearchAutoComplete (Object that controls the text, subclass of TextView)
// 2 => ImageView (Cancel icon to the right of the text entry)
// 1 => linearlayout
// 0 => ImageView ('Go' icon to the right of cancel)
// 1 => ImageView (not sure what this does)
try {
LinearLayout ll = (LinearLayout) searchView.getChildAt(0);
LinearLayout ll2 = (LinearLayout) ll.getChildAt(2);
LinearLayout ll3 = (LinearLayout) ll2.getChildAt(0);
LinearLayout ll4 = (LinearLayout) ll2.getChildAt(1);
TextView search_text = (TextView) ll3.getChildAt(1);
search_text.setTextColor(R.color.search_text);
ImageView cancel_icon = (ImageView)ll3.getChildAt(2);
ImageView accept_icon = (ImageView)ll4.getChildAt(0);
cancel_icon.setBackgroundDrawable(d);
accept_icon.setBackgroundDrawable(d);
} catch (Throwable e) {
Log.e("SearchBoxConstructor", "Unable to set the custom look of the search box");
}
This example shows changing the text color and the background colors of the cancel/accept images. searchView is a SearchView object already instantiated with it's background color:
Drawable d = getResources().getDrawable(R.drawable.search_widget_background);
searchView.setBackgroundDrawable(d);
Here is the drawable code:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<solid android:color="#color/white" />
</shape>
Obviously, this is hacky, but it will work for now.
From ICS this is doable using themes and styles. I'm using ActionBarSherlock which makes it applicable also for HC and below.
Add a style to define "android:textColorHint":
<style name="Theme.MyHolo.widget" parent="#style/Theme.Holo">
<item name="android:textColorHint">#color/text_hint_corp_dark</item>
</style>
Apply this as "actionBarWidgetTheme" to your theme:
<style name="Theme.MyApp" parent="#style/Theme.Holo.Light.DarkActionBar">
...
<item name="android:actionBarWidgetTheme">#style/Theme.MyHolo.widget</item>
</style>
Presto! Make sure that you use getSupportActionBar().getThemedContext() (or getSupportActionBar() for ActionBarSherlock) if any widgets are initiated where you might have other themes in effect.
How do you inflate the menu xml in your Activity? if you inflate the menu by using getMenuInflator() in your Activity, then the menu and also the searchView get the themed context, that have attached to the activity.
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater.inflate(R.menu.search_action_menu, menu);
}
if you check the source code of Activity.getMenuInflator() at API-15, you can see the themed context codes. Here it is.
*/
public MenuInflater getMenuInflater() {
// Make sure that action views can get an appropriate theme.
if (mMenuInflater == null) {
initActionBar();
if (mActionBar != null) {
mMenuInflater = new MenuInflater(mActionBar.getThemedContext());
} else {
mMenuInflater = new MenuInflater(this);
}
}
return mMenuInflater;
}