Android 另一种更换字体的方式

碎碎唸

不知道什么时候,自己项目中的TextView会自己变成AppCompatTextView。因为项目时间赶。不是特别的重视这个问题。再后来遇到了一个需求,那就是需要全局更改项目中的数字字体。这个时候我又重新开始思考AppCompatTextView的问题。

因为在之前的项目中更换过字体。只需自己继承自TextView,然后在构造方法中设置一下字体。就可以完成自定义字体了。

public class FontTextView extends AppCompatTextView {


    public FontTextView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        setTypeface(TypeFaceHelper.getInstance().getFineTypeFace());
    }

}

因为之前的项目是在项目早期,就已经决定使用自定义字体。所以我们当初规定所有的文字控件都是以FontTextView 但是,现在我们的项目进行着迭代了很久,如果继续使用这样方式工作量会很大,而且容易出错。所以我们需要一种比较简单的方式,来完成这件事。在开工之前,我希望能够先处理以下两个问题。

  1. 为什么TextView会被替换成AppCompatTextView呢?
  2. 能不能将AppCompatTextView替换成我们的FontTextView呢?

查找

我开始尝试的去寻找在什么时候,我们的TextView被替换了。我们可以在AppCompatTextView的构造方法中下个断点。这样当AppCompatTextView 被创建的话,我们就可以知道什么时候它被创建了。 下面是它的函数调用栈。

从上面的函数调用栈中,在我们xml解析完成之后,然后会调用createView这个方法来创建view。我们重点查看一下createView这个方法

switch (name) {
            case "TextView":
                view = createTextView(context, attrs);
                verifyNotNull(view, name);
                break;
            case "ImageView":
                view = createImageView(context, attrs);
                verifyNotNull(view, name);
                break;
            case "Button":
                view = createButton(context, attrs);
                verifyNotNull(view, name);
                break;
            case "EditText":
                view = createEditText(context, attrs);
                verifyNotNull(view, name);
                break;
            case "Spinner":
                view = createSpinner(context, attrs);
                verifyNotNull(view, name);
                break;
            case "ImageButton":
                view = createImageButton(context, attrs);
                verifyNotNull(view, name);
                break;
            case "CheckBox":
                view = createCheckBox(context, attrs);
                verifyNotNull(view, name);
                break;
            case "RadioButton":
                view = createRadioButton(context, attrs);
                verifyNotNull(view, name);
                break;
            case "CheckedTextView":

这里会根据xml解析出来的标签,从而创建对应的控件。具体查看一下TextView在是什么时候被创建.

 @NonNull
    protected AppCompatTextView createTextView(Context context, AttributeSet attrs) {
        return new AppCompatTextView(context, attrs);
    }

这样我们就已经知道了,我们的TextViewxml解析完成之后会被替换成AppCompatTextView了。那么现在如果能够将AppCompatTextView替换成我们的FontTextView就能完成自定义字体了。

替换

通过上面的函数栈,可以发现我onCreateViewAppCompatDelegateImpl里面的一个方法。

那么我们能不能重写这个方法,然后将返回值改成我们特定的FontTextView呢?

答案是一定的,但是这里有一个需要注意的地方。因为AppCompatDelegateImpl是包访问权限,正常情况下你是没有访问权限的。但是你可以把你的包名改成和它一致,这样你就具有访问权限了。


//包名一致
package androidx.appcompat.app;



public class FontTextDelegate extends AppCompatDelegateImpl {

    public FontTextDelegate(Context context, Window window, AppCompatCallback callback) {
        super(context, window, callback);
    }


    @Override
    public View createView(View parent, String name, @NonNull Context context, @NonNull AttributeSet attrs) {
        if (name.equals("TextView")) {
            return new FontTextView(context, attrs);
        }
        return super.createView(parent, name, context, attrs);
    }

}


我们已经重写了AppCompatDelegateImpl的方法了,现在只需要查看AppCompatDelegateImpl在什么时候被初始换。然后替换成我们重写后的子类即可完成目标了。还是一样的方式,在AppCompatDelegateImpl构造方法中设一个断点。

通过函数调用栈可以看到,AppCompatDelegateImpl是在AppCompatActivity中的getDelegate初始换的,那么我们只需要重写我们项目中的ActivitygetDelegate方法。就可以替换成AppCompatDelegateImpl了。

以上!

最后

如果你看到了这里,觉得文章写得不错就给个赞呗!欢迎大家评论讨论!如果你觉得那里值得改进的,请给我留言。一定会认真查询,修正不足,定期免费分享技术干货。谢谢!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值