Android Text View 去掉默认的padding的实现方法

先看下最终实现效果,满意您在往下看:

TextView 绘制的时候自带一定的Padding值,要想实现去掉默认的padding值,xml文件可以设置一个属性值 :

android:includeFontPadding="false"

然后运行起来就会发现,并没有什么卵用,也不能说完全没有,但效果差点意思。我就不运行了,在编译器上也能大概看到效果,如下图,我们可以看到依然有着无法删除的padding值。

我们先来看一下绘制TextView时的几条基准线:

  • top:在给定文本大小下,字体中最高字形高于基线的最大距离,即能绘制的最高点
  • ascent:单倍行距文本的基线以上建议距离,即推荐的文字绘制上边缘线
  • base:文字绘制基准线,也就是坐标轴,X轴就是Baseline
  • decent:单间距文本低于基线的建议距离,即推荐的文字绘制下边缘线
  • bottom:能绘制的最低点

Textview绘制文字会在  ascentdecent 之间,外面的距离我们可以理解为 类似 padding一样的间隔,但又并不是我们设置的paddingTop,paddingBottom。

要解决这个这个问题,首先我们要知道textview的内容文字绘制的真实区域:

红色的区域就是内容的真实高度,蓝色的部分就是textview绘制的多余的部分,现在我们要去掉这一部分,首先可以通过 getTextBounds 来获取绘制的真实区域

textView.getPaint().getTextBounds(text, 0, text.length(), textRect);

获取到真实区域后,那么再来看textview绘制的几条基准线,你想到了什么,是的,我们只需要稍微移动一下这几条线把高度压缩到文字的展示绘制区域即可,实现用 SpannableString 来实现,SpannableString 是 android  里面专门用来实现设置 textview 文字样式的类,这个不清楚的自行查询一下,这里不赘述了,具体我们用的是  LineHeightSpan ,可以通过修改 textview 的行高来实现我们的目的。具体看下代码:

spannableString.setSpan(new LineHeightSpan() {@Overridepublic void chooseHeight(CharSequence text, int start, int end, int spanstartv, int lineHeight, Paint.FontMetricsInt fm) {Rect textRect = new Rect();if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {textView.getPaint().getTextBounds(text, 0, text.length(), textRect);} else {textView.getPaint().getTextBounds(text.toString(), 0, text.length(), textRect);}// 直接把 textview 绘制区域 缩小到 文字真实大小的区域// 这个是有一点问题的,看下图fm.top = textRect.top;fm.bottom = textRect.bottom;fm.ascent = fm.top;fm.descent = fm.bottom;}
}, 0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

 Paint.FontMetricsInt 里的 top bottom ascent descent 就是用来调整 绘制的时候的具体位置的,我们把textview的绘制区域直接设置到 FontMetricsInt 里面,实现的效果如下图:

看起来确实去掉了padding,而且去的干干净净,需要这种效果的可以停下来,施展CV大法。

这种实现方式原理也很简单,是使文字真实的绘制区域高度为所绘制内容中字符的最大高度,这样可能会造成排版问题,文字对不齐,那我们就需要统一下绘制内容的高度,我们知道TextView 有个属性TextSize ,它的值最终决定了Textview 的高度,然后我们略微修改一下代码:

spannableString.setSpan(new LineHeightSpan() {@Overridepublic void chooseHeight(CharSequence text, int start, int end, int spanstartv, int lineHeight, Paint.FontMetricsInt fm) {Rect textRect = new Rect();if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {textView.getPaint().getTextBounds(text, 0, text.length(), textRect);} else {textView.getPaint().getTextBounds(text.toString(), 0, text.length(), textRect);}Log.e("NoPaddingText", "修改之前 " + fm.toString());Log.e("NoPaddingText", textRect.toString());Log.e("NoPaddingText", "textSize: " + textView.getTextSize());if (textRect.bottom - textRect.top < textView.getTextSize()) {// 一般我们认为字体的textview的textsize为textview的高度,当然有一定的误差// 当字体的高度没有字体的textsize大时,我们把大小设置成textsize,这样就可以解决文字的排版问题了float tempPadding = (textView.getTextSize() - (textRect.bottom - textRect.top)) / 2f;fm.top = (int) (textRect.top - tempPadding);fm.bottom = (int) (textRect.bottom + tempPadding);} else {fm.top = textRect.top;fm.bottom = textRect.bottom;}fm.ascent = fm.top;fm.descent = fm.bottom;Log.e("NoPaddingText", "修改之后 " + fm.toString());}
}, 0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

我们用TextView的TextSize来约束统一绘制高度,不足TextSize 的,补充添加一个padding值补齐正常的高度,实现效果如下:

这样看着顺眼多了,继续CV大法。

我这边是写了一个工具类,当然也可以自定义View形式实现,完整代码如下:

点这里跳转项目源码地址

import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Build;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.style.LineHeightSpan;
import android.util.Log;
import android.widget.TextView;public class TextUtil {// 设置上下取消绘制的padding值 考虑textsizepublic static void setNoVerticalPaddingText(TextView textView, CharSequence text) {if (textView == null || text == null)return;// 如果原先上下有padding,重置为 0textView.setPadding(textView.getPaddingLeft(), 0, textView.getPaddingRight(), 0);// 利用 LineHeightSpan 快速实现去除 padding 的效果SpannableString spannableString = new SpannableString(text);spannableString.setSpan(new LineHeightSpan() {@Overridepublic void chooseHeight(CharSequence text, int start, int end, int spanstartv, int lineHeight, Paint.FontMetricsInt fm) {Rect textRect = new Rect();if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {textView.getPaint().getTextBounds(text, 0, text.length(), textRect);} else {textView.getPaint().getTextBounds(text.toString(), 0, text.length(), textRect);}Log.e("NoPaddingText", "修改之前 " + fm.toString());Log.e("NoPaddingText", textRect.toString());Log.e("NoPaddingText", "textSize: " + textView.getTextSize());if (textRect.bottom - textRect.top < textView.getTextSize()) {// 一般我们认为字体的textview的textsize为textview的高度,当然有一定的误差 当然也可以自定义View 形式// 当字体的高度没有字体的textsize大时,我们把大小设置成textsize,这样就可以解决文字的排版问题了float tempPadding = (textView.getTextSize() - (textRect.bottom - textRect.top)) / 2f;fm.top = (int) (textRect.top - tempPadding);fm.bottom = (int) (textRect.bottom + tempPadding);} else {// 这么设置可以完全消除padding,但是会有问题,// 同样textsize的Textview 会因为设置的内容不一样而高度不一样// 如果有什么特殊需求可以考虑用一下fm.top = textRect.top;fm.bottom = textRect.bottom;}fm.ascent = fm.top;fm.descent = fm.bottom;Log.e("NoPaddingText", "修改之后 " + fm.toString());}}, 0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);textView.setText(spannableString);}// 设置上下取消绘制的padding值 不考虑textsizepublic static void setNoVerticalPaddingText2(TextView textView, CharSequence text) {if (textView == null || text == null)return;// 如果原先上下有padding,重置为 0textView.setPadding(textView.getPaddingLeft(), 0, textView.getPaddingRight(), 0);// 利用 LineHeightSpan 快速实现去除 padding 的效果SpannableString spannableString = new SpannableString(text);spannableString.setSpan(new LineHeightSpan() {@Overridepublic void chooseHeight(CharSequence text, int start, int end, int spanstartv, int lineHeight, Paint.FontMetricsInt fm) {Rect textRect = new Rect();if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {textView.getPaint().getTextBounds(text, 0, text.length(), textRect);} else {textView.getPaint().getTextBounds(text.toString(), 0, text.length(), textRect);}Log.e("NoPaddingText", "修改之前 " + fm.toString());Log.e("NoPaddingText", textRect.toString());Log.e("NoPaddingText", "textSize: " + textView.getTextSize());// 这么设置可以完全消除padding,但是会有问题,// 同样textsize的Textview 会因为设置的内容不一样而高度不一样// 如果有什么特殊需求可以考虑用一下fm.top = textRect.top;fm.bottom = textRect.bottom;fm.ascent = fm.top;fm.descent = fm.bottom;Log.e("NoPaddingText", "修改之后 " + fm.toString());}}, 0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);textView.setText(spannableString);}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/624845.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

书生·浦语大模型--第三节课笔记--基于 InternLM 和 LangChain 搭建你的知识库

文章目录 大模型开发范式RAGLangChain框架&#xff1a;构建向量数据库构建检索问答链优化建议web 部署 实践部分 大模型开发范式 LLM的局限性&#xff1a;时效性&#xff08;最新知识&#xff09;、专业能力有限&#xff08;垂直领域&#xff09;、定制化成本高&#xff08;个…

Android 仿快手视频列表,RecyclerView与Banner联动效果

这是看到群里讨论过快手APP的一个观看他人视频列表的一个联动效果&#xff0c;但是并不是完全按照这个软件的效果来做的&#xff0c;只是参考&#xff0c;并不是完全仿照这个软件来做的&#xff0c;没时间去优化排版问题了&#xff0c;请见谅&#xff0c;如图&#xff1a; 实现…

如何分析测试任务及需求(附分析流程)

测试分析 确认测试范围 根据测试项目的不同需求&#xff0c;有大致几类测试项目类型&#xff1a;商户/平台功能测试、支付方式接入测试、架构调整类测试、后台优化测试、性能测试、基本功能自动化测试。 测试项目需要按照文档要求进行测试需求分析&#xff0c;并给出对应的输出…

Swift 周报 第四十五期

文章目录 前言新闻和社区苹果或将扩充健康版图&#xff0c;为Apple Watch X铺路更新后的《Apple Developer Program 许可协议》现已发布 提案通过的提案 Swift论坛推荐博文话题讨论关于我们 前言 本期是 Swift 编辑组整理周报的第四十五期&#xff0c;每个模块已初步成型。各位…

【Linux 内核源码分析】RCU机制

RCU 基本概念 Linux内核的RCU&#xff08;Read-Copy-Update&#xff09;机制是一种用于实现高效读取和并发更新数据结构的同步机制。它在保证读操作不被阻塞的同时&#xff0c;也能够保证数据的一致性。 RCU的核心思想是通过延迟资源释放来实现无锁读取&#xff0c;并且避免了…

IOS自动化测试元素定位

一、元素属性介绍 1、元素属性 2、查看各定位方式执行效率 二、iOS常用定位方法 1、accessibility_id 2、class_name 3、Xpath 4、ios_class_chain(类型链) 5、ios_predicate(谓词) 一个页面最基本组成单元是元素&#xff0c;想要定位一个元素&#xff0c;我们需…

Linux网络服务部署yum仓库

目录 一、网络文件 1.1.存储类型 1.2.FTP 文件传输协议 1.3.传输模式 二、内网搭建yum仓库 一、网络文件 1.1.存储类型 直连式存储&#xff1a;Direct-Attached Storage&#xff0c;简称DAS 存储区域网络&#xff1a;Storage Area Network&#xff0c;简称SAN&#xff0…

01-15

#include "ui_widget.h"Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget) {ui->setupUi(this);//判断是否有该数据库if(!db.contains("stuInfo.db")){//说明数据库不存在 则创建dbQSqlDatabase::addDatabase("QSQLITE")…

ELK之Filebeat输出日志格式设置及输出字段过滤和修改

一、Filebeat输出日志格式设置 1.1 编辑vim filebeat.yml文件,修改输出格式设置 # output to console output.console:codec.format: string: %{[@timestamp]} %{[message]}pretty: true### 1.2 测试 执行 ./filebeat -e 可以看到/tmp/access.log(目前文件里只有140.77.188…

【LV12 DAY9 ADC实验】

电压在1501mv~1800mv时&#xff0c;LED2、LED3、LED4、LED5点亮 电压在1001mv~1500mv时&#xff0c;LED2、LED3、LED4点亮 电压在501mv~1000mv时&#xff0c;LED2、LED3点亮 电压在0mv~500mv时&#xff0c;LED2闪烁 #include "exynos_4412.h"void delay(unsigned in…

大语言模型系列-总述

大语言模型发展史 研究人员发现&#xff0c;扩展预训练模型&#xff08;Pre-training Language Model&#xff0c;PLM&#xff09;&#xff0c;例如扩展模型大小或数据大小&#xff0c;通常会提高下游任务的模型性能&#xff0c;模型大小从几十亿&#xff08;1 B 10亿&#x…

Mysql判断一个表中的数据是否在另一个表存在

方式一&#xff1a; 判断A表中有多少条数据在B表中【存在】,并且显示这些数据–EXISTS语句 select A.ID, A.NAME from 表A where EXISTS(select * from 表B where A.IDB.ID) 判断A表中有多少条数据在B表中【不存在】&#xff0c;并且显示这些数据–NOT EXISTS语句 select …

使用Go语言通过API获取代理IP并使用获取到的代理IP

目录 前言 【步骤一&#xff1a;获取代理IP列表】 【步骤二&#xff1a;使用代理IP发送请求】 【完整代码】 【总结】 前言 在网络爬虫、数据抓取等场景中&#xff0c;经常需要使用代理IP来隐藏真实的IP地址&#xff0c;以及增加请求的稳定性和安全性。本文将介绍如何使用…

ubuntu22: nvtop no gpu to monitor.

解决方法&#xff1a; 重新下载nvtop sudo apt update sudo apt -y install nvtop真是逆天 &#xff0c;ubuntu系统的nvidia driver突然坏了&#xff0c;然后我重装了nvidia driver, 之后用nvtop就出现这个问题了&#xff0c;但是逆天的是我竟然没有搜到一篇中文的帖子讲这个问…

NLP论文阅读记录 - 2021 | WOS 使用 GA-HC 和 PSO-HC 改进新闻文章的文本摘要

文章目录 前言0、论文摘要一、Introduction1.1目标问题1.2相关的尝试 二.相关工作三.本文方法3.1 总结为两阶段学习3.1.1 基础系统 3.2 重构文本摘要 四 实验效果4.1数据集4.2 对比模型4.3实施细节4.4评估指标4.5 实验结果4.6 细粒度分析 五 总结思考 前言 Improved Text Summa…

云卷云舒:2023年,我眼中的十大数据库

我眼中的十大数据库&#xff0c;只要看成长性和演进速度&#xff08;个见勿怪&#xff09;。 一、五强 1、openGauss&#xff1a;生态影响力变大&#xff0c;基于高斯的产品层出不穷 2、OceanBase&#xff1a;只因霸榜&#xff0c;技术强大&#xff0c;新特性更新频繁&#x…

lv14 并发控制:上下文、中断屏蔽和原子变量

1 上下文和并发场合 执行流&#xff1a;有开始有结束总体顺序执行的一段代码 又称上下文 应用编程&#xff1a;任务上下文 内核编程&#xff1a; 任务上下文&#xff1a;五状态 可阻塞 a. 应用进程或线程运行在用户空间b. 应用进程或线程运行在内核空间&#xff08;通过调用…

python基础语法看一篇就够了,全网最全python语法笔记汇总

前言 Python 是一种代表简单思想的语言&#xff0c;其语法相对简单&#xff0c;很容易上手。不过&#xff0c;如果就此小视 Python 语法的精妙和深邃&#xff0c;那就大错特错了。 如能在实战中融会贯通、灵活使用&#xff0c;必将使代码更为精炼、高效&#xff0c;同时也会极…

提前避坑Anzo Capital总结浮动差价的3个缺点

在交易中很多投资者倾向于选择浮动差价模式&#xff0c;这种模式的便利性就不言而喻了&#xff0c;但Anzo Capital需要提醒各位投资者&#xff0c;一定要知道浮动差价的3个缺点&#xff0c;在交易中提前避坑&#xff0c;下面Anzo Capital就和各位投资者一起总结浮动差价的这3…

leetcode 24两两交换链表中的节点

题目 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能进行节点交换&#xff09;。 思想 对于操作链表节点的时候&#xff0c;首先需要就是创建一个虚拟的…