android 之 TextView 应用详解

1,325 阅读10分钟

写在前面:希望看到的人能指出里面的错误和不足,也帮助那些不知道的人。

我发现在工作中, TextView 的使用频率很高,所以我就编写了关于 TextView 的应用详解,这里主要是讲解使用的,不是源码分析。

说明:API23 代表对应的最低版本,如果没有标注代表在 API16 以上都可以使用。

下面将对属性进行一一讲解:

android:allowUndo API23

就是撤销,但是在手机上是不可以的,只有当连接外接键盘才可以,默认值是 true (默认支持撤销),当连接外接键盘以后,只需要按 ctrl + z 即可完成撤销。目前只有 23 以上的才支持。

android:autoLink

自动连接对应的格式,比如你填写的属性值为: phone ,那么当点击这个电话号码的时候就会自动打开拨打电话的页面;如果填写的是: email ,那么就自动打开发邮件的页面,当然前提是你的邮件软件登录过,总共有以下属性:

属性名说明
phone4拨打电话
email2发送邮件
none0啥也没有(默认值)
web1浏览对应网页
all15自动识别上面的
map8已经被抛弃了

其中值这一栏是当我们使用代码控制的时候设置,只不过我们也不会直接设置,而且从 Linkify 中取;当然还可以赋值为: phone|web ,这代表在这两种选择;只不过当对应的值既不是这两种中的一种的时候就是 none ,所以这里写的 phone|web 相当于 phone|web|none 。对应的值见下表:

属性对应的常量
phone4Linkify.PHONE_NUMBERS
email2Linkify.EMAIL_ADDRESSES
web1Linkify.WEB_URLS
all15Linkify.ALL
map8Linkify.MAP_ADDRESSES

代码控制使用: setAutoLinkMask(int) ,当然在 kotlin 中:

textView?.autoLinkMask = Linkify.WEB_URLS

只不过代码控制,我进行了多次测试,发现并不管用,可能是打开的方式不对;同时这里支持混合文本,也就是如果文本中既包含了链接文本也包含普通文本,这种情况下也是可以的。比如网站可以这样: 百度:www.baidu.com ,也可以这样 百度: www.baidu.com \n我的掘金首页:https://juejin.cn/user/43636198216061/posts 也就是两个地址都同时匹配到,也都能点击。默认情况下,带有链接的文本的颜色跟普通文本不同,见下图: image.png 如果想更换链接文本的颜色,那么看下面的属性。

android:textColorLink

链接文本的颜色,可以设置的值参考: 设置颜色 中的 1,2,3,5 方式。 这两个属性有什么用呢,其实很容易知道,当一段文本中含有电话号码并且有点击电话号码拨打的需求,那么这两个属性就派上用场了,不然的话,你需要使用 Intent 中拨打电话 的方式来进行,比较麻烦。

android:text

设置文本内容,文本的内容可以写文本也可以取 strings.xml 中定义的值,而且如果是规定的文本,官方推荐使用定义好的,而不是直接写死文本,具体原因是如果将来要国际化的话,比较方便,同时有时候修改文本都不用进行代码中,而是直接在 strings.xml 文件中修改。

在代码中使用普通文本:

title.text = "吴敬悦"

在代码中可以使用富文本,代码像下面这样:

val ss = SpannableString("天下大势,分久必合")
val span = ForegroundColorSpan(Color.parseColor("#ff0000"))
ss.setSpan(span, 5, 9, Spanned.SPAN_INCLUSIVE_EXCLUSIVE)
title.text = ss

效果: image.png 更多富文本效果,见链接: SpannableString

android:textAllCaps

文本是不是全部大写显示,取值 true 和 false ,我感觉这个属性使用场景比较少,毕竟大部分都是使用汉字。

android:textColor

文本的颜色,取值使用设置颜色 中的 1,2,3,5 方式,使用代码的方式:

title.setTextColor(ContextCompat.getColor(context, R.color.red))
title.setTextColor(ActivityCompat.getColor(context, R.color.red))

两种方式其实是一个方法;其中 R.color.red 是在 colors.xml 中定义的颜色。如果直接是十六进制的值,那么这样:

title.setTextColor(Color.parseColor("#ff00ff"))

如果是想使用其他文本相同的字体颜色,那么这样:

title.setTextColor(other.currentTextColor)

其中 other 是另外一个 TextView 文本节点。如果需要使用 argb 的方式,那么像下面:

title.setTextColor(Color.argb(0.5f, 1f, 0f, 0f))

这个 api 需要 sdk 大于等于 26 的才可以使用,同时其中的取值范围都是 [0.0-1.0] , 类型是 Float ,并不是 [0-255] 。

也可以直接赋值十六进制,比如: 0x000000ff ,含义 0xAARRGGBB ,像这样:

title.setTextColor(0xffff00ff)

只不过在 kotlin 中会出现下面的错误: image.png 但是在 java 中却是正常的,并不代表所有的都不可以,只是当写的数值太大了就不可以了,但是由于第一项表示透明度,但是呢又不能填写 ff ,所以这种方式在 kotlin 中无法设置完全不透明的颜色。

android:textAppearance

文本的外观,并不是所有的文本样式,支持的样式如下:

<declare-styleable name="TextAppearance">
    <!-- Text color. -->
    <attr name="textColor" />
    <!-- Size of the text. Recommended dimension type for text is "sp" for scaled-pixels (example: 15sp). -->
    <attr name="textSize" />
    <!-- Style (normal, bold, italic, bold|italic) for the text. -->
    <attr name="textStyle" />
    <!-- Weight for the font used in the TextView. -->
    <attr name="textFontWeight" />
    <!-- Typeface (normal, sans, serif, monospace) for the text. -->
    <attr name="typeface" />
    <!-- Font family (named by string or as a font resource reference) for the text. -->
    <attr name="fontFamily" />
    <!-- Specifies the {@link android.os.LocaleList} for the text.
         May be a string value, which is a comma-separated language tag list, such as "ja-JP,zh-CN".
         When not specified or an empty string is given, it will fallback to the default one.
         {@see android.os.LocaleList#forLanguageTags(String)} -->
    <attr name="textLocale" format="string" />
    <!-- Color of the text selection highlight. -->
    <attr name="textColorHighlight" />
    <!-- Color of the hint text. -->
    <attr name="textColorHint" />
    <!-- Color of the links. -->
    <attr name="textColorLink" />
    <!-- Present the text in ALL CAPS. This may use a small-caps form when available. -->
    <attr name="textAllCaps" format="boolean" />
    <!-- Place a blurred shadow of text underneath the text, drawn with the
         specified color. The text shadow produced does not interact with
         properties on View that are responsible for real time shadows,
         {@link android.R.styleable#View_elevation elevation} and
         {@link android.R.styleable#View_translationZ translationZ}. -->
    <attr name="shadowColor" format="color" />
    <!-- Horizontal offset of the text shadow. -->
    <attr name="shadowDx" format="float" />
    <!-- Vertical offset of the text shadow. -->
    <attr name="shadowDy" format="float" />
    <!-- Blur radius of the text shadow. -->
    <attr name="shadowRadius" format="float" />
    <!-- Elegant text height, especially for less compacted complex script text. -->
    <attr name="elegantTextHeight" format="boolean" />
    <!-- Whether to respect the ascent and descent of the fallback fonts that are used in
    displaying the text. When true, fallback fonts that end up getting used can increase
    the ascent and descent of the lines that they are used on. -->
    <attr name="fallbackLineSpacing" format="boolean"/>
    <!-- Text letter-spacing. -->
    <attr name="letterSpacing" format="float" />
    <!-- Font feature settings. -->
    <attr name="fontFeatureSettings" format="string" />
    <!-- Font variation settings. -->
    <attr name="fontVariationSettings" format="string"/>
</declare-styleable>

我们发现这些属性都是跟字体相关的,所以如果设置跟字体相关的属性可以使用这个;只不过我一直觉得这个属性没什么用,因为这些属性我完全可以通过设置 style 的方式来完成,即便是要修改所有文本的样式,我们通过修改主题中的默认文本的属性即可完成。

android:maxLines

设置文本最大显示行数;文案的完整是: 我看什么都像你,我看月亮,像你,看星星,也像你。那些白亮透澈、温柔冷清的光,它们都让我想起你。 , 下面是我设置值为 2 的结果: 1630772453(1).png 对应的属性设置 android:maxLines="2" 。也可以通过代码的方式来修改显示的行数 setMaxLines(int) , 在 kotlin 中的代码为: text?.maxLines = 1 ;其实大部分情况是我们需要单行显示文本,只需要将值设置成 1 即可,在以前的方法中是使用 android:singleLine="true" 来实现,如果设置了这个值,那么文本变化如下: 1630772766.png 而设置 android:maxLines="1" 的样式如下: 1630772836(1).png 我们发现这两者之间是有差别的,对于 android:singleLine="true" 来说,默认会带有省略号,而下面的没有,如果要想使用上面的相同的效果,那么需要添加 android:ellipsize="end" 属性来获得。

android:singleLine

使用单行显示文本,并且文本末尾添加省略符号。已废弃,使用下面的属性代替;

android:maxLines="1"
android:ellipsize="end"

android:ellipsize

给多出的文本添加省略符号,取值为:

<attr name="ellipsize">
    <enum name="none" value="0" />
    <enum name="start" value="1" />
    <enum name="middle" value="2" />
    <enum name="end" value="3" />
    <enum name="marquee" value="4" />
</attr>

其中属性的说明如下:

  • none 没有,也是默认值;
  • start 代表省略符号在文本的开头;
  • middle 省略符号在中间;
  • end 省略符号在结尾,这个最常用;
  • marquee 跑马灯的时候需要; 对应的效果如下: 1630774760(1).png marquee 效果如下: GIF 2021-9-5 1-00-16.gif 在编写的过程中可能你会发现编译器报错: image.png 提示使用 singleLine 属性,但是当值为 end 的时候是正常的,目前还没找到原因,我也没有出现过什么错误,但是在生产环境上肯定是使用上面的建议进行编写。

android:textIsSelectable

文本是否支持复制,默认值为: false ;如果将此值设置为 true ,那么在 荣耀30pro 中的表现为:

image.png 如果设置了这个值,那么 android:focusableandroid:focusableInTouchModeandroid:clickableandroid:longClickable 的值都会设置成 true ;如有需要手动设置值,其中如果将 android:focusable 单独设置成了 false ,那么复制功能将会失效;如果设置 android:focusable="true"android:longClickable="false" ,那么长按复制将会失效。

有时候你可能有这样的需求,那就是点击屏幕的其他地方,这个复制的弹框消失,因为默认情况下点击是没有效果的,那么只需要在你需要点击的视图的地方添加以下三个属性并设置成对应的值:

  • android:focusableInTouchMode="true"
  • android:focusable="true"
  • android:clickable="true" 但是如果你的 TextView 嵌套了很多层,你设置最外面的布局不一定会管用,还受嵌套中的父布局点击事件影响,像:

image.png 假如红色部分有自己的事件,那么就会响应自己的事件,弹框就不会消失。

android:autoSizeTextType API26

设置文本根据显示区域自动调整文本字体大小的类型。

  • none 默认值,啥也不干;
  • uniform 根据显示区域自动调整字体大小,如果设置了此属性,那么 textSize 就会失效; 这两者的差异看下图: uniform 与 none 的差异 如果你还想在一个区间内进行调整,不希望调整得太大或者太小,那么可以设置下面的属性:
  • autoSizeMinTextSize 设置可调整的最小文本大小;
  • autoSizeMaxTextSize 设置可调整的最大文本大小; 如果你还想在你定义好的一系列字体大小中进行调整,那么可以设置 autoSizePresetSizes 属性,这个属性接收一个数组,在 arrays.xml 中定义:
<array name="autosize_text_sizes">
    <item>12sp</item>
    <item>16sp</item>
    <item>20sp</item>
    <item>24sp</item>
</array>

然后在使用的地方,写上 android:autoSizePresetSizes="@array/autosize_text_sizes" 即可;如果设置了这个属性,那么 autoSizeMinTextSizeautoSizeMaxTextSize 将会失效。 也许你只是希望调整每一次调整的步伐,那么可以设置 autoSizeStepGranularity 属性。

android:autoSizeMinTextSize API26

设置可调整的最小文本大小,默认值是 12,具体见上面的 autoSizeTextType 属性。

android:autoSizeMaxTextSize API26

设置可调整的最大文本大小,默认值是 112,具体见上面的 autoSizeTextType 属性。

android:autoSizePresetSizes API26

设置可调整文本大小的调整值,是一个数组,当发生文本大小调整的时候,会从这个数组中进行选择调整,具体见上面的 autoSizeTextType 属性。

android:autoSizeStepGranularity API26

设置可调整大小的步伐;如果设置的值为 2sp ,那么调整的路线为: 12 14 16 18 20 ... 直到找到那么相对合适的,默认值是 1,具体见上面的 autoSizeTextType 属性。

android:breakStrategy API23

文本的折行策略,也就是当遇到换行的时候所采用的策略,主要有以下值:

  • simple 默认值,换行符将尽可能多的单词放在同一行中,如果没有更多的单词可以放入同一行中,则换行。只有当一行有一个单词且该单词长于行宽时,才会添加自动连字符。这是最快的突破策略,也是编辑的理想选择;
  • high_quality 使用此选项,换行符可以对整个段落进行优化,以获得更具可读性的文本,并在需要时应用自动连字符;
  • balanced 换行符对整个段落进行优化,使所有行的长度相似,并在需要时应用自动连字符。这种折行策略适用于小屏幕设备,如手表屏幕。 三种属性的区别 经过我的测试,我并没有发现 simplehigh_quality 的区别。但是前两者跟第三个区别很大,很明显,第三个就是尽可能的对其。

未完待续。。。

参考博文、教程、视频

  1. SpannableStringBuilder
  2. setTextColor注意事项
  3. TextView
  4. Theming basics in Android
  5. What’s your text’s appearance?
  6. Android | 自动调整文本大小的 TextViews
  7. Android 日常 | TextView 的 breakStrategy 属性是怎么回事?