单个自定义 TextView 的多种字体

Multiple fonts to a single custom TextView

我们如何在单个自定义中使用不同风格的 Roboto(或任何其他)字体(Roboto-Regular、Roboto-Thin、Roboto-Bold 等)TextView

描述了一种以编程方式执行此操作的方法here。但是,如果我们想使用 XML.

更改样式,该如何实现呢?

可以使用这样的自定义属性来完成吗?

<com.project.abc.customviews.XYZTextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Welcome"
        app:type="thin" />

我不想为每种类型创建不同的 java 文件。 here 描述了另一种方法,但这存在内存问题。寻找好的解决方案。

我是这样实现的:

  1. 创建了自定义 TextView

    public class CaptainTextView extends TextView {
    private HashMap<String, Typeface> mTypefaces;
    
    public CaptainTextView(Context context) {
        super(context);
    }
    
    public CaptainTextView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    super(context, attrs, defStyleAttr);
    if (mTypefaces == null) {
        mTypefaces = new HashMap<>();
    }
    
    if (this.isInEditMode()) {
        return;
    }
    
    final TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.CaptainTextView);
    if (array != null) {
        final String typefaceAssetPath = array.getString(
            R.styleable.CaptainTextView_customTypeface);
    
        if (typefaceAssetPath != null) {
            Typeface typeface;
    
            if (mTypefaces.containsKey(typefaceAssetPath)) {
                typeface = mTypefaces.get(typefaceAssetPath);
            } else {
                AssetManager assets = context.getAssets();
                typeface = Typeface.createFromAsset(assets, typefaceAssetPath);
                mTypefaces.put(typefaceAssetPath, typeface);
            }
    
            setTypeface(typeface);
        }
        array.recycle();
    }
    }
    
    public CaptainTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        if (mTypefaces == null) {
            mTypefaces = new HashMap<>();
        }
    
        if (this.isInEditMode()) {
            return;
        }
    
        final TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.CaptainTextView);
        if (array != null) {
            final String typefaceAssetPath = array.getString(
                R.styleable.CaptainTextView_customTypeface);
    
            if (typefaceAssetPath != null) {
                Typeface typeface;
    
                if (mTypefaces.containsKey(typefaceAssetPath)) {
                    typeface = mTypefaces.get(typefaceAssetPath);
                } else {
                    AssetManager assets = context.getAssets();
                    typeface = Typeface.createFromAsset(assets, typefaceAssetPath);
                    mTypefaces.put(typefaceAssetPath, typeface);
                }
    
                setTypeface(typeface);
            }
            array.recycle();
        }
    }
    }
    
  2. 声明了自定义属性

    <resources>
    <declare-styleable name="CaptainTextView">
        <attr name="customTypeface" format="string" />
    </declare-styleable>
    </resources>
    
  3. 用于XML

    <com.project.captain.customviews.CaptainTextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Welcome"
        android:textSize="16sp"
        android:textStyle="bold"
        app:customTypeface="fonts/Roboto-Thin.ttf" />
    

瞧!