Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't change Toolbar's font from default. #181

Closed
Jeevuz opened this issue Jun 8, 2015 · 71 comments
Closed

Can't change Toolbar's font from default. #181

Jeevuz opened this issue Jun 8, 2015 · 71 comments

Comments

@Jeevuz
Copy link

Jeevuz commented Jun 8, 2015

Hi! I have a problem with changing the Toolbar's title font.

It successfully gets the default font set in Application, but no way to configure it separately.
I tried all solutions, fontPath through textAppearance using Toolbar's setTitleTextAppearance() (and its analog from xml), fontPath in style and use it as toolbar's style, changing the toolbar theme.
Nothing helps...
The same is with new design support library NavigationView. I have no idea how to change the font from default one for items.

Do you have any ideas why it is so?

@Jeevuz
Copy link
Author

Jeevuz commented Jun 8, 2015

I noticed that if I commented the default font in the initialization code,

CalligraphyConfig.initDefault(new CalligraphyConfig.Builder()
//        .setDefaultFontPath(getString(R.string.font_main))
        .setFontAttrId(R.attr.fontPath)
        .build());

then textAppearance starts to work:

<android.support.v7.widget.Toolbar
    android:id="@+id/toolbar"
    android:layout_height="?attr/actionBarSize"
    app:layout_gravity="fill_horizontal"
    android:background="?attr/colorPrimary"
    app:theme="@style/ThemeOverlay.AppCompat.ActionBar"
    app:titleTextAppearance="@style/ToolbarTitleTextAppearance"/>

where appearance is

<style name="ToolbarTitleTextAppearance" parent="TextAppearance.AppCompat.Widget.ActionBar.Title">
    <item name="android:textSize">18sp</item>
    <item name="fontPath">@string/font_secondary_bold</item>
</style>

So It seems possible to set fontPath in the app theme to get the Toolbar title works. But I don't really understand why it's so. And for the NavigationView I still have no solution to set font different from default (set in Application or theme).

Could you please help me to understand and solve this?

@chrisjenx
Copy link
Owner

Hi @Jeevuz

I've never tried setting the fontPath on the Toolbar theme. (It should just work as the resolved theme should be picked up, I am yet to test tho).
Worth noting (I think the linter complains), you should be using android:theme not app:theme, the layout inflater should pick up the theme correctly across versions.

texAppearance won't work. The Toolbar and Actionbar create the text views programatically, so we have really no idea what style is applied to them, we have to work it out manually.

The default font should work.
The theme font should also work, but that depends if the Themed context is passed through to Calligraphy.
Title and SubTitle Apperances need to be set on the Theme not the Toolbar. (as you used to do with the ActionBar).

If you want the really easy work around?

<Toolbar>
 <TextView fontPath="fonts/myFont.ttf" />
</Toolbar>

@Jeevuz
Copy link
Author

Jeevuz commented Jun 9, 2015

Hi Chris,
thanks for quick response!

You know what? Your "worth noting" has solved the problem! :)

You 100% right, I forgot that starting from support-v22.1 they deprecated the app:theme in favor of android:theme. So when I fixed this in my Toolbar

<android.support.v7.widget.Toolbar
    android:id="@+id/toolbar"
    android:layout_height="?attr/actionBarSize"
    app:layout_gravity="fill_horizontal"
    android:background="?attr/colorPrimary"
    android:theme="@style/ToolbarTheme"/>

and added the fontPath to the theme
in styles.xml:

<style name="ToolbarTheme" parent="@style/ThemeOverlay.AppCompat.ActionBar">
    <item name="fontPath">@string/font_secondary_light</item>
</style>

toolbar's title font changed.

And I changed the font for items in the android.support.design.widget.NavigationView in the same way!

So, thanks again for your responsiveness!

@Jeevuz Jeevuz closed this as completed Jun 9, 2015
@LeMimit
Copy link

LeMimit commented Jun 11, 2015

Hello Jeevuz,

You said in your last comment that you've succeeded to change the font for items in the android.support.design.widget.NavigationView.

I can't figure out how I can do that. Can you help me ?

Thanks !

@Jeevuz
Copy link
Author

Jeevuz commented Jun 11, 2015

Hi @LeMimit!

Yes, I used the same way as with Toolbar. I set the android:theme to the NavigationView. The theme is looks like

    <style name="NavigationViewThemeOverlay" parent="MyTheme">
        <item name="fontPath">@string/font_secondary_bold</item>
    </style>

Hope it will help you!

@marbat87
Copy link

marbat87 commented Jul 7, 2015

I'm sorry to write in a closed issue, but this really doesn't have any effect for me..
Any idea for a workaround for NavigationView?

Thanks in advance

@Jeevuz
Copy link
Author

Jeevuz commented Jul 7, 2015

Hi @marbat87!
Did you try the workaround I wrote above?
If yes, please show the code of used style and NavigationView. I'll try to help you.

@chrisjenx
Copy link
Owner

What is the navigation view? The new drawer?

On Tue, 7 Jul 2015 10:33 marbat87 notifications@github.com wrote:

I'm sorry to write in a closed issue, but this really doesn't have any
effect for me..
Any idea for a workaround for NavigationView?

Thanks in advance


Reply to this email directly or view it on GitHub
#181 (comment)
.

@chrisjenx
Copy link
Owner

This is because all the new design views don't inflate their children.
Chris Banes is aware, they are just taking their sweet time fixing stuff.

On Tue, 7 Jul 2015 10:49 Christopher Jenkins chris.mark.jenkins@gmail.com
wrote:

What is the navigation view? The new drawer?

On Tue, 7 Jul 2015 10:33 marbat87 notifications@github.com wrote:

I'm sorry to write in a closed issue, but this really doesn't have any
effect for me..
Any idea for a workaround for NavigationView?

Thanks in advance


Reply to this email directly or view it on GitHub
#181 (comment)
.

@Jeevuz
Copy link
Author

Jeevuz commented Jul 7, 2015

Yes, helper view from design support library. Helps to inflate the drawer from menu xml file.
Great that they aware ;)

@marbat87
Copy link

marbat87 commented Jul 7, 2015

This is my code.
But it keeps using the default font...

<android.support.design.widget.NavigationView
        android:theme="@style/Widget.Design.NavigationView.Risuscito"
        android:id="@+id/navigation_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        risuscito:headerLayout="@layout/navdrawer_header"
        risuscito:menu="@menu/drawer_menu"/>
<style name="Widget.Design.NavigationView.Risuscito">
        <item name="android:background">@color/navdrawer_background</item>
        <item name="colorControlHighlight">#12000000</item>
        <item name="fontPath">fonts/Roboto-Medium.ttf</item>
    </style>

@marbat87
Copy link

marbat87 commented Jul 7, 2015

I think I solved!

I found in support library the item "design_navigation_item.xml"
I imported it into my prohject and added the line to set the font, the result is the following:

<android.support.design.internal.NavigationMenuItemView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="?attr/listPreferredItemHeightSmall"
    android:paddingLeft="?attr/listPreferredItemPaddingLeft"
    android:paddingRight="?attr/listPreferredItemPaddingRight"
    android:drawablePadding="@dimen/navigation_icon_padding"
    android:gravity="center_vertical|start"
    fontPath="fonts/Roboto-Medium.ttf"
    android:maxLines="1"
    android:textAppearance="?attr/textAppearanceListItem"/>

This works! I think because it overrides the xml included in design support library.

Regards,
Marcello

@Jeevuz
Copy link
Author

Jeevuz commented Jul 7, 2015

I think, your solution works because you set fontPath right on the child view. It's ok, but in case you want to try to workaround without it, try to set your app theme as parent of your style.
<style name="Widget.Design.NavigationView.Risuscito" parent="<your app theme>" >.
That's how it worked in my case.

@Jeevuz Jeevuz reopened this Jul 7, 2015
@Jeevuz Jeevuz closed this as completed Jul 7, 2015
@Jeevuz
Copy link
Author

Jeevuz commented Jul 7, 2015

Ups, incidental reopen... sorry :)

@osrl
Copy link

osrl commented Jul 30, 2015

@chrisjenx you said the default should work; I changed my default font, everything except the Toolbar title changed. I also tried @Jeevuz's approach with themes. But that didn't work either.

In the application's onCreate

    CalligraphyConfig.initDefault(new CalligraphyConfig.Builder()
                    .setDefaultFontPath("fonts/UniSans-Regular.ttf")
                    .setFontAttrId(R.attr.fontPath)
                    .build()

Or with the theme option

<style name="ToolbarTheme" parent="@style/Widget.AppCompat.Toolbar">
    <item name="fontPath">fonts/UniSans-Regular.ttf</item>
</style> 

<android.support.v7.widget.Toolbar
    android:id="@+id/toolbar"
    android:theme="@style/ToolbarTheme"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="?attr/colorPrimary"
    android:minHeight="?attr/actionBarSize"/>

@chrisjenx
Copy link
Owner

@osrl

<style name="ToolbarTheme" parent="@style/Widget.AppCompat.Toolbar">
    <item name="fontPath">fonts/UniSans-Regular.ttf</item>
</style>

Parent THEME not style. E.g.

<style name="ToolbarTheme" parent="@style/ThemeOverlay.AppCompat.ActionBar">
    <item name="fontPath">@string/font_secondary_light</item>
</style>

@osrl
Copy link

osrl commented Jul 31, 2015

I tried that too. You said setting default font should work by itself am I wrong?

@chrisjenx
Copy link
Owner

If the layout inflater isn't being overwritten by appcompat then yes. Drop
in a full example or fork and update the sample app to show me. :)

On Fri, 31 Jul 2015 12:49 Osman Saral notifications@github.com wrote:

I tried that too. You said setting default font should work by itself am I
wrong?


Reply to this email directly or view it on GitHub
#181 (comment)
.

@Jeevuz
Copy link
Author

Jeevuz commented Jul 31, 2015

@osrl, maybe the problem is that you used the wrong theme for the Toolbar, same as in style you posted. I think default font worked for me by default. My toolbar xml was like this:

<android.support.v7.widget.Toolbar
    android:id="@+id/toolbar"
    android:layout_height="?attr/actionBarSize"
    android:background="?attr/colorPrimary"
    android:theme="@style/ThemeOverlay.AppCompat.ActionBar"/>

@osrl
Copy link

osrl commented Jul 31, 2015

I use a navigation drawer and change the toolbar title within a main activity (I switch fragments). Different activites have the correct font. But Main activity doesn't.
public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

        CalligraphyConfig.initDefault(new CalligraphyConfig.Builder()
                        .setDefaultFontPath("fonts/UniSans-Regular.ttf")
                        .setFontAttrId(R.attr.fontPath)
                        .build()
        );
    }

<android.support.v7.widget.Toolbar
    android:id="@+id/toolbar"
    style="@style/Widget.AppCompat.Toolbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="?attr/colorPrimary"
    android:minHeight="?attr/actionBarSize"/>

This is how I change the title. Maybe this is where it goes wrong.

            toolbar.setLogo(null);
            getSupportActionBar().setDisplayShowTitleEnabled(true);
            getSupportActionBar().setTitle(mTitle);

I set a logo on toolbar somewhere in the app. When I comment it out, things go well. How do I tell if the layout inflater is being overwritten by appcompat?

@chrisjenx
Copy link
Owner

@osrl Ahh right I know whats going on. The TextView is never created so the Spannable is never applied to the TextView when the Toolbar is created.

The (really bad) work around for now is to init the Toolbar with empty text:

toolbar.setTitle(" ");
toolbar.setSubtitle(" ");

If you do this after the toolbar is created in onCreate() this will allow the Spannable to be set on the TextViews then changing the text afterwards will work.

@chrisjenx
Copy link
Owner

Actually more precisely this:

toolbar.setTitle(" ");
toolbar.setSubtitle("  ");

There is a fix in the works, I have re-worked the Toolbar listener to be a bit more clever.

@osrl
Copy link

osrl commented Aug 3, 2015

Yes @chrisjenx that worked. Thank you. Please let us know when the fix is released, so we can remove the (really bad) workaround :)

@chrisjenx
Copy link
Owner

@osrl I updated the 2.1.1-SNAPSHOT if you are able to test?

@osrl
Copy link

osrl commented Aug 3, 2015

Did you mean 2.1.1-SNAPSHOT ?

@chrisjenx
Copy link
Owner

Yes.

@osrl
Copy link

osrl commented Aug 3, 2015

Sorry couldn't download the snapshot. Do I need to add a repository? Did I miss something?
compile 'uk.co.chrisjenx:calligraphy:2.1.1-SNAPSHOT'

@chrisjenx
Copy link
Owner

In your sample your not using the snapshot. Was that intentional?

@pickeyboy
Copy link

It is same behaviour with or without SNAPSHOT, I tried both.

@chrisjenx
Copy link
Owner

OK thanks.

On Wed, 16 Mar 2016, 10:50 pickeyboy, notifications@github.com wrote:

It is same behaviour with or without SNAPSHOT, I have tried both.


You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub
#181 (comment)

@pickeyboy
Copy link

I found something .. in my main activity I have set for No default action bar by following code in Manifest file.

However settings uses the default action bar provided by system. The Calligraphy font is not applied to default actionbar provided in SettingsActivity but it works in MainActivity because main activity's layout xml has got toolbar widget defined and set.

Do you think, is that the same reason?

@chrisjenx
Copy link
Owner

Yeah, I don't support the action bar, only toolbars. It's too much to
maintain otherwise.

On Thu, 17 Mar 2016, 06:40 pickeyboy, notifications@github.com wrote:

I found something .. in my main activity I have set for No default action
bar by following code in Manifest file.
android:name=".activity.MainActivity"
android:theme="@style/AppTheme.NoActionBar" />

However settings uses the action bar provided by system. The Calligraphy
font is not applied to default actionbar provided in SettingsActivity,
however, it works in MainActivity because I am defining in layout xml and
explicitly setting it.

Do you think, is that the same reason?


You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub
#181 (comment)

@shankarimoorthy
Copy link

I have one doubt...i used five fontpath for edittext and textview on xml files...but it wont changed,how to give more than one font path in " CalligraphyConfig"....i used this code but i cant get the ans

@OverRide
public void onCreate() {
super.onCreate();
CalligraphyConfig.initDefault(new CalligraphyConfig.Builder()
//.setDefaultFontPath("fonts/HelvLight-regular.ttf")
.setDefaultFontPath("fonts/HelveticaNeue-Light.otf")
//.setDefaultFontPath("fonts/HelveticaNeue-Medium.otf")
//.setDefaultFontPath("fonts/HelveticaNeueBold.ttf")
//.setDefaultFontPath("fonts/MyriadPro-Regular.otf")
.setFontAttrId(R.attr.fontPath)
.build()
);

xml file:

    <Button
        android:id="@+id/button_login"
        fontPath="fonts/HelveticaNeue-Medium.otf"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="25dp"
        android:layout_marginRight="25dp"
        android:layout_marginTop="25dp"
        android:background="@color/app_theme_color"
        android:text="LOGIN"
        android:textColor="@color/white" />

    <TextView
        android:id="@+id/txt_forgot_password"
        fontPath="fonts/HelveticaNeue-Light.otf"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginBottom="10dp"
        android:layout_marginTop="10dp"
        android:gravity="center"
        android:text="Forgot Password?"
        android:textColor="@color/app_theme_text_color"
        android:textSize="14sp" />
}

@chrisjenx
Copy link
Owner

Try using ttf, otfs are notoriously buggy.

You also can't set more than one default typeface.

On Thu, 17 Mar 2016, 08:43 shankarimoorthy, notifications@github.com
wrote:

I have one doubt...i used five fontpath for edittext and textview on xml
files...but it wont changed,how to give more than one font path in "
CalligraphyConfig"....i used this code but i cant get the ans

@OverRide https://github.com/Override
public void onCreate() {
super.onCreate();
CalligraphyConfig.initDefault(new CalligraphyConfig.Builder()
//.setDefaultFontPath("fonts/HelvLight-regular.ttf")
.setDefaultFontPath("fonts/HelveticaNeue-Light.otf")
//.setDefaultFontPath("fonts/HelveticaNeue-Medium.otf")
//.setDefaultFontPath("fonts/HelveticaNeueBold.ttf")
//.setDefaultFontPath("fonts/MyriadPro-Regular.otf")
.setFontAttrId(R.attr.fontPath)
.build()
);

xml file:

android:id="@+id/editTextPassword"
fontPath="fonts/HelveticaNeue-Light.otf"
android:layout_width="fill_parent"
android:layout_height="40dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="8dp"
android:background="@color/white"
android:hint="@string/hint_password_login"
android:inputType="textPassword"
android:padding="8dp"
android:textColor="@color/app_hint_text_color"
android:textColorHint="@color/app_hint_text_color"
android:textCursorDrawable="@drawable/cursor_drawable" />

<Button
    android:id="@+id/button_login"
    fontPath="fonts/HelveticaNeue-Medium.otf"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_marginLeft="25dp"
    android:layout_marginRight="25dp"
    android:layout_marginTop="25dp"
    android:background="@color/app_theme_color"
    android:text="LOGIN"
    android:textColor="@color/white" />

<TextView
    android:id="@+id/txt_forgot_password"
    fontPath="fonts/HelveticaNeue-Light.otf"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:layout_marginBottom="10dp"
    android:layout_marginTop="10dp"
    android:gravity="center"
    android:text="Forgot Password?"
    android:textColor="@color/app_theme_text_color"
    android:textSize="14sp" />

}


You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub
#181 (comment)

@shankarimoorthy
Copy link

Thankyou for your reply...i will try to slove

@chrisjenx
Copy link
Owner

Also if you're using App Compat, you'll need to use the 2.1.1 Snapshot.

@shankarimoorthy
Copy link

sir i have one doubt..i wish to use more than one ttf files inside the xml page..then how can i use Calligraphy

@chrisjenx
Copy link
Owner

@shankarimoorthy you can only define one font in the CalligraphyConfig

You can use fontPath="fonts/HelveticaNeue-Light.otf" per TextView etc..

See the Sample Project, that uses multiple Typefaces.

@consp1racy
Copy link

Alright, I really didn't want to change font in my whole toolbar, I just wanted Roboto Medium title on Android 4. Calligraphy couldn't apply app:titleTextAppearance for me so I subclassed Toolbar and read app:fontPath manually.

XpResources2.java

This class contains some helper code that resolves fontPath from a text appearance or style resource.

public class XpResources2 {
    private static final int[] TEMP_ARRAY = new int[1];

    private XpResources2() {
    }

    public static String resolveString(Context context, @StyleRes int style, @AttrRes int attr) {
        TEMP_ARRAY[0] = attr;
        TypedArray ta = context.obtainStyledAttributes(style, TEMP_ARRAY);
        try {
            return ta.getString(0);
        } finally {
            ta.recycle();
        }
    }

    public static void applyFontToTextView(final TextView titleTextView, final int titleTextAppearance) {
        final Context context = titleTextView.getContext();
        String fontPath = getCalligraphyFontPath(context, titleTextAppearance);
        if (fontPath != null) {
            CalligraphyUtils.applyFontToTextView(context, titleTextView, fontPath);
        }
    }

    public static String getCalligraphyFontPath(final Context context, final int titleTextAppearance) {
        int attrId = CalligraphyConfig.get().getAttrId();
        return XpResources2.resolveString(context, titleTextAppearance, attrId);
    }
}

XpToolbar.java

Use this class in your XML layouts instead of android.support.v7.widget.Toolbar. It will update font when appropriate and should be somewhat effective doing that.

public class XpToolbar extends Toolbar {

    private static final Field FIELD_TITLE_TEXT_VIEW;
    private static final Field FIELD_TITLE_TEXT_APPEARANCE;

    private WeakReference<TextView> mTitleTextView = new WeakReference<>(null);
    private int mTitleTextAppearance = 0;

    static {
        Field titleTextView = null;
        try {
            titleTextView = Toolbar.class.getDeclaredField("mTitleTextView");
            titleTextView.setAccessible(true);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        FIELD_TITLE_TEXT_VIEW = titleTextView;

        Field titleTextAppearance = null;
        try {
            titleTextAppearance = Toolbar.class.getDeclaredField("mTitleTextAppearance");
            titleTextAppearance.setAccessible(true);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        FIELD_TITLE_TEXT_APPEARANCE = titleTextAppearance;
    }

    public XpToolbar(final Context context) {
        super(context);
    }

    public XpToolbar(final Context context, @Nullable final AttributeSet attrs) {
        super(context, attrs);
    }

    public XpToolbar(final Context context, @Nullable final AttributeSet attrs, final int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public static TextView getTitleTextView(Toolbar toolbar) {
        try {
            return (TextView) FIELD_TITLE_TEXT_VIEW.get(toolbar);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            return null;
        }
    }

    @StyleRes
    public static int getTitleTextAppearance(Toolbar toolbar) {
        try {
            return FIELD_TITLE_TEXT_APPEARANCE.getInt(toolbar);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            return 0;
        }
    }

    @Override
    public void setTitle(final CharSequence title) {
        super.setTitle(title);

        if (!TextUtils.isEmpty(title)) {
            // There's no title text view when there's no title.
            applyTitleFont();
        }
    }

    @Override
    public void setTitleTextAppearance(final Context context, @StyleRes final int resId) {
        super.setTitleTextAppearance(context, resId);

        applyTitleFont();
    }

    private void applyTitleFont() {
        TextView titleTextView = getTitleTextView(this);
        if (titleTextView != null) {
            @StyleRes int titleTextAppearance = getTitleTextAppearance(this);
            if (titleTextAppearance != 0) {
                boolean changed = false;
                if (titleTextView != mTitleTextView.get()) {
                    mTitleTextView = new WeakReference<>(titleTextView);
                    changed = true;
                }
                if (mTitleTextAppearance != titleTextAppearance) {
                    mTitleTextAppearance = titleTextAppearance;
                    changed = true;
                }
                if (changed) {
                    XpResources2.applyFontToTextView(titleTextView, titleTextAppearance);
                }
            }
        }
    }
}

I'm sure a clever mind could adapt it to style just subtitle as well.

It's even possible that calligraphy inflated such class instead of Toolbar automatically.

@chrisjenx
Copy link
Owner

I'm confused why you needed to do that? The title and subtitle styles are
set via the Theme applied to the Toolbar. See the sample App.

On Tue, 19 Apr 2016, 19:38 Eugen Pechanec, notifications@github.com wrote:

Alright, I really didn't want to change font in my whole toolbar, I just
wanted Roboto Medium title on Android 4. Calligraphy couldn't apply
app:titleTextAppearance for me so I subclassed Toolbar and read
app:fontPath manually.
XpResources2.java

This class contains some helper code that resolves fontPath from a text
appearance or style resource.

public class XpResources2 {
private static final int[] TEMP_ARRAY = new int[1];

private XpResources2() {
}

public static String resolveString(Context context, @StyleRes int style, @AttrRes int attr) {
    TEMP_ARRAY[0] = attr;
    TypedArray ta = context.obtainStyledAttributes(style, TEMP_ARRAY);
    try {
        return ta.getString(0);
    } finally {
        ta.recycle();
    }
}

public static void applyFontToTextView(final TextView titleTextView, final int titleTextAppearance) {
    final Context context = titleTextView.getContext();
    String fontPath = getCalligraphyFontPath(context, titleTextAppearance);
    if (fontPath != null) {
        CalligraphyUtils.applyFontToTextView(context, titleTextView, fontPath);
    }
}

public static String getCalligraphyFontPath(final Context context, final int titleTextAppearance) {
    int attrId = CalligraphyConfig.get().getAttrId();
    return XpResources2.resolveString(context, titleTextAppearance, attrId);
}

}

XpToolbar.java

Use this class in your XML layouts instead of
android.support.v7.widget.Toolbar. It will update font when appropriate
and should be somewhat effective doing that.

public class XpToolbar extends Toolbar {

private static final Field FIELD_TITLE_TEXT_VIEW;
private static final Field FIELD_TITLE_TEXT_APPEARANCE;

private WeakReference<TextView> mTitleTextView = new WeakReference<>(null);
private int mTitleTextAppearance = 0;

static {
    Field titleTextView = null;
    try {
        titleTextView = Toolbar.class.getDeclaredField("mTitleTextView");
        titleTextView.setAccessible(true);
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    }
    FIELD_TITLE_TEXT_VIEW = titleTextView;

    Field titleTextAppearance = null;
    try {
        titleTextAppearance = Toolbar.class.getDeclaredField("mTitleTextAppearance");
        titleTextAppearance.setAccessible(true);
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    }
    FIELD_TITLE_TEXT_APPEARANCE = titleTextAppearance;
}

public XpToolbar(final Context context) {
    super(context);
}

public XpToolbar(final Context context, @Nullable final AttributeSet attrs) {
    super(context, attrs);
}

public XpToolbar(final Context context, @Nullable final AttributeSet attrs, final int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}

public static TextView getTitleTextView(Toolbar toolbar) {
    try {
        return (TextView) FIELD_TITLE_TEXT_VIEW.get(toolbar);
    } catch (IllegalAccessException e) {
        e.printStackTrace();
        return null;
    }
}

@StyleRes
public static int getTitleTextAppearance(Toolbar toolbar) {
    try {
        return FIELD_TITLE_TEXT_APPEARANCE.getInt(toolbar);
    } catch (IllegalAccessException e) {
        e.printStackTrace();
        return 0;
    }
}

@Override
public void setTitle(final CharSequence title) {
    super.setTitle(title);

    if (!TextUtils.isEmpty(title)) {
        // There's no title text view when there's no title.
        applyTitleFont();
    }
}

@Override
public void setTitleTextAppearance(final Context context, @StyleRes final int resId) {
    super.setTitleTextAppearance(context, resId);

    applyTitleFont();
}

private void applyTitleFont() {
    TextView titleTextView = getTitleTextView(this);
    if (titleTextView != null) {
        @StyleRes int titleTextAppearance = getTitleTextAppearance(this);
        if (titleTextAppearance != 0) {
            boolean changed = false;
            if (titleTextView != mTitleTextView.get()) {
                mTitleTextView = new WeakReference<>(titleTextView);
                changed = true;
            }
            if (mTitleTextAppearance != titleTextAppearance) {
                mTitleTextAppearance = titleTextAppearance;
                changed = true;
            }
            if (changed) {
                XpResources2.applyFontToTextView(titleTextView, titleTextAppearance);
            }
        }
    }
}

}

I'm sure a clever mind could adapt it to style just subtitle as well.

It's even possible that calligraphy inflated such class instead of Toolbar
automatically.


You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub
#181 (comment)

@consp1racy
Copy link

See the sample App.

I basically did it the same way except I styled Toolbar instead of ActionBar.

I'm confused why you needed to do that?

My setup was just this:

<style name="TextAppearance.AppCompat.Title" parent="Base.TextAppearance.AppCompat.Title" tools:override="true">
    <item name="fontPath">fonts/Roboto-Medium.ttf</item>
</style>

TextAppearance.AppCompat.Title is base for TextAppearance.AppCompat.Widget.ActionBar.Title which is base for TextAppearance.Widget.AppCompat.Toolbar.Title which is the value of app:titleTextAppearance for default Toolbar widget style. The above text appearance should've been picked up by both ActionBar and Toolbar. I haven't tested ActionBar but Toolbar didn't work. Well, it was picked up but fontPath wasn't applied.

My toolbar wasn't inflated with the font I specified in my fontPath attribute automatically because at no point is Toolbar using LayoutInflater internally. I'm not sure if it's possible to wire it to how Toolbar manages its title TextView. See this:

public void setTitle(CharSequence title) {
    if (!TextUtils.isEmpty(title)) {
        if (mTitleTextView == null) {
            final Context context = getContext();
            mTitleTextView = new TextView(context);
            mTitleTextView.setSingleLine();
            mTitleTextView.setEllipsize(TextUtils.TruncateAt.END);
            if (mTitleTextAppearance != 0) {
                mTitleTextView.setTextAppearance(context, mTitleTextAppearance);
            }
            if (mTitleTextColor != 0) {
                mTitleTextView.setTextColor(mTitleTextColor);
            }
        }
        if (!isChildOrHidden(mTitleTextView)) {
            addSystemView(mTitleTextView, true);
        }
    } else if (mTitleTextView != null && isChildOrHidden(mTitleTextView)) {
        removeView(mTitleTextView);
        mHiddenViews.remove(mTitleTextView);
    }
    if (mTitleTextView != null) {
        mTitleTextView.setText(title);
    }
    mTitleText = title;
}

So I found a way around it.

If you have any tips or if I (very much likely) overlooked something I'm all ears.

Just a thought: Toolbar uses app:titleTextAppearance, ActionBar uses app:titleTextStyle. Does this concern Calligraphy somehow?

@chrisjenx
Copy link
Owner

Do you have your Toolbar defined in the XML? Or are you relying on the
AppCompatActivity to add it?

The Toolbar uses the android:actionBarStyle and
android:titleTextAppearance. I guess the app: ones work, but no need to
do that.

Basically Calligraphy resolves the Toolbar styles from the theme Theme ->
actionBarStyle -> titleTextAppearance/subtitleTextAppearance. Did you try
those?

On Tue, 19 Apr 2016 at 21:49 Eugen Pechanec notifications@github.com
wrote:

See the sample App.

I basically did it the same way except I styled Toolbar instead of
ActionBar.

I'm confused why you needed to do that?

My setup was just this:

<style name="TextAppearance.AppCompat.Title" parent="Base.TextAppearance.AppCompat.Title" tools:override="true"> fonts/Roboto-Medium.ttf </style>

TextAppearance.AppCompat.Title is base for
TextAppearance.AppCompat.Widget.ActionBar.Title which is base for
TextAppearance.Widget.AppCompat.Toolbar.Title which is the value of
app:titleTextAppearance for default Toolbar widget style. The above text
appearance should've been picked up by both ActionBar and Toolbar. I
haven't tested ActionBar but Toolbar didn't work. Well, it was picked up
but fontPath wasn't applied.

My toolbar wasn't inflated with the font I specified in my fontPath
attribute automatically because at no point is Toolbar using
LayoutInflater internally. I'm not sure if it's possible to wire it to
how Toolbar manages its title TextView. See this:

public void setTitle(CharSequence title) {
if (!TextUtils.isEmpty(title)) {
if (mTitleTextView == null) {
final Context context = getContext();
mTitleTextView = new TextView(context);
mTitleTextView.setSingleLine();
mTitleTextView.setEllipsize(TextUtils.TruncateAt.END);
if (mTitleTextAppearance != 0) {
mTitleTextView.setTextAppearance(context, mTitleTextAppearance);
}
if (mTitleTextColor != 0) {
mTitleTextView.setTextColor(mTitleTextColor);
}
}
if (!isChildOrHidden(mTitleTextView)) {
addSystemView(mTitleTextView, true);
}
} else if (mTitleTextView != null && isChildOrHidden(mTitleTextView)) {
removeView(mTitleTextView);
mHiddenViews.remove(mTitleTextView);
}
if (mTitleTextView != null) {
mTitleTextView.setText(title);
}
mTitleText = title;
}

So I found a way around it.

If you have any tips or if I (very much likely) overlooked something I'm
all ears.

Just a thought: Toolbar uses app:titleTextAppearance, ActionBar uses
app:titleTextStyle. Does this concern Calligraphy somehow?


You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub
#181 (comment)

@consp1racy
Copy link

Do you have your Toolbar defined in the XML?

Yes, absolutely, then I call setSupportActionBar(...). It's a android.support.v7.widget.Toolbar.

The Toolbar uses [...]

Action bar provided by AppCompat uses app:titleTextStyle attribute.
android.widget.Toolbar (native toolbar since API 21) uses android:titleTextAppearance.
android.support.v7.widget.Toolbar (AppCompat toolbar) uses app:titleTextAppearance (because android:titleTextAppearance was introduced in API 21).
Toolbars absolutely ignore titleTextStyle and AppCompat action bar ignores titleTextAppearance.
However this shouldn't impact Calligraphy in any way, correct?

Did you try those?

I don't think there's much point to it, all of AppCompat title attributes (app:actionBarStyle -> app:titleTextStyle and app:toolbarStyle -> app:titleTextAppearance) point to a text appearance which has fontPath attribute defined.

But yes, I tried overriding both toolbar and action bar styles so app:titleTextAppearance and app:titleTextStyle respectively point directly to a text appearance resource with font path specified. No success.

Using calligraphy 2.2.0 and appcompat 23.3.0.

I prepared a tiny project to illustrate what I'm working with.
https://drive.google.com/file/d/0B01rD9OuoIztQTk2QndhZG9mVFk/view?usp=sharing

@mdumrauf
Copy link

Any news on this? I'm having the same problem trying to set fontPath to a Toolbar

@chrisjenx
Copy link
Owner

@consp1racy we look up those attributes manually as those views are never inflated.
Workaround is to set the ones defined in the sample for now. Then we can look at a better way of doing this later.

@mdumrauf
Copy link

@chrisjenx you mean setting them manually by code or this?

<Toolbar>
 <TextView fontPath="fonts/myFont.ttf" />
</Toolbar>

@mdumrauf
Copy link

I've just checked Toolbar's source code and also came across your comment here #120 (comment). I used the layout solution and applied fontPath to the TextView.

I also had to hide the default title. Any of these two options are suitable:

  1. getSupportActionBar().setDisplayShowTitleEnabled(false);
  2. Use an empty string for the label of the Activity in the AndroidManifest declaration:
<activity
            android:name=".activity.MainActivity"
            android:launchMode="singleTop"
            android:label=""
            android:screenOrientation="portrait"
            android:theme="@style/AppTheme.NoActionBar"/>

I prefer the second one so that I don't have to add code that is actually part of the view.

@cperry-gpsw
Copy link

Correct me if I'm wrong, but poking into the source for Toolbar shows that it uses toolbarStyle:

public Toolbar(Context context, @Nullable AttributeSet attrs) {
    this(context, attrs, R.attr.toolbarStyle);
}

setting a style to anything other than that in your theme will have no effect.

I'm taking the same approach as @consp1racy and setting my titleTextStyle in my toolbarStyle to a TextAppearance that contains the relevant fontPath, which does not work as of this version of Calligraphy.

If you point me in the right direction, perhaps I can submit a fix.

@consp1racy
Copy link

I'm using a workaround, see here:
https://github.com/consp1racy/android-commons/blob/master/android/src/main/java/net/xpece/android/widget/CalligraphyToolbar.java
https://github.com/consp1racy/android-commons/blob/master/android/src/main/java/net/xpece/android/widget/CalligraphyToolbarHelper.java
https://github.com/consp1racy/android-commons/blob/master/android/src/main/java/net/xpece/android/widget/XpToolbar.java

Proguard setup:

-keepclassmembernames class android.support.v7.widget.Toolbar {
    android.widget.TextView mTitleTextView;
    android.widget.TextView mSubtitleTextView;
    int mTitleTextAppearance;
    int mSubtitleTextAppearance;
    android.graphics.drawable.Drawable mCollapseIcon;
}

Pros:
Works.

Cons:
Subclasses Toolbar.

Usage:
Use net.xpece.android.widget.CalligraphyToolbar instead of android.support.v7.widget.Toolbar.

How it works:
Every time a title or subtitle TextView is created inside a CalligraphyToolbar, the appropriate text appearance resource (specified by app:titleTextAppearance and app:subtitleTextAppearance) is taken and its fontPath read and applied to said TextView.

@JHabergas
Copy link

JHabergas commented Feb 13, 2017

Good day sir Chris! How do I set the custom font on the CollapsingToolbarLayout? I am using Android Studio 2.2.3.

here is in the activity_main.xml:

      `<android.support.design.widget.CollapsingToolbarLayout
        android:id="@+id/toolbar_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true"
        app:contentScrim="?attr/colorPrimary"
        app:layout_scrollFlags="scroll|exitUntilCollapsed"
        >

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            app:layout_collapseMode="pin"
            app:popupTheme="@style/AppTheme.PopupOverlay"

            />

    </android.support.design.widget.CollapsingToolbarLayout>`

and strings.xml here i can see the title set in string:

<string name="title_activity_preface">Preface</string>

Please help Sir.. Thank you..

@mramdanf
Copy link

mramdanf commented Feb 14, 2017

hai @Jeevuz i have same problem, im successfully change default font for entire of my app but when i want to change font for my toolbar separately its not working. below is what i was done so far.

<android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="@color/dark_orange"
            android:theme="@style/ToolbarTheme">

</android.support.v7.widget.Toolbar>
<style name="ToolbarTheme" parent="@style/ThemeOverlay.AppCompat.ActionBar">
        <item name="fontPath">@string/titillium_bold</item>
 </style>

@Jeevuz
Copy link
Author

Jeevuz commented Feb 14, 2017 via email

@shifatul-i
Copy link

shifatul-i commented Feb 14, 2017

Hello, anybody successfully implemented it with CollapsingToolbarLayout ?

<android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/toolbar_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            app:contentScrim="?attr/colorPrimary"
            android:theme="@style/ToolbarTheme"                           <!-- Not working-->
            app:expandedTitleTextAppearance="@style/HeaderTitleStyle"     <!-- Not working-->
            app:collapsedTitleTextAppearance="@style/HeaderTitleStyle"    <!-- Not working-->
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_collapseMode="pin"
                app:popupTheme="@style/AppTheme.PopupOverlay" />

        </android.support.design.widget.CollapsingToolbarLayout>

Styles

    <style name="ToolbarTheme" parent="@style/ThemeOverlay.AppCompat.ActionBar">
        <item name="fontPath">fonts/Roboto-Medium.ttf</item>
    </style>

    <style name="HeaderTitleStyle" parent="@android:style/TextAppearance">
        <item name="fontPath">fonts/Roboto-Medium.ttf</item>
    </style>

the attachBaseContext and CalligraphyConfig.initDefault is also set as per main documantation

@mramdanf
Copy link

thanks for response @Jeevuz, im sory for my newbieness what API do you mean? im tested the app with android kitkat 4.4.2 below is snippet of my build gradle

compileSdkVersion 23
    buildToolsVersion "23.0.2"
    defaultConfig {
        applicationId "xxx"
        minSdkVersion 16
        targetSdkVersion 23
        versionCode 20
        versionName "8.0.9"
    }

could you give me some advice please..

@Jeevuz
Copy link
Author

Jeevuz commented Feb 14, 2017 via email

@chrisjenx
Copy link
Owner

chrisjenx commented Feb 14, 2017 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests