Android中App控制字体大小

Android中App字体不随系统字体大小的改变而改变

通常是在Application或Activity中复写getResources方法 ,下面的代码就实现了app字体不随系统字体大小改变.

	override fun getResources(): Resources {
        val res = super.getResources()
        if(res != null && res.configuration.fontScale != 1f){
            val config = res.configuration
            config.setToDefaults()
            if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 ){
                createConfigurationContext(config)
            }else
              res.updateConfiguration(config, res.displayMetrics)

        }
        return super.getResources()
    }

还可以将textView的单位设置为dp,这样也不会跟随系统字体大小改变,但是这里有个不好的地方,如果app中要求可以调节app全局的字体大小功能,这时候用dp作为单位就不太好了.

一般上面重写getResources函数,是在app启动的时候才会生效,假设app在运行的时候~用户跑去系统设置里更改字体大小,这时候上面的配置不就不会生效了,而app里的文字会跟着系统设置的字体大小而改变. 怎么解决呢? 重写Application的onConfigurationChanged函数做监听操作,当系统字体大小发生变化,会触发这个函数的调用,所以可以在该函数内重启应用或主Activity,使得上面的getResources会被调用,从而app里的文字不就不会跟着系统设置的字体大小而改变

	@Override
    public void onConfigurationChanged(Configuration newConfig) {

        if(newConfig.fontScale > 1){
            Intent intent = new Intent(this, MainActivity.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            startActivity(intent);
        }
        super.onConfigurationChanged(newConfig);
    }

遇到的问题:

  1. 在Android7.0中,调用Configuration类的setToDefaults函数,会使得Dialog弹框不显示(半透明背景显示),这是因为在Android7.0中,Configuration类的setToDefaults函数内将screenWidthDp和screenHeightDp都置为0 (SCREEN_WIDTH_DP_UNDEFINED和SCREEN_HEIGHT_DP_UNDEFINED的值都为0), 从而造成dialog显示不了,怎么解决? 不调用setToDefaults函数,而单独设置Configuration类的属性,例如需要设置fontScale,代码如下

    	override fun getResources(): Resources {
        	val res = super.getResources()
        	if(res != null && res.configuration.fontScale != 1f){
            	val config = res.configuration
            	config.fontScale = 1f
            	if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 ){
                	createConfigurationContext(config)
            	}else
              	res.updateConfiguration(config, res.displayMetrics)
        	}
        return super.getResources()
    }
    
  2. 在Android7.x中,重写getResources并不能使得app里的文字不会跟着系统设置的字体大小而改变,需要重写activity的attachBaseContext才能生效,代码如下

    	override fun attachBaseContext(newBase: Context?) {
    
        	if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N) {
            	val res = newBase?.getResources()
            	val config = res?.configuration
            	config?.fontScale = 1
            	val newContext = newBase?.createConfigurationContext(config)
            	super.attachBaseContext(newContext)
            	return
        	}
        	super.attachBaseContext(newBase)
    	}
    

app中要求可以调节app全局的字体大小功能实现

通过设置configuration类的fontScale来控制字体的缩放比例,从而实现app全局的字体大小控制. 建议一般标准字体按照 “1” 这个值来取,大字体可以设置为1.3.

	fun setFontScale(fontScale: Float) {
        val res = resources
        val configuration = res.configuration
        configuration.fontScale = fontScale
        res.updateConfiguration(configuration, res.displayMetrics)
    }

注意:通过代码取当前页面textView,其字体大小值的单位是px,需要转化为sp,才能乘以上面的fontScale,从而拿到放大之后的字体大小值

Autosizing TextViews

当app文字大小需要根据系统文字大小,或app中设置fontScale值进行调整时,可能会导致TextView文字溢出,部分不能显示的问题,因为TextView是无法根据字体大小来动态控制宽高的,所以这时候Android8.0新增用来动态改变TextView字体大小的新特性 Autosizing TextViews 就上场了,Autosizing TextViews使得TextView可以动态调整其文字的大小,使得不会出现溢出或部分显示这种问题.

	<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center">

    <TextView
        android:layout_width="340dp"
        android:layout_height="50dp"
        android:background="@drawable/shape_bg_008577"
        android:gravity="center_vertical"
        android:maxLines="1"
        android:text="Autosizing TextViews 用来动态改变TextView字体大小"
        android:textSize="18sp"
        android:autoSizeTextType="uniform"
        android:autoSizeMaxTextSize="18sp"
        android:autoSizeMinTextSize="10sp"
        android:autoSizeStepGranularity="1sp"/>
	</LinearLayout>

主要通过上面4个auto开头的属性来控制,具体属性意义自行查阅官方文档.当需要兼容8.0以下设备,则需要用AppCompatTextView代替TextView,并且上面几个属性的命名空间需要用app命名空间.

	<android.support.v7.widget.AppCompatTextView
        android:layout_width="wrap_content"
        android:layout_height="@dimen/dimen_size_30"
        android:text="Autosizing TextViews 用来动态改变TextView字体大小"
        app:autoSizeTextType="uniform"
        app:autoSizeMaxTextSize="@dimen/textsize_16"
        app:autoSizeMinTextSize="@dimen/textsize_12"
        android:autoSizeStepGranularity="@dimen/textsize_2"/>

注意: 在AppCompatTextView使用android命名空间的auto开头的属性," 动态改变TextView字体大小 " 无效果

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章