I have an usual button and a theme which is applied to android:theme in AndroidManifest file:
<Button
android:id="#+id/supperButton"
android:layout_width="match_parent"
android:layout_height="120dp" />
<style name="AppTheme" parent="Theme.AppCompat">
</style>
When i inflate this button and stop the app with debugger to see what class has been created i see the following:
As you can see, instead of an usual button class, AppComapatButton has been created. When i change theme to as follows:
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
</style>
MaterialButton is created, instead of an usual button class or AppComapatButton:
Question: as i can gather, themes can define what exactly type of a widget is used. So what exactly does define it? Maybe there is some attribute in a theme that does it ?
It happens if your Activity extends AppCompatActivity.
The AppCompatActivity calls the setFactory2 method using a custom implementation of LayoutInflater.
This implementation is done by the AppCompatViewInflater
which checks the names of the views in the layout and automatically "substitutes" all usages of core Android widgets inflated from layout files by the AppCompat extensions of those widgets.
You can check in the source code:
#Nullable
public final View createView(/**...*/) {
//...
switch (name) {
case "Button":
view = createButton(context, attrs);
verifyNotNull(view, name);
break;
//...
}
#NonNull
protected AppCompatButton createButton(Context context, AttributeSet attrs) {
return new AppCompatButton(context, attrs);
}
In the MaterialComponents theme is defined another implemetantion, the MaterialComponentsViewInflater.
For example you can check in the source code:
#Override
protected AppCompatButton createButton(#NonNull Context context, #NonNull AttributeSet attrs) {
return new MaterialButton(context, attrs);
}
You can use an own inflater adding in the app theme the viewInflaterClass attribute:
<style name="Theme.App" parent="Theme.MaterialComponents.*">
<item name="viewInflaterClass">com.google.android.material.theme.MaterialComponentsViewInflater</item>
</style>
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);
}
I've tried to change theme of the MediaRouteActionProvider connection dialog. I using in my application a Light theme with Dark Actionbar, so the dialog have dark gray content, but the background is dark..
When the app is connected to a device, the other dialogs are ok, they have white background with the correct theme. (For exmaple in VideoMediaRouteControllerDialog and on the disconnect dialog.)
Have you any idea, how can I change the connection dialog's theme?
Thank you very much!
//Screenshot 1: Connection dialog (with the theme issue)
//Screenshot 2: Controller dialog (with the right, needed theme)
Unfortunately that dialog doesn't follow the standard theme (Dialogs in Android are all pretty unfriendly in general but that one is among the hardest to work with). Since that dialog is provided by media router, you can only provide a customized theme if you replace that completely with your own dialog.
You can try subclassing MediaRouteDialogFactory and override onCreateChooserDialogFragment() method and pass your implementation to the ActionProvide:
mediaRouteActionProvider.setDialogFactory(yourDialogFactoryImlementation)
You can take a look at the CCL where I do a similar thing not for the chooser dialog but for the controller.
Right now theming these Dialogs have issue - wrong theme applied to Dialog
You can override themes used in MediaRouterThemeHelper
<style name="Theme.MediaRouter.Light.DarkControlPanel">
<item name="mediaRoutePlayDrawable">#drawable/mr_ic_play_dark</item>
<item name="mediaRoutePauseDrawable">#drawable/mr_ic_pause_dark</item>
<item name="mediaRouteCastDrawable">#drawable/mr_ic_cast_dark</item>
<item name="mediaRouteAudioTrackDrawable">#drawable/ic_audiotrack</item>
<item name="mediaRouteControllerPrimaryTextStyle">#style/Widget.MediaRouter.ControllerText.Primary.Dark</item>
<item name="mediaRouteControllerSecondaryTextStyle">#style/Widget.MediaRouter.ControllerText.Secondary.Dark</item>
</style>
<style name="Theme.MediaRouter.LightControlPanel">
<item name="mediaRoutePlayDrawable">#drawable/mr_ic_play_light</item>
<item name="mediaRoutePauseDrawable">#drawable/mr_ic_pause_light</item>
<item name="mediaRouteCastDrawable">#drawable/mr_ic_cast_light</item>
<item name="mediaRouteAudioTrackDrawable">#drawable/mr_ic_audiotrack_light</item>
<item name="mediaRouteControllerPrimaryTextStyle">#style/Widget.MediaRouter.ControllerText.Primary.Light</item>
<item name="mediaRouteControllerSecondaryTextStyle">#style/Widget.MediaRouter.ControllerText.Secondary.Light</item>
</style>
What I did was pulling the mediarouter appcompat library source from GitHub, then I fixing the theming and rebuilding the whole thing into my own custom mediarouter library.
What you're looking for in the code is MediaRouteChooserDialog, and even there, the constructor that only takes a Context as a parameter, as that's the one being called by onCreateChooserDialog() in MediaRouteChooserDialogFragment.
I was lazy so I simply put android.R.style.Theme_Holo_Light_Dialog instead of the 0 in the constructor, and it worked just fine. But of course you can always look for a more sophisticated solution.
I made it work similar as #Naddaf described it. You need to extend MediaRouteDialogFactory (you can set this to the MediaRouteActionProvider or MediaRouteButton with setDialogFactory() ) and override the method:
#Override
public MediaRouteChooserDialogFragment onCreateChooserDialogFragment(){
return new CustomMediaRouteChooserDialogFragment();
}
Then in your CustomMediaRouteChooserDialogFragment override:
#Override
public CustomMediaRouteChooserDialog onCreateChooserDialog(Context context, Bundle savedInstanceState)
{
return new CustomMediaRouteChooserDialog(context);
}
And in the CustomMediaRouteChooserDialog create a constructor, where you set your holo light theme.
public CustomMediaRouteChooserDialog(Context context)
{
super(context, android.R.style.Theme_Holo_Light_Dialog);
}
Hope this helps!
Based on the other answers, this worked for me:
set a custom action provider in the menu item
<item
android:id="#+id/media_route_menu_item"
android:title="#string/cast_menu_title"
app:actionProviderClass="MediaRouteActionProviderThemeLight"
app:showAsAction="always"/>
this is the custom action provider using a light theme
public class MediaRouteActionProviderThemeLight extends MediaRouteActionProvider {
private static final int THEME_DIALOG = android.support.v7.mediarouter.R.style.Theme_MediaRouter_Light;
/**
* Creates the action provider.
*
* #param context The context.
*/
public MediaRouteActionProviderThemeLight(Context context) {
super(context);
setDialogFactory(new MediaRouteDialogFactoryThemeLight());
}
private static class MediaRouteDialogFactoryThemeLight extends MediaRouteDialogFactory {
#NonNull
#Override
public MediaRouteChooserDialogFragment onCreateChooserDialogFragment() {
return new MediaRouteChooserDialogFragmentThemeLight();
}
#NonNull
#Override
public MediaRouteControllerDialogFragment onCreateControllerDialogFragment() {
return new MediaRouteControllerDialogFragmentThemeLight();
}
}
public static class MediaRouteChooserDialogFragmentThemeLight extends MediaRouteChooserDialogFragment {
#Override
public MediaRouteChooserDialog onCreateChooserDialog(Context context, Bundle savedInstanceState) {
return new MediaRouteChooserDialog(context, THEME_DIALOG);
}
}
public static class MediaRouteControllerDialogFragmentThemeLight extends MediaRouteControllerDialogFragment {
#Override
public MediaRouteControllerDialog onCreateControllerDialog(Context context, Bundle savedInstanceState) {
return new MediaRouteControllerDialog(context, THEME_DIALOG);
}
}
}
take into account the dialog with play/pause buttons and volume control use the material colors from your main theme, colorPrimary as background and textColorPrimary for the title/subtitle. In case your app use dark theme you should overwrite the background using the theme below, and change the THEME_DIALOG constant in the class MediaRouteActionProviderThemeLight:
<style name="CastAppThemeMediaRouter" parent="Theme.MediaRouter.Light">
<item name="colorPrimaryDark">#color/primary_dark_material_light</item>
<item name="colorPrimary">#color/primary_material_light</item>
<item name="colorAccent">#color/accent_material_light</item>
</style>
To use a light theme with dark controls use the following theme. Be sure to set as primaryColor a dark color, the volume bar is set to light/dark automatically based in the primaryColor.
<style name="CastThemeMediaRouter" parent="Theme.MediaRouter.Light.DarkControlPanel">
<item name="colorPrimary">#color/black</item>
</style>
i'm using a ShareActionProvider, but i want to custom the icon (i want to change the color, because currently, it's white).
I'm using this code :
mShareActionProvider = (ShareActionProvider) item.getActionProvider();
Intent myIntent = new Intent(Intent.ACTION_SEND);
myIntent.setType("text/plain");
myIntent.putExtra(Intent.EXTRA_TEXT, str_share);
mShareActionProvider.setShareIntent(myIntent);
The XML :
<item
android:id="#+id/menu_item_share"
android:showAsAction="ifRoom"
android:title="#string/titlePartager"
android:actionProviderClass="android.widget.ShareActionProvider"
android:icon="#drawable/ic_share"/>
How can i change the icon (or color) ?
thx,
Edit / Short answer: if using AppCompat's ShareActionProvider, just provide a new actionModeShareDrawable in your theme definition.
<style name="MyTheme" parent="Theme.AppCompat">
<item name="actionModeShareDrawable">#drawable/my_share_drawable</item>
</style>
If not using AppCompat, then this resource is defined for Lollipor or newer, but not for previous versions.
Below is answer for the native ShareActionProvider (which was the original scope of this question).
To change this image, you should change the value of actionModeShareDrawable for your app's theme. Take a look at the ShareActionProvider's onCreateActionView() method:
public View onCreateActionView() {
// Create the view and set its data model.
...
// Lookup and set the expand action icon.
TypedValue outTypedValue = new TypedValue();
mContext.getTheme().resolveAttribute(R.attr.actionModeShareDrawable, outTypedValue, true);
Drawable drawable = mContext.getResources().getDrawable(outTypedValue.resourceId);
...
Unfortunately this attribute is not public in the Android framework (though it is if using compatibility libraries, such as AppCompat or ActionBarSherlock). In that case, it's just a matter of overriding that value for the theme.
If you are using neither of these libraries, the only solution (that I know of) is to create a subclass of ShareActionProvider and reimplement the onCreateActionView() method. You can then use whatever drawable you want instead.
EDIT However this is further complicated by the fact that the implementation of onCreateActionView() uses other classes that are not public either. To avoid duplicating a lot of code, you can just change the icon via reflection, like this:
public class MyShareActionProvider extends ShareActionProvider
{
private final Context mContext;
public MyShareActionProvider(Context context)
{
super(context);
mContext = context;
}
#Override
public View onCreateActionView()
{
View view = super.onCreateActionView();
if (view != null)
{
try
{
Drawable icon = ... // the drawable you want (you can use mContext to get it from resources)
Method method = view.getClass().getMethod("setExpandActivityOverflowButtonDrawable", Drawable.class);
method.invoke(view, icon);
}
catch (Exception e)
{
Log.e("MyShareActionProvider", "onCreateActionView", e);
}
}
return view;
}
}
As with any solutions that involve reflection, this may be brittle if the internal implementation of ShareActionProvider changes in the future.
To change the icon for the ShareActionProvider you need to extend the AppCompat theme and set your custom icon to "actionModeShareDrawable":
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="actionModeShareDrawable">#drawable/ic_share</item>
</style>
You can change background color by defining custom style, as:
<resources>
<style name="MyTheme" parent="#android:style/Theme.Holo.Light">
<item name="android:actionBarStyle">#style/MyActionBar</item>
</style>
<style name="MyActionBar" parent="#android:style/Widget.Holo.Light.ActionBar">
<item name="android:background">ANY_HEX_COLOR_CODE</item>
</style>
</resources>
Now you need to set "MyTheme" as theme for application / activity.
I have an application that uses a preference activity to set some user settings. I been trying to figure this out all day. I am trying to theme the alert dialog when an user presses an Edit Text Preference object. A dialog opens up and the user can set the shared preference. The dialog pops up:
I want the text green. I want the divider green. The line and cursor green.
This is what I have so far.
<style name="CustomDialogTheme" parent="#android:style/Theme.Dialog">
<item name="android:background">#color/text_green</item>
<item name="android:textColor">#color/text_green</item>
</style>
Can someone point me in the right direction or maybe share some code. I am at lost. I've been surfing the net to find something most of the day. Thanks in advance.
If you don't want to create a custom layout or use a third party library, you can subclass EditTextPreference, then access each View you want to edit by using Resources.getIdentifier then using Window.findViewById. Here's a quick example.
public class CustomDialogPreference extends EditTextPreference {
public CustomDialogPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public CustomDialogPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
/**
* {#inheritDoc}
*/
#Override
protected void showDialog(Bundle state) {
super.showDialog(state);
final Resources res = getContext().getResources();
final Window window = getDialog().getWindow();
final int green = res.getColor(android.R.color.holo_green_dark);
// Title
final int titleId = res.getIdentifier("alertTitle", "id", "android");
final View title = window.findViewById(titleId);
if (title != null) {
((TextView) title).setTextColor(green);
}
// Title divider
final int titleDividerId = res.getIdentifier("titleDivider", "id", "android");
final View titleDivider = window.findViewById(titleDividerId);
if (titleDivider != null) {
titleDivider.setBackgroundColor(green);
}
// EditText
final View editText = window.findViewById(android.R.id.edit);
if (editText != null) {
editText.setBackground(res.getDrawable(R.drawable.apptheme_edit_text_holo_light));
}
}
}
Implementation
Replace <EditTextPreference.../> with <path_to_CustomDialogPreference.../> in your xml.
Note
I used Android Holo Colors to create the background for the EditText.
You can build your custom layout for your own dialog theme using your own customized components or you can use external libs, for example android-styled-dialogs
So in this case use can customize dialogs as you want:
<style name="DialogStyleLight.Custom">
<!-- anything can be left out: -->
<item name="titleTextColor">#color/dialog_title_text</item>
<item name="titleSeparatorColor">#color/dialog_title_separator</item>
<item name="messageTextColor">#color/dialog_message_text</item>
<item name="buttonTextColor">#color/dialog_button_text</item>
<item name="buttonSeparatorColor">#color/dialog_button_separator</item>
<item name="buttonBackgroundColorNormal">#color/dialog_button_normal</item>
<item name="buttonBackgroundColorPressed">#color/dialog_button_pressed</item>
<item name="buttonBackgroundColorFocused">#color/dialog_button_focused</item>
<item name="dialogBackground">#drawable/dialog_background</item>
</style>
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)