前言: 最近公司做了横屏手持车载设备,屏幕和通常的手机屏幕差别不大,我们是按照1334*750的设计图尺寸做的,横屏适配和竖屏适配方式是不一样的,横屏的像素宽,横向布局不会太复杂,通常"match_parent"或权重就可以满足横向设计要求,但是高度就不一样了,比如设计图的高度是750px,几乎只有横向像素的一半,如果竖屏内容需要滑动显示倒无所谓了,对于车载端,主要界面偏偏都不是大篇幅的需要高度滑动展示,通常是一个屏幕刚好展示完,所以我们会借助适配框架AutoSize来按照屏幕高度来适配布局,后面新加了一个需求需要全局改变字体大小,通过百度扒拉扒拉,97%的人都说重写getResources得到resources的configuration,将configuration.fontscale值改变,嘿嘿,这简单吧!如果这样想就错了,呜呜,容我细细道来:

遇见的卡壳问题: autosize的布局适配原理也是对DisplayMetrics做相应修改,而字体大小缩放也是更新DisplayMetrics,所以,如果你重写getResources更新fontscale,那么autosize的适配必将失效,后来想既然先设置autosize后更新fontscale适配失效,那顺序反过来会怎样?反过来会怎样呢?先更新fontscale后设置autosize适配会让适配生效字体缩放失效,好了,说了半天那我们来说替代方案吧:

第一步:现在设计给了三种标准字体大小:16、18、23, 大致思路是定义字体大小属性,在attrs中定义不同字体大小属性值,现在以两种字体为例:

<!--字体大小属性-->
<attr name="text_size_15sp" format="reference|dimension"/>
<attr name="text_size_17sp" format="reference|dimension"/>

第二步:定义与三种字体对应的主题如

<style name="DayStandardTheme" parent="DayTheme">
    <item name="text_size_15sp">@dimen/standard_text_15</item>
    <item name="text_size_17sp">@dimen/standard_text_17</item>
</style>
<!--白天大字体-->
<style name="DayMiddleTheme" parent="DayTheme">
    <item name="text_size_15sp">@dimen/middle_text_15</item>
    <item name="text_size_17sp">@dimen/middle_text_17</item>
</style>
<!--白天超大字体-->
<style name="DayLargeTheme" parent="DayTheme">
    <item name="text_size_15sp">@dimen/large_text_15</item>
    <item name="text_size_17sp">@dimen/large_text_17</item>
</style>

第三步:布局文件的字体样式设置字体大小,这里强烈建议将TextView的字体样式提出来,比如我常常会这样写:

<style name="text_style_17dp_white">
        <item name="android:textColor">@color/white</item>
        <item name="android:textSize">?attr/text_size_17sp</item>
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">wrap_content</item>
    </style>

注意: 写"textSize"时使用主题属性引用: ?attr/text_size_17sp
第四步:BaseActivity里动态设置主题

//字体大小级别,1:"标准"  2:"中"  3:"大"
        int fontState=2;
        if(DayNightHelper.isDay()){
            //设置白天主题,同时考虑字体大小状态
            if(fontState==1){
                //设置标准字体大小
                setTheme(R.style.DayStandardTheme);
            }else if(fontState==2){
                //设置中号字体大小
                setTheme(R.style.DayMiddleTheme);
            }else if(fontState==3){
                //设置大号字体大小
                setTheme(R.style.DayLargeTheme);
            }
        }else{
            //设置夜晚主题,同时考虑字体大小状态
            if(fontState==1){
                //设置标准字体大小
                setTheme(R.style.NightStandardTheme);
            }else if(fontState==2){
                //设置中号字体大小
                setTheme(R.style.NightMiddleTheme);
            }else if(fontState==3){
                //设置大号字体大小
                setTheme(R.style.NightLargeTheme);
            }

备注: 可能还有人会对"@dimen/standard_text_15" 以及 "@dimen/middle_text_15"有疑问,我是这样计算的,根据三种字体大小: 16 18 23
,第二种级别字体是标准字体的1.125倍,第三种级别字体是标准字体的1.4375倍,那根据取舍便得标准、大号字体、超大号字体得dimens尺寸值:

<resources>

    <dimen name="standard_text_15">15sp</dimen>
    <dimen name="standard_text_17">17sp</dimen>
    <dimen name="middle_text_15">16.8sp</dimen>
    <dimen name="middle_text_17">19sp</dimen>
    <dimen name="large_text_15">21.5sp</dimen>
    <dimen name="large_text_17">24.4sp</dimen>
</resources>

综上,上面的例子不但能实现字体大小跟随主题切换同时也能实现日夜模式切换,但是这种方式感觉唯一不好的是自己得把每种字体的三种大小都定义在对应的主题里,同时字体的三种字体大小值都得靠自己计算,这些操作起来可能会觉得繁琐…