开源项目Plaid学习(三)FontTextView

本章及后续几章主要学习Plaid里面一系列自定义的Textview。大体来说,是这样:
TextView->FontTextView->BaselineGridTextView->AuthorTextView
...BaselineGridTextView->DynamicTypeTextView

FontTextView

/**
 * Extension to TextView that adds support for custom fonts.
 */
public class FontTextView extends TextView {


    public FontTextView(Context context) {
        super(context);
        init(context, null);
    }

    public FontTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public FontTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    public FontTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.FontTextView);

        if (a.hasValue(R.styleable.FontTextView_android_textAppearance)) {
            final int textAppearanceId = a.getResourceId(R.styleable
                            .FontTextView_android_textAppearance,
                    android.R.style.TextAppearance);
            TypedArray atp = getContext().obtainStyledAttributes(textAppearanceId,
                    R.styleable.FontTextAppearance);
            if (atp.hasValue(R.styleable.FontTextAppearance_font)) {
                setFont(atp.getString(R.styleable.FontTextAppearance_font));
            }
            atp.recycle();
        }

        if (a.hasValue(R.styleable.FontTextView_font)) {
            setFont(a.getString(R.styleable.FontTextView_font));
        }
        a.recycle();
    }

    public void setFont(String font) {
        setPaintFlags(getPaintFlags() | Paint.ANTI_ALIAS_FLAG);
        setTypeface(FontUtil.get(getContext(), font));
    }
}

这个Custome View只做一件事情,就是支持设置字体。此外,还需要两个res/values目录下的xml文件来自定义属性(主要是font属性要处理,至于textview的基础属性,可以直接用,因为父类会自己提取然后处理):
attrs_font.xml文件:



    
    
        
        
        
        
    

attrs_font_text_view.xml文件:



    
        
        
    

再回过来看FontTextView的代码,可以看到有4个构造函数,参数是Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes这几个,逐渐增多。
查阅资料可知,第四个初始函数是API21加上的,参考官方文档:

public View (Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
Added in API level 21
Perform inflation from XML and apply a class-specific base style from a theme attribute or style resource. This constructor of View allows subclasses to use their own base style when they are inflating.
When determining the final value of a particular attribute, there are four inputs that come into play:

  1. Any attribute values in the given AttributeSet.
  2. The style resource specified in the AttributeSet (named "style").
  3. The default style specified by defStyleAttr.
  4. The default style specified by defStyleRes.
  5. The base values in this theme.

Each of these inputs is considered in-order, with the first listed taking precedence over the following ones. In other words, if in the AttributeSet you have supplied , then the button's text will always be black, regardless of what is specified in any of the styles.
Parameters

  • context: The Context the view is running in, through which it can access the current theme, resources, etc.
  • attrs: The attributes of the XML tag that is inflating the view.
  • defStyleAttr: An attribute in the current theme that contains a reference to a style resource that supplies default values for the view. Can be 0 to not look for defaults.
  • defStyleRes: A resource identifier of a style resource that supplies default values for the view, used only if defStyleAttr is 0 or can not be found in the theme. Can be 0 to not look for defaults.

文档说的很清楚,def在这里的意思是default,也就是指定默认的属性,如果没有的话就用0。
这里的代码并没有设置默认style,所以其实构造都是用的init函数,这也是很多自定义view为了省事采用的方法,毕竟自己用不需要搞的太麻烦。
这里自定义的方式也值得注意,并没有放在一个xml文件,而是用了两个xml文件。attrs_font_text_view.xml这个文件比较好理解,就是说这个控件有font和textAppearance两种属性。带有android的属性,就是支持这个属性的意思,可以直接用而不需要自己管。
光从这个FontTextView的角度来看,一个attrs_font_text_view.xml已经够了,为什么要再弄一个attrs_font.xml呢?
init函数代码分析:先是读FontTextView的属性,然后判断是不是有android:textAppearance属性,假如有,那么读取资源,然后再套到FontTextAppearance里,然后再提取font设置一次。之后再直接用FontTextView提取font设置一次。
因此,FontTextAppearance并不会直接出现在其他地方,唯一的作用是可以把font写到style里面。
例如:


然后在styles里面:


这么折腾也是醉了。换我的话直接加个font属性就行了。

字体是通过FontUtil来查找的:

/**
 * Adapted from github.com/romannurik/muzei/
 * 

* Also see https://code.google.com/p/android/issues/detail?id=9904 */ public class FontUtil { private FontUtil() { } private static final Map sTypefaceCache = new HashMap<>(); public static Typeface get(Context context, String font) { synchronized (sTypefaceCache) { if (!sTypefaceCache.containsKey(font)) { Typeface tf = Typeface.createFromAsset( context.getApplicationContext().getAssets(), "fonts/" + font + ".ttf"); sTypefaceCache.put(font, tf); } return sTypefaceCache.get(font); } } public static String getName(@NonNull Typeface typeface) { for (Map.Entry entry : sTypefaceCache.entrySet()) { if (entry.getValue() == typeface) { return entry.getKey(); } } return null; } }

这个工具类也很简单,就是实现字符映射对应的字体库。

小结

本来想挑一个最简单的自定义View,没想到写下来也这么长了。不过麻雀虽小,五脏俱全。这个View看似简单,却包括了一些很重要的知识,尤其是自定义属性的处理。
按照目前这个进度,Plaid这个App写个几十篇没问题啊……感觉就像找到一座金矿,可以挖好久。

你可能感兴趣的:(开源项目Plaid学习(三)FontTextView)