Android 为什么设置系统字体,应用字体会根据系统字体改变?

为什么设置系统字体,应用中字体会根据系统字体改变

设置系统字体显示大小后,应用中的字体也根据也跟随系统设置而变化,这样是不是之前写好的整个布局就有可能乱了。

拿TextView源码看下面setTextSize源码看下设置字体细节

/**
*  unit 设置字体的单位 比如 sp,px,dp等等
*  size  字体大小
**/
public void setTextSize(int unit, float size) {
        if (!isAutoSizeEnabled()) {
            setTextSizeInternal(unit, size, true /* shouldRequestLayout */);
        }
    }

继续往下看

    private void setTextSizeInternal(int unit, float size, boolean shouldRequestLayout) {
        Context c = getContext();
        Resources r;
        // 获取Resources 对象,当前View没有就获取系统的一般当前view都会有
        if (c == null) {
            r = Resources.getSystem();
        } else {
            r = c.getResources();
        }
        // 将设置的字体大小根据 unit 单位和DisplayMetrics进行换算
        setRawTextSize(TypedValue.applyDimension(unit, size, r.getDisplayMetrics()),
                shouldRequestLayout);
    }

继续看下TypedValue.applyDimension() 如何计算字体大小的

   // 字体换算方法
    
     public static float applyDimension(int unit, float value,
                                       DisplayMetrics metrics)
    {
        switch (unit) {
        case COMPLEX_UNIT_PX:
            return value;
        case COMPLEX_UNIT_DIP:
            return value * metrics.density;
        case COMPLEX_UNIT_SP:
            return value * metrics.scaledDensity;
        case COMPLEX_UNIT_PT:
            return value * metrics.xdpi * (1.0f/72);
        case COMPLEX_UNIT_IN:
            return value * metrics.xdpi;
        case COMPLEX_UNIT_MM:
            return value * metrics.xdpi * (1.0f/25.4f);
        }
        return 0;
    }

可以看出,根据不同unit计算出来的字体大小不一样,px是不需要就算,,dip是根据density 去计算,sp是根据 scaledDensity计算字体大小,pt是根据xdpi 和一个指定指数计算等等。当改变系统现实大小的时候,参与字体计算的值只要有变化都会改变字体大小。

通过改变系统字体大小,打log看以DisplayMetrics中的值只有scaledDensity 这个值有变化 (可以参考) 所以只要我们在系统字体改变的时候,控制这个值不要改变就可以了,那这个值是在那里赋值?通过一顿瞎点,点到了ResourceImpl这个类里边的updateConfiguration
方法,并且在方法中看到了这个字段的赋值

 public void updateConfiguration(Configuration config, DisplayMetrics metrics,
                                    CompatibilityInfo compat) {
     
     //.....
     
                // Protect against an unset fontScale.
                mMetrics.scaledDensity = mMetrics.density *
                        (mConfiguration.fontScale != 0 ? mConfiguration.fontScale : 1.0f);

           // .....
    }

原来scaledDensity 是fontScale和density计算得来的,density 改变系统字体是不会变化的,那就是fontScale这玩意导致的,那这玩意是那的,通过一顿点击发现是Configuration类的一个public 字段,那这fontScale这个字段系统是什么时候设置的呢?一顿点和排查最后找到了ActivityManageService中的updateFontScaleIfNeeded的方法

private void updateFontScaleIfNeeded(@UserIdInt int userId) {
       //.....
        synchronized (this) {
            if (getGlobalConfiguration().fontScale == scaleFactor) {
                return;
            }
             //.....
}

再看下这个方法是哪里调用的,又是一通乱点发现是在ActivityManageService中的一个内部类FontScaleSettingObserver
中的一个onChange方法中调用的,

 private final class FontScaleSettingObserver extends ContentObserver {
     
        @Override
        public void onChange(boolean selfChange, Uri uri, @UserIdInt int userId) {
            if (mFontScaleUri.equals(uri)) {
                updateFontScaleIfNeeded(userId);
            } else if (mHideErrorDialogsUri.equals(uri)) {
                synchronized (ActivityManagerService.this) {
                    updateShouldShowDialogsLocked(getGlobalConfiguration());
                }
            }
        }
    }

我猜这个肯定是一个观察者模式,观察到系统配置有相关变化,随后去设置一系列的值,那我们也可以手动的改变这个fontScale值为基准的,不让其随着系统改变而改变、
网上找了段代码,在activity中添加就可以了,源码也不知道分析有误没,如果有误欢迎来提

 @Override
    public Resources getResources() {
        Resources resources = super.getResources();
        Configuration configuration =new Configuration();
        configuration.setToDefaults();
        resources.updateConfiguration(configuration,resources.getDisplayMetrics());
        return resources;
    }
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值