源码阅读之TextView(1)--XMLTypefaceAttr

导读:本文TextView基于android-28版本,代码行数12551.

► 包

  • TextView位于包 android.widget;
    该包下包含很多常用的UI控件,例如Switch、ScrollView、ListView等等。

► 父类

  • 继承自View
    View的源码阅读链接:敬请期待
  • 实现了ViewTreeObserver.OnPreDrawListener
    在将要绘制视图树时要调用的回调方法。 此时,树中的所有视图均已测量并指定了框架。 可以使用它来调整滚动范围,甚至可以在绘制之前请求新的布局。
 /**
     * Interface definition for a callback to be invoked when the view tree is about to be drawn.
     */
    public interface OnPreDrawListener {
        /**
         * Callback method to be invoked when the view tree is about to be drawn. At this point, all
         * views in the tree have been measured and given a frame. Clients can use this to adjust
         * their scroll bounds or even to request a new layout before drawing occurs.
         *
         * @return Return true to proceed with the current drawing pass, or false to cancel.
         *
         * @see android.view.View#onMeasure
         * @see android.view.View#onLayout
         * @see android.view.View#onDraw
         */
        public boolean onPreDraw();
    }

► 结构

image.png
· XMLTypefaceAttr

这个结构块包含了@IntDef注解,@Retention注解以及@interface注解

XMLTypefaceAttr是TextView中的一个由@interface 定义的自定义注解,其中初始化了四种类别,分别为DEFAULT_TYPEFACE、SANS、SERIF、MONOSPACE。
在xml中通过“typeface”属性调用。

 // Enum for the "typeface" XML parameter.
    // TODO: How can we get this from the XML instead of hardcoding it here?
    /** @hide */
    @IntDef(value = {DEFAULT_TYPEFACE, SANS, SERIF, MONOSPACE})
    @Retention(RetentionPolicy.SOURCE)
    public @interface XMLTypefaceAttr{}
    private static final int DEFAULT_TYPEFACE = -1;
    private static final int SANS = 1;
    private static final int SERIF = 2;
    private static final int MONOSPACE = 3;
❶ @IntDef
@IntDef(value = {DEFAULT_TYPEFACE, SANS, SERIF, MONOSPACE})

表示整数类型的带注释元素, 代表逻辑类型,并且其值应为显式命名的常量之一。 如果IntDef#flag()属性设置为true,则可以组合多个常量。也就是flag这个值决定了是否常量可以被当成一个标识,或仅可作为枚举值使用。
例如下两种写法:

/**此时定义的常量值仅作为枚举值使用**/
 @IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})

/**此时定义的常量值可作为标识符使用**/
@IntDef(
      flag = true,
      value = {NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})
❷ @Rentention
 @Retention(RetentionPolicy.SOURCE)

表示带有注释类型的注释将保留多长时间。 如果注释类型声明上没有保留注释,则保留策略默认为RetentionPolicy.CLASS。
此处RetentionPolicy.SOURCE表示当前定义将在编译之后被丢弃。
此外还有其他两种策略分别为:
RetentionPolicy.CLASS :注释将由编译器记录在类文件中,但VM不必在运行时保留它们。
RetentionPolicy. RUNTIME:注释将由编译器记录在类文件中,并在运行时由VM保留,因此可以通过反射方式读取它们。
另外只有当元注释类型直接用于注释时,保留元注释才有效。 如果将元注释类型用作其他注释类型的成员类型,则无效。

SOURCE:在源文件中有效,编译过程中会被忽略
CLASS:随源文件一起编译在class文件中,运行时忽略
RUNTIME:在运行时有效
参考:https://juejin.cn/post/6844903949233815566

❸ XMLTypefaceAttr的使用
  • 单独看此块代码,只有当typeface和familyName都为null时,才会进入typefaceIndex的判断逻辑。

    /**
     * Sets the Typeface taking into account the given attributes.
     *设置字体时要考虑的字体属性
     * @param typeface a typeface
     * @param familyName family name string, e.g. "serif"
     * @param typefaceIndex an index of the typeface enum, e.g. SANS, SERIF.
     * @param style a typeface style
     * @param weight a weight value for the Typeface or -1 if not specified.
     */
    private void setTypefaceFromAttrs(@Nullable Typeface typeface, @Nullable String familyName,
            @XMLTypefaceAttr int typefaceIndex, @Typeface.Style int style,
            @IntRange(from = -1, to = Typeface.MAX_WEIGHT) int weight) {
        if (typeface == null && familyName != null) {
            // Lookup normal Typeface from system font map.
            final Typeface normalTypeface = Typeface.create(familyName, Typeface.NORMAL);
            resolveStyleAndSetTypeface(normalTypeface, style, weight);
        } else if (typeface != null) {
            resolveStyleAndSetTypeface(typeface, style, weight);
        } else {  // both typeface and familyName is null.
            switch (typefaceIndex) {
                case SANS:
                    resolveStyleAndSetTypeface(Typeface.SANS_SERIF, style, weight);
                    break;
                case SERIF:
                    resolveStyleAndSetTypeface(Typeface.SERIF, style, weight);
                    break;
                case MONOSPACE:
                    resolveStyleAndSetTypeface(Typeface.MONOSPACE, style, weight);
                    break;
                case DEFAULT_TYPEFACE:
                default:
                    resolveStyleAndSetTypeface(null, style, weight);
                    break;
            }
        }
    }
  • 结合TextView整个代码来看,setTypefaceFromAttrs涉及的逻辑大概如下:
    image.png

    当TextView所涉及到的关于属性的数值传递到setTypefaceFromAttrs方法时,(typeface即对应TextView中的同名属性,familyName即对应TextView属性fontFamily),对以下三种情况:
    typeface为null,fontName不为null
    • 查看Typeface的源码可以发现系统事先初始化了由fontName和Typeface组成的静态map集合,
      当typeface为null,但fontName不为null,则默认向这个map集合中获取属性为Normal的Typeface。
static final Map sSystemFontMap;

......
if (typeface == null && familyName != null) {
           // Lookup normal Typeface from system font map.
           final Typeface normalTypeface = Typeface.create(familyName, Typeface.NORMAL);
           resolveStyleAndSetTypeface(normalTypeface, style, weight);
   }

  • resolveStyleAndSetTypeface方法
 private void resolveStyleAndSetTypeface(@NonNull Typeface typeface, @Typeface.Style int style,
            @IntRange(from = -1, to = Typeface.MAX_WEIGHT) int weight) {
//@IntRange限制输入的weight元素范围从-1至MAX_WEIGHT(1000),
//weight对应TextView布局中的textFontWeight属性(1-1000)表示字的厚度。
        if (weight >= 0) {
            weight = Math.min(Typeface.MAX_WEIGHT, weight);
            final boolean italic = (style & Typeface.ITALIC) != 0;
//创建最符合指定的现有字体以及指定的粗细和斜体样式的字体对象
            setTypeface(Typeface.create(typeface, weight, italic));
        } else {
//创建最符合指定的现有字体以及指定的粗细和斜体样式的字体对象
            setTypeface(typeface, style);
        }
    }

typeface不为null,直接调用resolveStyleAndSetTypeface方法创建字体相关属性

if (typeface != null) {
     resolveStyleAndSetTypeface(typeface, style, weight);
 } 

typeface和fontName都为null
typefaceIndex在TextAppearanceAttributes静态内部类的构造方法中设置默认值-1,对应xml中typeface在枚举变量中的位置

switch (typefaceIndex) {
                case SANS:
                    resolveStyleAndSetTypeface(Typeface.SANS_SERIF, style, weight);
                    break;
                case SERIF:
                    resolveStyleAndSetTypeface(Typeface.SERIF, style, weight);
                    break;
                case MONOSPACE:
                    resolveStyleAndSetTypeface(Typeface.MONOSPACE, style, weight);
                    break;
                case DEFAULT_TYPEFACE:
                default:
                    resolveStyleAndSetTypeface(null, style, weight);
                    break;
            }

你可能感兴趣的:(源码阅读之TextView(1)--XMLTypefaceAttr)