letterSpacing导致TextView文本被截断

ops/2024/9/23 20:18:12/

一.背景介绍

(Android10 11目前有这个问题 Android15似乎有新的属性 但是没有可用的环境 没有验证)
简介
android:maxLines="1" 
android:textAlignment="viewStart"
android:letterSpacing="0.04"
多个属性同时作用情况下 在系统为阿拉伯语情况下,显示英文文本字符串出现截断问题


UX需求:
1.有两个控件 address displayName
address自适应宽度 displayName在address之后占满剩余空间
2.系统为阿拉伯语情况下控件位置需要调换(父控件  android:layoutDirection="locale" 实现)
3.系统为英语情况下 如果控件有多余的宽度,文本要在Textview的内部靠左显示。
系统为阿拉伯语情况下 如果控件有多余的宽度,文本要在Textview的内部靠右显示。(android:textAlignment="viewStart"实现)
4.控件都只显示一行文本,当文本过长时,尾部显示...(android:maxLines="1"  android:ellipsize="end"实现)
5.UX提供了字体文件 但是字体本身字符间距太小 需要通过代码设置letterSpacing(android:letterSpacing="0.04"实现)


二.xml实现

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="528dp"android:layout_height="140dp"android:background="#55DDDDDD"android:layoutDirection="locale"tools:context=".MainActivity"><TextViewandroid:id="@+id/address"android:layout_width="50dp"android:layout_height="wrap_content"android:text="adress"android:textColor="#F00"app:layout_constraintEnd_toStartOf="@+id/displayName"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent" /><TextViewandroid:id="@+id/displayName"android:layout_width="0dp"android:layout_height="wrap_content"android:ellipsize="end"android:letterSpacing="0.04"android:maxLines="1"android:text="This is long text This is long text This is long text This is long text This is long text This is long textThis is long text"android:textAlignment="viewStart"android:textDirection="locale"android:textSize="36sp"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toEndOf="@+id/address"app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

三. 现象分析


在系统语言切换到阿拉伯的情况下 英文出现截断现象 


当我们修改如下属性时 截断问题可以被解决
例如删除 android:maxLines="1" 
例如 把android:textAlignment="viewStart" 改成textStart
例如删除android:letterSpacing="0.04"
但是为了满足UX的需求 这些属性我们都不能修改
另外 如果把displayName的文本改成阿拉伯语 也不会出现问题
还有一个现象 displayName的文本越长 被截断的文本就越多
还有我们将letterSpacing改的越小 被截断的现象越不明显
从以上的各种现象 可以推测,是Android系统在系统语言是阿拉伯语情况下 对于英文文本的letterSpacing计算有问题 导致其判断显示省略号的位置出错
后面调查发现 Android系统在系统语言是英文情况下 对于阿拉伯语文本的letterSpacing计算也有问题

四.解决思路


如果条件变化 我们可以改动如下情况任意一个
 * 1.view textAlignment is TEXT_ALIGNMENT_VIEW_START
 * 2.text is too long to display in textview
 * 3.letterSpacing is not 0
 * 4.ellipsize="end"
截断问题都不会发生

但如果无法修改上面的这几个状态 那么我们可以在这种情况下重新绘制text

或者动态修改TEXT_ALIGNMENT的属性值 

下面介绍重新绘制text的方案

五.代码实现

import android.content.Context
import android.graphics.Canvas
import android.text.Layout
import android.text.StaticLayout
import android.text.TextUtils
import android.util.AttributeSet
import android.view.View
import androidx.appcompat.widget.AppCompatTextView
import com.telenav.transformerhmi.uiframework.R/**** it will re draw text* when all of following conditions happen together* 1.view textAlignment is TEXT_ALIGNMENT_VIEW_START* 2.text is too long to display in textview* 3.letterSpacing is not 0* 4.ellipsize="end"* otherwise this is just a normal textview*/class AutoAlignmentViewStartTextView @JvmOverloads constructor(context: Context,attrs: AttributeSet? = null,defStyleAttr: Int = R.style.TextAppearance
) : AppCompatTextView(context, attrs, defStyleAttr) {override fun onDraw(canvas: Canvas) {if (textAlignment == View.TEXT_ALIGNMENT_VIEW_START && needEllipsis() && letterSpacing != 0f && ellipsize == TextUtils.TruncateAt.END) {// get Paintval paint = paint.apply {color = currentTextColortextSize = textSize}val text = text.toString()// get text content widthval width = width - paddingLeft - paddingRight// create StaticLayout to deal with text which has ellipsisval layout = StaticLayout.Builder.obtain(text, 0, text.length, paint, width).setMaxLines(maxLines).setEllipsize(TextUtils.TruncateAt.END)  // Display ellipsis when the view size is exceeded.setAlignment(Layout.Alignment.ALIGN_NORMAL)  // Left-align text, but right-align by canvas movement.build()// text center verticalval y = (height - layout.height) / 2canvas.save()if (layoutDirection == View.LAYOUT_DIRECTION_RTL) {// Move the canvas so the text starts drawing from the rightcanvas.translate(paddingLeft.toFloat(), y.toFloat())}layout.draw(canvas)canvas.restore()} else {super.onDraw(canvas)}}private fun needEllipsis(): Boolean {val availableWidth = width - paddingStart - paddingEndvar currentWidth = 0fvar lineCount = 0text.forEach { char ->currentWidth += paint.measureText(char.toString())if (currentWidth > availableWidth) {// Text occupies the entire line.lineCount++if (lineCount > maxLines) {return true}currentWidth = paint.measureText(char.toString())}}if (currentWidth > 0) {lineCount++}// measured line count > maxLinesreturn lineCount > maxLines}
}


 


http://www.ppmy.cn/ops/114940.html

相关文章

Android外接USB扫码枪

前言 公司的设备以前接入的都是串口的扫码头&#xff0c;优点是直接通过串口读取流里面的数据就OK了&#xff0c;缺点是你需要知道每一款扫码器的型号以获取波特率及Android设备的串口地址。因为现在usb扫码器越来越方便且即插即用&#xff0c;不需要额外供电以及价格便宜等特…

electron-vue安装与打包问题解决

electron-vue安装与打包问题解决 1.项目安装 报错 RequestError: connect ETIMEDOUT 185.199.109.133:443RequestError: socket hang up 问题 npm国内下载时存在网络连接失败以及网络缓慢的情况&#xff0c;需要使用镜像安装设置npm镜像地址&#xff0c;安装vue-electron时…

免费的跨平台剪贴板工具,超好用!

在日常的工作中&#xff0c;我们会频繁地使用复制和粘贴功能来处理各种信息。不知道你是不是也遇到过和我一样的烦恼&#xff1a;在处理多个任务时&#xff0c;需要来回切换窗口以找到之前复制的内容。这时&#xff0c;一款高效的剪贴板管理工具就显得尤为重要。 今天就给大家…

开源模型应用落地-Qwen2.5-7B-Instruct与vllm实现推理加速的正确姿势(一)

一、前言 目前,大语言模型已升级至Qwen2.5版本。无论是语言模型还是多模态模型,均在大规模多语言和多模态数据上进行预训练,并通过高质量数据进行后期微调以贴近人类偏好。在本篇学习中,将集成vllm实现模型推理加速,现在,我们赶紧跟上技术发展的脚步,去体验一下新版本模…

基于微信小程序的宠物寄养平台的设计与实现+ssm(lw+演示+源码+运行)

摘 要 随着科技和网络的进步&#xff0c;微信小程序技术与网络、生活贴和的更加紧密。需要依靠客户端的单机系统逐渐被淘汰&#xff0c;利用互联网可以处理大量数据的新型系统如雨后春笋般迅速发展起来。这类系统和信息化时代的同步发展对传统的办公管理方式造成了很大的压力。…

计算机毕业设计 家电销售展示平台的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

[OpenCV] 数字图像处理 C++ 学习——15像素重映射(cv::remap) 附完整代码

文章目录 前言1.像素重映射理论基础2.代码实现(1) remap()细节(2)水平翻转(2)垂直翻转(3)旋转 180 度(4)径向扭曲 3.完整代码 前言 像素重映射将图像中的每个像素映射到新位置&#xff0c;实现图像的扭曲、校正等操作。在 OpenCV 中&#xff0c;cv::remap() 函数就是用于实现这…

云栖大会Day1:云应用开发平台 CAP 来了

2024 云栖大会开幕&#xff0c;在大会第一天&#xff0c;阿里云正式发布全新产品——云应用开发平台 CAP。CAP 拥有丰富的场景化应用模板&#xff0c;可以极速体验&#xff0c;并且具备更低的成本优势以及灵活组装等特点&#xff0c;成为广大开发者与企业必备的一站式应用开发平…