美文网首页Android开发
源码阅读之TextView(1)--XMLTypefaceAtt

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

作者: 小鹿啊小鹿 | 来源:发表于2020-12-22 16:58 被阅读0次

    导读:本文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<String, Typeface> 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)--XMLTypefaceAtt

        本文链接:https://www.haomeiwen.com/subject/alhsnktx.html