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大法。

完整代码如下:(两种实现形式:1、工具类; 2、自定义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);}}
import android.content.Context;
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.AttributeSet;
import android.widget.TextView;import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatTextView;/*** 自定义view 形式 实现 NoPaddingTextView 布局可以预览*/
public class NoPaddingTextView extends AppCompatTextView {public NoPaddingTextView(@NonNull Context context) {this(context, null);}public NoPaddingTextView(@NonNull Context context, @Nullable AttributeSet attrs) {this(context, attrs, 0);}public NoPaddingTextView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}@Overridepublic void setText(CharSequence text, BufferType type) {super.setText(getNoVerticalPaddingText(this,text), type);}// 设置上下取消绘制的padding值 考虑textsizepublic final SpannableString getNoVerticalPaddingText(TextView textView, CharSequence text) {if (textView == null || text == null)return new SpannableString("");// 如果原先上下有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);return spannableString;}
}

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

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

相关文章

机器人强化学习-双机械臂

概要 基于 robosuite 库&#xff0c;进行双臂机器人学习训练 环境测试 下面展示下分别控制两个机械手随机运动的画面&#xff1a; 双臂显示场景如下&#xff1a;双臂调用代码如下&#xff1a; import numpy as np import robosuite as suite import robomimic import rob…

周五~~~摸鱼

学习也能很快乐哦~~&#xff01; vim /etc/motd 修改这个文件可以让你刚登录linux 系统显示图形效果 佛祖 效果&#xff1a; 自行车 效果&#xff1a; love \ ------------ / ------ \ \ …

thinkphp+mysql+vue大学新生入学报到交流平台t49m6

运行环境:phpstudy/wamp/xammp等 开发语言&#xff1a;php 后端框架&#xff1a;Thinkphp5 前端框架&#xff1a;vue.js 服务器&#xff1a;apache 数据库&#xff1a;mysql 数据库工具&#xff1a;Navicat/phpmyadmin 本系统尝试使用thinkphp框架在网上架构一个动态的大学新生…

龙哥的问题(积性函数,莫比乌斯反演)

题目路径&#xff1a; 221. 龙哥的问题 - AcWing题库 思路&#xff1a;

【EI会议征稿通知】2024年通信技术与软件工程国际学术会议 (CTSE 2024)

2024年通信技术与软件工程国际学术会议 (CTSE 2024) 2024 International Conference on Communication Technology and Software Engineering (CTSE 2024) 2024年通信技术与软件工程国际学术会议 (CTSE 2024)将于2024年03月15-17日在中国长沙举行。会议专注于通信技术与软件工…

ARM day5、day6 硬件编程

一、硬件 fs4412 sd卡 串口线 电源 二、根据原理图点灯 1、确定需求&#xff1a; 点灯&#xff08;亮 or 灭&#xff09; 2、查看原理图 2.1 外设原理图 devboard 查找LED2->CHG_COK(核心板) 2.2 核心板原理图 coreboard 查找CHG_COK->XEINT23/KP_ROW7/ALV_DBG…

【笔记】《AI中文版》V3 第 1 章 概述

参考链接&#xff1a; 开源内容&#xff1a;https://github.com/siyuxin/AI-3rd-edition-notes 英文版 V2&#xff1a; https://terrorgum.com/tfox/books/artificialintelligenceinthe21stcentury.pdf 没找到 V3 笔记 作为计算机科学的一个分支&#xff0c;人工智能主要研究…

android 13.0 Hotseat 添加allapp button功能实现

1.概述 在13.0产品的rom定制化开发中,在laucher3定制化开发中,在hotseat功能中有需求要求添加allapp按钮 点击按钮进入所有app页面,就是在hotseat的几个功能按钮中间放一个allapp功能键,实现点击进入app列表页 效果图如图: 2.Hotseat 添加allapp button相关代码 packages/…

计算机网络-甘晴void学习笔记

计算机网络 计科210X 甘晴void 202108010XXX 文章目录 计算机网络期中复习1计算机网络和因特网1.1 因特网1.2 网络边缘1.3 网络核心1.4 分组交换的时延/丢包和吞吐量1.5 协议层次与服务模型 2 应用层原理2.1 应用层协议原理2.2 Web和Http2.3 因特网中的电子邮件2.4 DNS&#x…

基于Harris角点的多视角图像全景拼接算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 Harris角点检测 4.2 图像配准 4.3 图像变换和拼接 4.4 全景图像优化 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 function [ImageB…

如何在C#中读取USB转串口参数并显示在ComboBox

如何在C#中读取USB转串口参数并显示在ComboBox 在很多应用程序中&#xff0c;尤其是那些需要与外部硬件通信的程序中&#xff0c;自动检测和读取串口参数是一个非常有用的功能。在本文中&#xff0c;我们将讨论如何在C#中实现这一功能&#xff0c;重点是如何自动识别通过USB转换…

MetaGPT-打卡-day2,MetaGPT框架组件学习

文章目录 Agent组件实现一个单动作的Agent实现一个多动作的Agent技术文档生成助手其他尝试 今天是第二天的打卡~昨天是关于一些概念的大杂烩&#xff0c;今天的话&#xff0c;就来到了Hello World环节。 从单个Agnet到多个Agent&#xff0c;再到组合更复杂的工作流来解决问题。…