本篇文章已授权微信公众号 guolin_blog(郭霖)独家发布

前言

虽然去年写的一篇文章【一种非常好用的Android屏幕适配】就包含字体大小适配,但那篇文章讲的是根据不同屏幕尺寸来适配字体大小的,接下来我要聊的是字体大小适配中的其他几种场景。

场景一

有这样一个需求,界面上需要显示一个标题文本,但是该标题的文案长度是不固定的,要求标题的文案全部显示出来,不能用省略号显示,并且标题所占的宽高是固定的。例如标题的文案为 “这是标题,该标题的名字比较长,产品要求不换行全部显示出来”,如下图所示,第一个为不符合需求的标题,第二个为符合需求的标题。

也就是说TextView控件的宽高需要固定,然后根据标题的文案长度动态改变字体大小,也就是上图第二个标题的效果。那是怎么实现的呢?

以前的做法一般是测量TextView文本所占的宽度与TextView控件的宽度对比,动态改变TextView的字体大小,写起来即麻烦又耗性能。但是现在不用这么麻烦了,Android 8.0 新增了用来动态改变TextView字体大小的新特性 Autosizing TextViews,只需要简单设置一下属性即可。

例如上图中符合需求的效果可以这样写:

xml 方式

xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:gravity="center">

android:layout_width="340dp"

android:layout_height="50dp"

android:background="@drawable/shape_bg_008577"

android:gravity="center_vertical"

android:maxLines="1"

android:text="这是标题,该标题的名字比较长,产品要求不换行全部显示出来"

android:textSize="18sp"

android:autoSizeTextType="uniform"

android:autoSizeMaxTextSize="18sp"

android:autoSizeMinTextSize="10sp"

android:autoSizeStepGranularity="1sp"/>

可以看到TextView控件多了如下属性:

autoSizeTextType:设置TextView是否支持自动改变字体大小,none表示不支持,uniform表示支持。

autoSizeMinTextSize:最小字体大小,例如设置为10sp,表示文字最多只能缩小到10sp。

autoSizeMaxTextSize:最大字体大小,例如设置为18sp,表示文字最多只能放大到18sp。

autoSizeStepGranularity:缩放粒度,即每次字体大小变化的数值,例如设置为1sp,表示每次缩小或放大的值为1sp。

上面的只是针对于8.0的设备有效,如果想要兼容8.0以下设备,则需要用AppCompatTextView代替TextView,并且上面几个属性的命名空间需要用app命名空间。如下:

xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="match_parent"

android:layout_height="match_parent"

xmlns:app="http://schemas.android.com/apk/res-auto"

android:gravity="center">

android:layout_width="340dp"

android:layout_height="50dp"

android:background="@drawable/shape_bg_008577"

android:gravity="center_vertical"

android:maxLines="1"

android:text="这是标题,该标题的名字比较长,产品要求不换行全部显示出来"

android:textSize="18sp"

app:autoSizeTextType="uniform"

app:autoSizeMaxTextSize="18sp"

app:autoSizeMinTextSize="10sp"

app:autoSizeStepGranularity="1sp"/>

肯定很多人说 “为什么自己写的时候不用AppCompatTextView也能兼容8.0以下设备呢?”,那是因为你当前的xml文件对应的Activity继承的是AppCompatActivity,如果继承的是Activity或FragmentActivity是不能达到兼容的。这一点其实官方文档 Autosizing TextViews 也没有说清楚,导致很多人误解了,各位可以自己验证下。

动态编码方式

使用 TextViewCompat 的setAutoSizeTextTypeWithDefaults()方法设置TextView是否支持自动改变字体大小,setAutoSizeTextTypeUniformWithConfiguration()方法设置最小字体大小、最大字体大小与缩放粒度。如下所示:

TextView tvText = findViewById(R.id.tv_text);

TextViewCompat.setAutoSizeTextTypeWithDefaults(tvText,TextViewCompat.AUTO_SIZE_TEXT_TYPE_UNIFORM);

TextViewCompat.setAutoSizeTextTypeUniformWithConfiguration(tvText,10,18,1, TypedValue.COMPLEX_UNIT_SP);

setAutoSizeTextTypeWithDefaults()

参数1为需要动态改变字体大小的TextView,参数2为是否支持自动改变字体大小的类型,AUTO_SIZE_TEXT_TYPE_UNIFORM表示支持,AUTO_SIZE_TEXT_TYPE_NONE表示不支持。

setAutoSizeTextTypeUniformWithConfiguration()

参数1为需要动态改变字体大小的TextView,参数2、3、4分别为最小字体大小、最大字体大小与缩放粒度,参数5为参数2、3、4的单位,例如sp 、dp、px等。

同样,如果要兼容8.0以下设备,要么在xml中用AppCompatTextView代替TextView,要么当前Activity继承AppCompatActivity。

小结

Autosizing TextViews是Android 8.0 新增的特性,可以用来动态改变TextView字体大小。如果要兼容8.0以下设备,则需要满足以下2个条件中的其中一个。

在xml中用AppCompatTextView代替TextView,并且上面几个属性的命名空间用app命名空间。

当前Activity继承AppCompatActivity,而不是Activity或FragmentActivity。

Autosizing TextViews更多属性请参考 Autosizing TextViews

场景二

很多人肯定遇到过这种情况,测试扔个图片过来,然后说怎么运行在这个测试机后下面的内容都挡住了(如下右图,左图为正常情况),你不是说做了屏幕适配的吗?然后你拿测试的手机一看,设置里面竟然选了 特大 字体。

嗯... 经过这么一看基本就知道什么问题了。原因是你在xml文件写死了控件的高度,并且TextView的字体单位用的是sp,这种情况下到手机设置中改变字体大小,那么界面中的字体大小就会随系统改变。

那么我们应该怎么解决这个问题呢?这时候我们可以观察下微信的做法,经过研究发现微信的字体是不会随着系统字体大小的改变而改变的,并且微信本身是有改变字体大小功能的。微信中改变字体大小后不仅字体大小改变了,控件的宽高也会跟着改变。所以可以猜到微信的字体适配是如下方式实现的:

字体大小不随系统改变

想要实现字体大小不随系统改变有两种方式:

1. xml方式

TextView的字体单位不使用sp,而是用dp。因为sp单位的字体大小会随系统字体大小的改变而改变,而dp单位则不会。

2. 动态编码方式

字体大小是否随系统改变可以通过Configuration类的fontScale变量来控制,fontScale变量默认为1,表示字体大小不随系统字体大小的改变而改变,那么我们只需要保证fontScale始终为1即可。具体代码如下,一般放在Activity的基类BaseActivity即可。

@Override

public void onConfigurationChanged(Configuration newConfig) {

super.onConfigurationChanged(newConfig);

if (newConfig.fontScale != 1) { //fontScale不为1,需要强制设置为1

getResources();

}

}

@Override

public Resources getResources() {

Resources resources = super.getResources();

if (resources.getConfiguration().fontScale != 1) { //fontScale不为1,需要强制设置为1

Configuration newConfig = new Configuration();

newConfig.setToDefaults();//设置成默认值,即fontScale为1

resources.updateConfiguration(newConfig, resources.getDisplayMetrics());

}

return resources;

}

虽然两种方式都可以解决场景二的问题,但是一般都是使用动态编码方式,原因如下:

若应用需要增加类似微信可以改变字体大小的功能,如果在xml中用的是dp单位,那么该功能将无法实现!

若需求改成字体大小需要随系统字体大小的改变而改变,只需要删掉该段代码即可。

官方推荐使用sp作为字体单位。

控件宽高尽量不要固定

原因是如果应用需要增加类似微信可以改变字体大小的功能,如果控件宽高固定的话,调大字体会导致控件显示不下,这不是我们需要的效果。

场景三

有这样一种情况,当你按照设计图的标注去写一个TextView控件的时候,宽高用的是wrap_content,也没有设置任何padding,但是运行在手机上该TextView所占的宽高却比设计图的要大。如下图所示,字体周围多了很多空白部分。

这是因为TextView本身就含有内边距造成的,那么TextView有没有属性可以去除内边距呢?答案是有的,该属性为 includeFontPadding,设置为false表示不包含字体内边距,具体代码如下:

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:background="@color/colorPrimary"

android:text="Hello"

android:textSize="50sp"

android:includeFontPadding="false"/>

运行效果如下图中的第二个“Hello”(第一个“Hello”为普通TextView),看起来好像是可以的,但是仔细看发现还是留有一点内边距的。

一般的应用可能不在乎那点内边距,但如果做的是TV上的应用就要求比较严格了,因为TV界面一般是不支持上下左右滚动的,如果设计图上的内容刚好占满屏幕,那么这些内边距就会导致个别控件显示不全。所以在这种情况下是必须要解决的,既然TextView自带属性不能解决,那就只能自定义了。具体代码如下:

import android.content.Context;

import android.content.res.TypedArray;

import android.graphics.Canvas;

import android.graphics.Paint;

import android.graphics.Rect;

import android.support.v7.widget.AppCompatTextView;

import android.util.AttributeSet;

public class NoPaddingTextView extends AppCompatTextView {

private Paint mPaint = getPaint();

private Rect mBounds = new Rect();

private Boolean mRemoveFontPadding = false;//是否去除字体内边距,true:去除 false:不去除

public NoPaddingTextView(Context context) {

super(context);

}

public NoPaddingTextView(Context context, AttributeSet attrs) {

super(context, attrs);

initAttributes(context, attrs);

}

public NoPaddingTextView(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

initAttributes(context, attrs);

}

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

if (mRemoveFontPadding) {

calculateTextParams();

setMeasuredDimension(mBounds.right - mBounds.left, -mBounds.top + mBounds.bottom);

}

}

protected void onSizeChanged(int w, int h, int oldw, int oldh) {

super.onSizeChanged(w, h, oldw, oldh);

}

protected void onDraw(Canvas canvas) {

drawText(canvas);

}

/**

* 初始化属性

*/

private void initAttributes(Context context, AttributeSet attrs) {

TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.NoPaddingTextView);

mRemoveFontPadding = typedArray.getBoolean(R.styleable.NoPaddingTextView_removeDefaultPadding, false);

typedArray.recycle();

}

/**

* 计算文本参数

*/

private String calculateTextParams() {

String text = getText().toString();

int textLength = text.length();

mPaint.getTextBounds(text, 0, textLength, mBounds);

if (textLength == 0) {

mBounds.right = mBounds.left;

}

return text;

}

/**

* 绘制文本

*/

private void drawText(Canvas canvas) {

String text = calculateTextParams();

int left = mBounds.left;

int bottom = mBounds.bottom;

mBounds.offset(-mBounds.left, -mBounds.top);

mPaint.setAntiAlias(true);

mPaint.setColor(getCurrentTextColor());

canvas.drawText(text, (float) (-left), (float) (mBounds.bottom - bottom), mPaint);

}

}

将NoPaddingTextView需要的属性定义在attr.xml文件中,如下:

布局文件中使用,如下:

xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:app="http://schemas.android.com/apk/res-auto"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:gravity="center"

android:orientation="horizontal">

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:background="@color/colorPrimary"

android:text="Hello"

android:textSize="50sp"

app:removeDefaultPadding="true"/>

运行效果如下图中的第三个“Hello”(第一个为普通TextView,第二个为加了includeFontPadding属性的TextView),完美解决!

OK!字体大小适配中最常用的三种场景都讲了,如果还有其他场景欢迎补充~

android 字体大小属于什么类型,聊聊 Android 中的字体大小适配相关推荐

  1. ppt流程图字体太小_【PPT】几种处理字体的小方法,让PPT中的字体更好看

    撰文 | 晓光 你好,这里是陈西设计之家. 我们经常设计制作PPT使用一些常规的字体,没有多余的设计,可能并不好看 那么今天,我们来讲解几种字体的处理方式,让PPT中的字体设计更加的好看. ▣ 01 ...

  2. html字体怎么设置大写,如何在html中设置字体的属性

    如何在html中设置字体的属性 发布时间:2021-06-08 17:45:33 来源:亿速云 阅读:72 作者:Leah 这篇文章给大家介绍如何在html中设置字体的属性,内容非常详细,感兴趣的小伙 ...

  3. android各目录大小,Android 基础篇 — 放不同drawable文件夹中图片的大小

    我们接着上篇文章Android 基础篇 - 不同DPI取哪个本地文件夹中的资源 讲,文末尾提到一个问题,为什么不同drawable文件夹中的图片大小在终端设备会不一样? 1 准备 在drawable- ...

  4. 【Android 修炼手册】常用技术篇 -- 聊聊 Android 的打包

    这是[Android 修炼手册]系列第 10 篇文章,如果还没有看过前面系列文章,欢迎点击 这里 查看- 预备知识 了解 android 基本开发 看完本文可以达到什么程度 了解 Android AP ...

  5. css 字体图标更改颜色_在CSS中更改字体

    css 字体图标更改颜色 CSS字体属性 (CSS font properties ) Font properties in CSS is used to define the font family ...

  6. 字体系列 (三):Xml中的字体 font ttf

    在本系列的上一篇文章中,我们对 Typeface 进行了深入的解析,还没有看过上一篇文章的朋友,建议先去阅读 Android字体系列 (二):Typeface完全解析.接下来我们看下 Google 推 ...

  7. html字体高度怎么调,当在CSS中设置字体大小时,字母的真实高度是多少?

    关于这个问题的一些背景 在金属上创建信件时,em指的是每个块的尺寸,该字母将被刻上,这个大小由资本M确定,因为它通常占用最多的空间. 现在有一天,字体开发者在计算机上创建自己的字体,而没有物理金属的限 ...

  8. win10 linux分区大小调整大小,如何在windows系统中调整分区大小(包括windows10/8/7)...

    对磁盘进行分区(尤其是Windows 10,8和7)至关重要.毕竟,通过磁盘的分区,任务和其他程序的处理可以采用更有效的路线.分区可以更轻松地整理任务并专注于重要的事情. 分区磁盘时,第一次尝试时总是 ...

  9. 字体感觉小了 引入的vant_vue-cli3中vant字体库改为本地引入

    内网项目无法引用外部cdn资源,所以需要将vant的字体库改为本地引入 相关插件:"less-loader": "^7.0.0","vant" ...

最新文章

  1. 使用squid代理时出现“The requested URL could not be retrieved”
  2. Smart/400开发上手2: COBOL批处理程序处理过程
  3. css选择器参考手册
  4. python关系运算符实例_python编程中最常用的比较运算符实例
  5. Spring 静态代理和动态代理
  6. 蓝牙抓包工具选择android,Android 蓝牙抓包
  7. 获取稳定的西刺代理IP
  8. xp框架下载官方_定制Xposed框架(干货)
  9. linux安装CacheCloud
  10. PDF文件怎么转成JPG图片?来看这几种转换方法
  11. 中兴新支点操作系统上的文件小贴士
  12. 湖北飞young使用任意路由器教程
  13. python数据分布统计_Python 数据可视化:数据分布统计图和热图
  14. c++使用制表符\t
  15. PHP面试题2021和2022面试、跳槽必备大全!
  16. 基本极限定理(切比雪夫不等式,大数定律,中心极限定理)
  17. XMind商业思维导图——市场营销!
  18. 常见界面布局之LinearLayout线性布局
  19. 使用AFNetworking
  20. 你不去PEACH区块链俱乐部太可惜了,90后的人才呀,佩服五体投地

热门文章

  1. 三步读懂对象存储-访问方式
  2. 如何修改linux文件句柄数,Linux服务器修改文件句柄数和用户最大进程数限制
  3. 春节过完了,我终于知道为什么百度不发红包了?
  4. 图像分割——线检测——拉普拉斯标定(Matlab)
  5. [单片机][cx32][填坑日记] 从AC5到AC6 flash写入功能异常
  6. 美通企业日报 | 护照含金量迎来亚洲时代;沃尔沃集团联网交通设备交付一百万台...
  7. 打造公路“头等舱”——智能座舱与交互革命进行时 | 12月8日 TF85
  8. 2022暑初二信息竞赛学习成果分享1
  9. 串口通信下连续输出Hello windows
  10. 近世代数1:映射,变换