diff --git a/README.md b/README.md index 8295323..5fb2e5c 100644 --- a/README.md +++ b/README.md @@ -39,11 +39,25 @@ Define your default font using `CalligraphyConfig`, in your `Application` class @Override public void onCreate() { super.onCreate(); + + // Customize each text style font separately CalligraphyConfig.initDefault(new CalligraphyConfig.Builder() .setDefaultFontPath("fonts/Roboto-RobotoRegular.ttf") + .setDefaultBoldFontPath("fonts/Roboto-RobotoBold.ttf") + .setDefaultItalicFontPath("fonts/Roboto-RobotoItalic.ttf") + .setDefaultBoldItalicFontPath("fonts/Roboto-RobotoBoldItalic.ttf") .setFontAttrId(R.attr.fontPath) .build() ); + + // Set the inherent default font path to look up Regular, Bold, Italic, and Bold-Italic fonts stored in your assets folder + // NOTE: This string will be formatted to lookup each font style. If one of the styles is not found, the default (Regular) will be used + CalligraphyConfig.initDefault(new CalligraphyConfig.Builder() + .setInherentDefaultFontPaths("fonts/Roboto-%s.ttf") + .setFontAttrId(R.attr.fontPath) + .build() + ); + //.... } ``` @@ -70,11 +84,22 @@ _You're good to go!_ ### Custom font per TextView ```xml + + fontPath="fonts/Roboto-Regular.ttf" + boldFontPath="fonts/Roboto-Bold.ttf" + italicFontPath="fonts/Roboto-Italic.ttf" + boldItalicFontPath="fonts/Roboto-Bold-Italic.ttf"/> + + + ``` _Note: Popular IDE's (Android Studio, IntelliJ) will likely mark this as an error despite being correct. You may want to add `tools:ignore="MissingPrefix"` to either the View itself or its parent ViewGroup to avoid this. You'll need to add the tools namespace to have access to this "ignore" attribute. `xmlns:tools=" @@ -84,9 +109,19 @@ http://schemas.android.com/tools"`. See https://code.google.com/p/android/issues ```xml + + + + ``` @@ -103,8 +138,17 @@ http://schemas.android.com/tools"`. See https://code.google.com/p/android/issues ```xml + + + + ``` @@ -117,8 +161,17 @@ http://schemas.android.com/tools"`. See https://code.google.com/p/android/issues + + + ``` @@ -136,7 +189,17 @@ The `CalligraphyFactory` looks for the font in a pretty specific order, for the defined in the `Style` and a `TextAttribute` defined in the `View` the `Style` attribute is picked first! 4. `Theme` - if defined this is used. 5. `Default` - if defined in the `CalligraphyConfig` this is used of none of the above are found -**OR** if one of the above returns an invalid font. +**OR** if one of the above returns an invalid font. + +When specifying an inherent font path, we lookup each font based on these values +```java + // If we fail to find one of the fonts, we will either default to the Regular font supplied (i.e. "fonts/font-Regular.ttf") + // or the default system font if there is no Regular + String.format("fonts/font-%s.ttf", "Regular"); + String.format("fonts/font-%s.ttf", "Bold"); + String.format("fonts/font-%s.ttf", "Italic"); + String.format("fonts/font-%s.ttf", "Bold-Italic"); +``` ### Why *not* piggyback off of fontFamily attribute? diff --git a/calligraphy/src/main/java/uk/co/chrisjenx/calligraphy/CalligraphyConfig.java b/calligraphy/src/main/java/uk/co/chrisjenx/calligraphy/CalligraphyConfig.java old mode 100644 new mode 100755 index c22148a..a1faa91 --- a/calligraphy/src/main/java/uk/co/chrisjenx/calligraphy/CalligraphyConfig.java +++ b/calligraphy/src/main/java/uk/co/chrisjenx/calligraphy/CalligraphyConfig.java @@ -1,7 +1,10 @@ package uk.co.chrisjenx.calligraphy; +import android.content.Context; +import android.graphics.Typeface; import android.os.Build; import android.text.TextUtils; +import android.util.Log; import android.widget.AutoCompleteTextView; import android.widget.Button; import android.widget.CheckBox; @@ -70,10 +73,34 @@ public static CalligraphyConfig get() { * The default Font Path if nothing else is setup. */ private final String mFontPath; + /** + * The default Bold Font Path if nothing else is setup. + */ + private final String mBoldFontPath; + /** + * The default Italic Font Path if nothing else is setup. + */ + private final String mItalicFontPath; + /** + * The default Bold Italic Font Path if nothing else is setup. + */ + private final String mBoldItalicFontPath; /** * Default Font Path Attr Id to lookup */ private final int mAttrId; + /** + * Default Bold Font Path Attr Id to lookup + */ + private final int mBoldAttrId; + /** + * Default Italic Font Path Attr Id to lookup + */ + private final int mItalicAttrId; + /** + * Default Bold Italic Font Path Attr Id to lookup + */ + private final int mBoldItalicAttrId; /** * Use Reflection to inject the private factory. */ @@ -90,7 +117,13 @@ public static CalligraphyConfig get() { protected CalligraphyConfig(Builder builder) { mIsFontSet = builder.isFontSet; mFontPath = builder.fontAssetPath; + mBoldFontPath = builder.boldFontAssetPath; + mItalicFontPath = builder.italicFontAssetPath; + mBoldItalicFontPath = builder.boldItalicFontAssetPath; mAttrId = builder.attrId; + mBoldAttrId = builder.boldAttrId; + mItalicAttrId = builder.italicAttrId; + mBoldItalicAttrId = builder.boldItalicAttrId; mReflection = builder.reflection; mCustomViewCreation = builder.customViewCreation; final Map, Integer> tempMap = new HashMap<>(DEFAULT_STYLES); @@ -105,6 +138,27 @@ public String getFontPath() { return mFontPath; } + /** + * @return mBoldFontPath for text views might be null + */ + public String getBoldFontPath() { + return mBoldFontPath; + } + + /** + * @return mItalicFontPath for text views might be null + */ + public String getItalicFontPath() { + return mItalicFontPath; + } + + /** + * @return mBoldItalicFontPath for text views might be null + */ + public String getBoldItalicFontPath() { + return mBoldItalicFontPath; + } + /** * @return true if set, false if null|empty */ @@ -131,6 +185,27 @@ public int getAttrId() { return mAttrId; } + /** + * @return the custom boldAttrId to look for, -1 if not set. + */ + public int getBoldAttrId() { + return mBoldAttrId; + } + + /** + * @return the custom italicAttrId to look for, -1 if not set. + */ + public int getItalicAttrId() { + return mItalicAttrId; + } + + /** + * @return the custom boldItalicAttrId to look for, -1 if not set. + */ + public int getBoldItalicAttrId() { + return mBoldItalicAttrId; + } + public static class Builder { /** * Default AttrID if not set. @@ -148,6 +223,18 @@ public static class Builder { * The fontAttrId to look up the font path from. */ private int attrId = R.attr.fontPath; + /** + * The boldFontPath to look up the font path from. + */ + private int boldAttrId = R.attr.boldFontPath; + /** + * The italicFontPath to look up the font path from. + */ + private int italicAttrId = R.attr.italicFontPath; + /** + * The boldItalicFontPath to look up the font path from. + */ + private int boldItalicAttrId = R.attr.boldItalicFontPath; /** * Has the user set the default font path. */ @@ -156,6 +243,18 @@ public static class Builder { * The default fontPath */ private String fontAssetPath = null; + /** + * The default bold fontPath + */ + private String boldFontAssetPath = null; + /** + * The default italic fontPath + */ + private String italicFontAssetPath = null; + /** + * The default bold italic fontPath + */ + private String boldItalicFontAssetPath = null; /** * Additional Class Styles. Can be empty. */ @@ -168,10 +267,73 @@ public static class Builder { * @return this builder. */ public Builder setFontAttrId(int fontAssetAttrId) { - this.attrId = fontAssetAttrId != INVALID_ATTR_ID ? fontAssetAttrId : INVALID_ATTR_ID; + this.attrId = fontAssetAttrId; + return this; + } + + /** + * This defaults to R.attr.boldFontPath. So only override if you want to use your own attrId. + * + * @param fontAssetAttrId the custom attribute to look for fonts in assets. + * @return this builder. + */ + public Builder setBoldFontAttrId(int fontAssetAttrId) { + this.boldAttrId = fontAssetAttrId; + return this; + } + + /** + * This defaults to R.attr.italicFontPath. So only override if you want to use your own attrId. + * + * @param fontAssetAttrId the custom attribute to look for fonts in assets. + * @return this builder. + */ + public Builder setItalicFontAttrId(int fontAssetAttrId) { + this.italicAttrId = fontAssetAttrId; + return this; + } + + /** + * This defaults to R.attr.boldItalicFontPath. So only override if you want to use your own attrId. + * + * @param fontAssetAttrId the custom attribute to look for fonts in assets. + * @return this builder. + */ + public Builder setBoldItalicFontAttrId(int fontAssetAttrId) { + this.boldItalicAttrId = fontAssetAttrId; return this; } + /** + * Set the default font if you don't define one else where in your styles. + * + * @param defaultFontAssetPath an inherent path to a font family in the assets folder, e.g. "fonts/Roboto-%s.ttf", + * passing null will default to the device font-family. This will dynamically apply + * regular, bold, and italic (if available in the assets folder). + * E.g. "fonts/Roboto-%s.ttf" -> "fonts/Roboto-Regular.ttf", "fonts/Roboto-Bold.ttf", "fonts/Roboto-Italic.ttf" + * @return this builder. + */ + public Builder setInherentDefaultFontPaths(Context context, String defaultFontAssetPath) { + if (!CalligraphyUtils.isInherentFontPath(defaultFontAssetPath)) { + throw new IllegalStateException("You must pass a font path that may be formatted. e.g. fonts/font-%s.ttf"); + } + + loadDefaultFontPath(context, defaultFontAssetPath, CalligraphyUtils.FONT_REGULAR); + loadDefaultFontPath(context, defaultFontAssetPath, CalligraphyUtils.FONT_BOLD); + loadDefaultFontPath(context, defaultFontAssetPath, CalligraphyUtils.FONT_ITALIC); + loadDefaultFontPath(context, defaultFontAssetPath, CalligraphyUtils.FONT_BOLD_ITALIC); + return this; + } + + private void loadDefaultFontPath(Context context, String defaultFontAssetPath, String fontStyle) { + try { + Typeface.createFromAsset(context.getAssets(), CalligraphyUtils.pullFontPathFromInherentFontPath(defaultFontAssetPath, fontStyle)); + setDefaultFontPath(CalligraphyUtils.pullFontPathFromInherentFontPath(defaultFontAssetPath, fontStyle)); + } catch (Throwable t) { + Log.e("Calligraphy", "Error setting font path", t); + } + } + /** * Set the default font if you don't define one else where in your styles. * @@ -185,11 +347,50 @@ public Builder setDefaultFontPath(String defaultFontAssetPath) { return this; } + /** + * Set the default bold font if you don't define one else where in your styles. + * + * @param defaultFontAssetPath a path to a font file in the assets folder, e.g. "fonts/Roboto-light.ttf", + * passing null will default to the device font-family. + * @return this builder. + */ + public Builder setDefaultBoldFontPath(String defaultFontAssetPath) { + this.isFontSet = !TextUtils.isEmpty(defaultFontAssetPath); + this.boldFontAssetPath = defaultFontAssetPath; + return this; + } + + /** + * Set the default italic font if you don't define one else where in your styles. + * + * @param defaultFontAssetPath a path to a font file in the assets folder, e.g. "fonts/Roboto-light.ttf", + * passing null will default to the device font-family. + * @return this builder. + */ + public Builder setDefaultItalicFontPath(String defaultFontAssetPath) { + this.isFontSet = !TextUtils.isEmpty(defaultFontAssetPath); + this.italicFontAssetPath = defaultFontAssetPath; + return this; + } + + /** + * Set the default bold italic font if you don't define one else where in your styles. + * + * @param defaultFontAssetPath a path to a font file in the assets folder, e.g. "fonts/Roboto-light.ttf", + * passing null will default to the device font-family. + * @return this builder. + */ + public Builder setDefaultBoldItalicFontPath(String defaultFontAssetPath) { + this.isFontSet = !TextUtils.isEmpty(defaultFontAssetPath); + this.boldItalicFontAssetPath = defaultFontAssetPath; + return this; + } + /** *

Turn of the use of Reflection to inject the private factory. * This has operational consequences! Please read and understand before disabling. * This is already disabled on pre Honeycomb devices. (API 11)

- * + *

*

If you disable this you will need to override your {@link android.app.Activity#onCreateView(android.view.View, String, android.content.Context, android.util.AttributeSet)} * as this is set as the {@link android.view.LayoutInflater} private factory.

*
@@ -211,21 +412,21 @@ public Builder disablePrivateFactoryInjection() { * Due to the poor inflation order where custom views are created and never returned inside an * {@code onCreateView(...)} method. We have to create CustomView's at the latest point in the * overrideable injection flow. - * + *

* On HoneyComb+ this is inside the {@link android.app.Activity#onCreateView(android.view.View, String, android.content.Context, android.util.AttributeSet)} * Pre HoneyComb this is in the {@link android.view.LayoutInflater.Factory#onCreateView(String, android.util.AttributeSet)} - * + *

* We wrap base implementations, so if you LayoutInflater/Factory/Activity creates the * custom view before we get to this point, your view is used. (Such is the case with the * TintEditText etc) - * + *

* The problem is, the native methods pass there parents context to the constructor in a really * specific place. We have to mimic this in {@link uk.co.chrisjenx.calligraphy.CalligraphyLayoutInflater#createCustomViewInternal(android.view.View, android.view.View, String, android.content.Context, android.util.AttributeSet)} * To mimic this we have to use reflection as the Class constructor args are hidden to us. - * + *

* We have discussed other means of doing this but this is the only semi-clean way of doing it. * (Without having to do proxy classes etc). - * + *

* Calling this will of course speed up inflation by turning off reflection, but not by much, * But if you want Calligraphy to inject the correct typeface then you will need to make sure your CustomView's * are created before reaching the LayoutInflater onViewCreated. @@ -238,13 +439,13 @@ public Builder disableCustomViewInflation() { /** * Add a custom style to get looked up. If you use a custom class that has a parent style * which is not part of the default android styles you will need to add it here. - * + *

* The Calligraphy inflater is unaware of custom styles in your custom classes. We use * the class type to look up the style attribute in the theme resources. - * + *

* So if you had a {@code MyTextField.class} which looked up it's default style as * {@code R.attr.textFieldStyle} you would add those here. - * + *

* {@code builder.addCustomStyle(MyTextField.class,R.attr.textFieldStyle} * * @param styleClass the class that related to the parent styleResource. null is ignored. diff --git a/calligraphy/src/main/java/uk/co/chrisjenx/calligraphy/CalligraphyContextWrapper.java b/calligraphy/src/main/java/uk/co/chrisjenx/calligraphy/CalligraphyContextWrapper.java index 8650208..6b2c140 100644 --- a/calligraphy/src/main/java/uk/co/chrisjenx/calligraphy/CalligraphyContextWrapper.java +++ b/calligraphy/src/main/java/uk/co/chrisjenx/calligraphy/CalligraphyContextWrapper.java @@ -16,6 +16,8 @@ public class CalligraphyContextWrapper extends ContextWrapper { private CalligraphyLayoutInflater mInflater; private final int mAttributeId; + private final int mBoldAttributeId; + private final int mItalicAttributeId; /** * Uses the default configuration from {@link uk.co.chrisjenx.calligraphy.CalligraphyConfig} @@ -84,6 +86,8 @@ static CalligraphyActivityFactory get(Activity activity) { CalligraphyContextWrapper(Context base) { super(base); mAttributeId = CalligraphyConfig.get().getAttrId(); + mBoldAttributeId = CalligraphyConfig.get().getBoldAttrId(); + mItalicAttributeId = CalligraphyConfig.get().getItalicAttrId(); } /** @@ -99,16 +103,18 @@ static CalligraphyActivityFactory get(Activity activity) { * @deprecated use {@link #wrap(android.content.Context)} */ @Deprecated - public CalligraphyContextWrapper(Context base, int attributeId) { + public CalligraphyContextWrapper(Context base, int attributeId, int boldAttributeId, int italicAttributeId) { super(base); mAttributeId = attributeId; + mBoldAttributeId = boldAttributeId; + mItalicAttributeId = italicAttributeId; } @Override public Object getSystemService(String name) { if (LAYOUT_INFLATER_SERVICE.equals(name)) { if (mInflater == null) { - mInflater = new CalligraphyLayoutInflater(LayoutInflater.from(getBaseContext()), this, mAttributeId, false); + mInflater = new CalligraphyLayoutInflater(LayoutInflater.from(getBaseContext()), this, mAttributeId, mBoldAttributeId, mItalicAttributeId, false); } return mInflater; } diff --git a/calligraphy/src/main/java/uk/co/chrisjenx/calligraphy/CalligraphyFactory.java b/calligraphy/src/main/java/uk/co/chrisjenx/calligraphy/CalligraphyFactory.java old mode 100644 new mode 100755 index ca45b62..d340985 --- a/calligraphy/src/main/java/uk/co/chrisjenx/calligraphy/CalligraphyFactory.java +++ b/calligraphy/src/main/java/uk/co/chrisjenx/calligraphy/CalligraphyFactory.java @@ -3,6 +3,7 @@ import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.content.Context; +import android.graphics.Typeface; import android.os.Build; import android.text.TextUtils; import android.util.AttributeSet; @@ -16,6 +17,11 @@ class CalligraphyFactory { private static final String ACTION_BAR_TITLE = "action_bar_title"; private static final String ACTION_BAR_SUBTITLE = "action_bar_subtitle"; + /** + * Default AttrID if not set. + */ + public static final int INVALID_ATTR_ID = -1; + /** * Some styles are in sub styles, such as actionBarTextStyle etc.. * @@ -91,9 +97,13 @@ protected static boolean matchesResourceIdName(View view, String matches) { } private final int mAttributeId; + private final int mBoldAttributeId; + private final int mItalicAttributeId; - public CalligraphyFactory(int attributeId) { + public CalligraphyFactory(int attributeId, int boldAttributeId, int italicAttributeId) { this.mAttributeId = attributeId; + this.mBoldAttributeId = boldAttributeId; + this.mItalicAttributeId = italicAttributeId; } /** @@ -123,28 +133,7 @@ void onViewCreatedInternal(View view, final Context context, AttributeSet attrs) } // Try to get typeface attribute value // Since we're not using namespace it's a little bit tricky - - // Try view xml attributes - String textViewFont = CalligraphyUtils.pullFontPathFromView(context, attrs, mAttributeId); - - // Try view style attributes - if (TextUtils.isEmpty(textViewFont)) { - textViewFont = CalligraphyUtils.pullFontPathFromStyle(context, attrs, mAttributeId); - } - - // Try View TextAppearance - if (TextUtils.isEmpty(textViewFont)) { - textViewFont = CalligraphyUtils.pullFontPathFromTextAppearance(context, attrs, mAttributeId); - } - - // Try theme attributes - if (TextUtils.isEmpty(textViewFont)) { - final int[] styleForTextView = getStyleForTextView((TextView) view); - if (styleForTextView[1] != -1) - textViewFont = CalligraphyUtils.pullFontPathFromTheme(context, styleForTextView[0], styleForTextView[1], mAttributeId); - else - textViewFont = CalligraphyUtils.pullFontPathFromTheme(context, styleForTextView[0], mAttributeId); - } + String textViewFont = selectFont((TextView) view, context, attrs); // Still need to defer the Native action bar, appcompat-v7:21+ uses the Toolbar underneath. But won't match these anyway. final boolean deferred = matchesResourceIdName(view, ACTION_BAR_TITLE) || matchesResourceIdName(view, ACTION_BAR_SUBTITLE); @@ -180,5 +169,43 @@ public void onGlobalLayout() { } } + private String selectFont(TextView textView, Context context, AttributeSet attrs) { + String textViewFont; + + // get style: regular/bold/italic + int styleAttributeId; + if (textView.getTypeface() == null) { + styleAttributeId = mAttributeId; + } else if (textView.getTypeface().getStyle() == Typeface.BOLD && mBoldAttributeId != INVALID_ATTR_ID) { + styleAttributeId = mBoldAttributeId; + } else if (textView.getTypeface().getStyle() == Typeface.ITALIC && mItalicAttributeId != INVALID_ATTR_ID) { + styleAttributeId = mItalicAttributeId; + } else { + styleAttributeId = mAttributeId; + } + + // Try view xml attributes + textViewFont = CalligraphyUtils.pullFontPathFromView(context, attrs, styleAttributeId); -} + // Try view style attributes + if (TextUtils.isEmpty(textViewFont)) { + textViewFont = CalligraphyUtils.pullFontPathFromStyle(context, attrs, styleAttributeId); + } + + // Try View TextAppearance + if (TextUtils.isEmpty(textViewFont)) { + textViewFont = CalligraphyUtils.pullFontPathFromTextAppearance(context, attrs, styleAttributeId); + } + + // Try theme attributes + if (TextUtils.isEmpty(textViewFont)) { + final int[] styleForTextView = getStyleForTextView(textView); + if (styleForTextView[1] != -1) { + textViewFont = CalligraphyUtils.pullFontPathFromTheme(context, styleForTextView[0], styleForTextView[1], styleAttributeId); + } else { + textViewFont = CalligraphyUtils.pullFontPathFromTheme(context, styleForTextView[0], styleAttributeId); + } + } + return textViewFont; + } +} \ No newline at end of file diff --git a/calligraphy/src/main/java/uk/co/chrisjenx/calligraphy/CalligraphyLayoutInflater.java b/calligraphy/src/main/java/uk/co/chrisjenx/calligraphy/CalligraphyLayoutInflater.java index 6f9cfc1..8ef3b80 100644 --- a/calligraphy/src/main/java/uk/co/chrisjenx/calligraphy/CalligraphyLayoutInflater.java +++ b/calligraphy/src/main/java/uk/co/chrisjenx/calligraphy/CalligraphyLayoutInflater.java @@ -25,28 +25,34 @@ class CalligraphyLayoutInflater extends LayoutInflater implements CalligraphyAct }; private final int mAttributeId; + private final int mBoldAttributeId; + private final int mItalicAttributeId; private final CalligraphyFactory mCalligraphyFactory; // Reflection Hax private boolean mSetPrivateFactory = false; private Field mConstructorArgs = null; - protected CalligraphyLayoutInflater(Context context, int attributeId) { + protected CalligraphyLayoutInflater(Context context, int attributeId, int boldAttributeId, int italicAttributeId) { super(context); mAttributeId = attributeId; - mCalligraphyFactory = new CalligraphyFactory(attributeId); + mBoldAttributeId = boldAttributeId; + mItalicAttributeId = italicAttributeId; + mCalligraphyFactory = new CalligraphyFactory(attributeId, boldAttributeId, italicAttributeId); setUpLayoutFactories(false); } - protected CalligraphyLayoutInflater(LayoutInflater original, Context newContext, int attributeId, final boolean cloned) { + protected CalligraphyLayoutInflater(LayoutInflater original, Context newContext, int attributeId, int boldAttributeId, int italicAttributeId, final boolean cloned) { super(original, newContext); mAttributeId = attributeId; - mCalligraphyFactory = new CalligraphyFactory(attributeId); + mBoldAttributeId = boldAttributeId; + mItalicAttributeId = italicAttributeId; + mCalligraphyFactory = new CalligraphyFactory(attributeId, boldAttributeId, italicAttributeId); setUpLayoutFactories(cloned); } @Override public LayoutInflater cloneInContext(Context newContext) { - return new CalligraphyLayoutInflater(this, newContext, mAttributeId, true); + return new CalligraphyLayoutInflater(this, newContext, mAttributeId, mBoldAttributeId, mItalicAttributeId, true); } // === diff --git a/calligraphy/src/main/java/uk/co/chrisjenx/calligraphy/CalligraphyUtils.java b/calligraphy/src/main/java/uk/co/chrisjenx/calligraphy/CalligraphyUtils.java old mode 100644 new mode 100755 index 11737bf..ec849af --- a/calligraphy/src/main/java/uk/co/chrisjenx/calligraphy/CalligraphyUtils.java +++ b/calligraphy/src/main/java/uk/co/chrisjenx/calligraphy/CalligraphyUtils.java @@ -22,6 +22,11 @@ */ public final class CalligraphyUtils { + public static final String FONT_REGULAR = "Regular"; + public static final String FONT_BOLD = "Bold"; + public static final String FONT_ITALIC = "Italic"; + public static final String FONT_BOLD_ITALIC = "Bold-Italic"; + /** * Applies a custom typeface span to the text. * @@ -57,7 +62,7 @@ public static boolean applyFontToTextView(final TextView textView, final Typefac /** * Applies a Typeface to a TextView, if deferred,its recommend you don't call this multiple * times, as this adds a TextWatcher. - * + *

* Deferring should really only be used on tricky views which get Typeface set by the system at * weird times. * @@ -113,14 +118,37 @@ static boolean applyFontToTextView(final Context context, final TextView textVie return applyFontToTextView(textView, typeface, deferred); } - static void applyFontToTextView(final Context context, final TextView textView, final CalligraphyConfig config) { - applyFontToTextView(context, textView, config, false); + static void applyFontToTextView(final Context context, final TextView textView, final CalligraphyConfig config, boolean deferred) { + if (context == null || textView == null || config == null) { + return; + } + if (!config.isFontSet()) { + return; + } + + String fontPath = getFontPathByStyle(textView, config); + applyFontToTextView(context, textView, fontPath, deferred); } - static void applyFontToTextView(final Context context, final TextView textView, final CalligraphyConfig config, boolean deferred) { - if (context == null || textView == null || config == null) return; - if (!config.isFontSet()) return; - applyFontToTextView(context, textView, config.getFontPath(), deferred); + private static String getFontPathByStyle(TextView textView, CalligraphyConfig config) { + String fontPath = null; + if (textView.getTypeface() != null) { + switch (textView.getTypeface().getStyle()) { + case Typeface.BOLD: + fontPath = config.getBoldFontPath(); + break; + case Typeface.ITALIC: + fontPath = config.getItalicFontPath(); + break; + case Typeface.BOLD_ITALIC: + fontPath = config.getBoldItalicFontPath(); + break; + } + } + if (fontPath == null) { + fontPath = config.getFontPath(); + } + return fontPath; } /** @@ -137,11 +165,45 @@ public static void applyFontToTextView(final Context context, final TextView tex } static void applyFontToTextView(final Context context, final TextView textView, final CalligraphyConfig config, final String textViewFont, boolean deferred) { - if (context == null || textView == null || config == null) return; - if (!TextUtils.isEmpty(textViewFont) && applyFontToTextView(context, textView, textViewFont, deferred)) { + if (context == null || textView == null || config == null) { return; } - applyFontToTextView(context, textView, config, deferred); + + if (TextUtils.isEmpty(textViewFont) || !isInherentFontPath(textViewFont)) { + applyFontToTextView(context, textView, config, deferred); + return; + } + + String style = getStyleIdentifier(textView); + + try { + Typeface.createFromAsset(context.getAssets(), pullFontPathFromInherentFontPath(textViewFont, style)); + applyFontToTextView(context, textView, pullFontPathFromInherentFontPath(textViewFont, style), deferred); + } catch (Throwable t) { + applyFontToTextView(context, textView, config, deferred); + } + } + + private static String getStyleIdentifier(TextView textView) { + String style; + if (textView.getTypeface() == null) { + style = FONT_REGULAR; + } else { + switch (textView.getTypeface().getStyle()) { + case Typeface.BOLD: + style = FONT_BOLD; + break; + case Typeface.ITALIC: + style = FONT_ITALIC; + break; + case Typeface.BOLD_ITALIC: + style = FONT_BOLD_ITALIC; + break; + default: + style = FONT_REGULAR; + } + } + return style; } /** @@ -257,8 +319,7 @@ static String pullFontPathFromTheme(Context context, int styleAttrId, int attrib theme.resolveAttribute(styleAttrId, value, true); final TypedArray typedArray = theme.obtainStyledAttributes(value.resourceId, new int[]{attributeId}); try { - String font = typedArray.getString(0); - return font; + return typedArray.getString(0); } catch (Exception ignore) { // Failed for some reason. return null; @@ -310,6 +371,14 @@ static String pullFontPathFromTheme(Context context, int styleAttrId, int subSty return null; } + public static String pullFontPathFromInherentFontPath(String fontPath, String fontType) { + return String.format(fontPath, fontType); + } + + public static boolean isInherentFontPath(String fontPath) { + return fontPath.contains("%s"); + } + private static Boolean sToolbarCheck = null; /** diff --git a/calligraphy/src/main/res/values/attrs.xml b/calligraphy/src/main/res/values/attrs.xml index 02c6672..5ca5fa6 100644 --- a/calligraphy/src/main/res/values/attrs.xml +++ b/calligraphy/src/main/res/values/attrs.xml @@ -1,4 +1,7 @@ + + + \ No newline at end of file diff --git a/releases/calligraphy-release.aar b/releases/calligraphy-release.aar new file mode 100644 index 0000000..a1140cc Binary files /dev/null and b/releases/calligraphy-release.aar differ