Android去除TextView文本中的默认内边距
16lz
2021-01-25
Android开发过程中可能很多人都遇到过这样的问题,那就是TextView上下内边距的问题。使用TextView控件的时候由于其内边距导致与UI效果相差甚远。很是让不少程序猿难受,也包括我自己因为这个原因也没少和UI设计师打嘴仗。于是最近写了一个自定义的NoBroderTextView去除了TextView上下内边距。
通过查阅Google官网的Android开发文档发现TextView中有android:includeFontPadding属性去除内边距。但是当设置该数据行为false的时候发现TextView还有一点点内边距存在,并不能让TextView控件的上下边距与文本严丝合缝。而这一点点的间距是Android框架中为TextView预留的字体边际。无法通过System API设置及修改。感兴趣的同学可以查看源码发现。无奈只能自定义实现TextView实现了,话不多少直接上代码。
package com.liming.nobroder.nopaddingtextview.views;import android.content.Context;import android.graphics.Canvas;import android.graphics.Rect;import android.support.v7.widget.AppCompatTextView;import android.text.Layout;import android.text.TextPaint;import android.text.TextUtils;import android.util.AttributeSet;import android.util.Log;/** * 无内边距TextView控件 * @author liming Create date : 2019/01/30 */public class NoPaddingTextView extends AppCompatTextView { //日志标记 private final String TAG = NoPaddingTextView.class.getSimpleName(); //文本画笔 private TextPaint textPaint; //绘制矩形 private Rect rect; //默认宽度 private int layoutWidth = -1; //获得每行数据 private String[] lineContents; //获取行间距的额外空间 private float line_space_height = 0.0f; //获取行间距乘法器 private float line_space_height_mult = 1.0f; /** * 构造方法 * * @param context * @param attrs */ public NoPaddingTextView(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs); } /** * 构造方法 * * @param context * @param attrs * @param defStyleAttr */ public NoPaddingTextView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context, attrs); } /** * 初始化方法 */ private void init(Context context, AttributeSet attrs) { //声明画笔对象 textPaint = new TextPaint(); //声明矩形绘制对象 rect = new Rect(); //获得行间距额外数据 line_space_height = getLineSpacingExtra(); //获得行间距方法器 line_space_height_mult = getLineSpacingMultiplier(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); Layout _layout = getLayout(); if (_layout != null) { //获得文本内容文本内容不可以修改,平切判断当前当前内容是否为null final String _tvContent = TextUtils.isEmpty(getText()) ? "" : getText().toString(); //获取文本长度 final int _tvLenght = _tvContent.length(); //设置文本宽度 textPaint.getTextBounds(_tvContent, 0, _tvLenght, rect); //设置文本大小 textPaint.setTextSize(getTextSize()); //设置文本颜色 textPaint.setColor(getCurrentTextColor()); //获取行数据 getTextContentData(_layout); //获得行高 int _lineHeight = -rect.top + rect.bottom; //初始化布局 initLayout(_layout); //设置布局区域 int[] _area = getWidthAndHeigt(widthMeasureSpec, heightMeasureSpec, layoutWidth, _layout.getLineCount(), _lineHeight); //设置布局 setMeasuredDimension(_area[0], _area[1]); } } /** * 初始化化布局高度 * * @param _layout */ private void initLayout(Layout _layout) { //获得布局大小 if (layoutWidth < 0) { //获取第一次测量数据 layoutWidth = _layout.getWidth(); } } /** * 获取布局数据 * * @param pWidthMeasureSpec * @param pHeightMeasureSpec * @param pWidth * @return 返回宽高数组 */ private int[] getWidthAndHeigt(int pWidthMeasureSpec, int pHeightMeasureSpec, int pWidth, int pLineCount, int pLineHeight) { int _widthMode = MeasureSpec.getMode(pWidthMeasureSpec); //获取宽的模式 int _heightMode = MeasureSpec.getMode(pHeightMeasureSpec); //获取高的模式 int _widthSize = MeasureSpec.getSize(pWidthMeasureSpec); //获取宽的尺寸 int _heightSize = MeasureSpec.getSize(pHeightMeasureSpec); //获取高的尺寸 //声明控件尺寸 int _width; int _height; //判断模式 if (_widthMode == MeasureSpec.EXACTLY) { //如果match_parent或者具体的值,直接赋值 _width = _widthSize; } else { _width = pWidth - rect.left; } //高度跟宽度处理方式一样 if (_heightMode == MeasureSpec.EXACTLY) { _height = _heightSize; } else { if(pLineCount > 1){ _height = pLineHeight * pLineCount + (int) (line_space_height * line_space_height_mult * (pLineCount -1)); }else{ _height = pLineHeight * pLineCount; } } //初始化宽高数组 int[] _area = { _width, _height }; return _area; } /** * 获取行数据 * * @param _layout 文本布局对象(注:该布局其实使用的是Layout子类对象StaticLayout) */ private void getTextContentData(Layout _layout) { //初始化航速数据 lineContents = new String[_layout.getLineCount()]; //获得每行数据 for (int i = 0; i < _layout.getLineCount(); i++) { int _start = _layout.getLineStart(i); int _end = _layout.getLineEnd(i); lineContents[i] = getText().subSequence(_start, _end).toString(); } } @Override protected void onDraw(Canvas canvas) { //行高 float _line_height = -rect.top + rect.bottom; //行间距 float _line_space = line_space_height * line_space_height_mult; //循环获取每行数据内容 for (int i = 0; i < lineContents.length; i++) { //获得数据 String _drawContent = lineContents[i]; //显示日志 Log.e(TAG, "LINE[" + (i + 1) + "]=" + _drawContent); //绘制每行数据 canvas.drawText(_drawContent, 0, -rect.top + (_line_height + _line_space) * i, textPaint); } }}
其中getTextContentData()方法获取文本内容,并且获取每行数据将其缓存到lineContents数组中。
通过getWidthAndHeight()方法获取自定义控件的宽高(其实就是当控件设置为wrap_content或者match_parent的时候实际控件的高度)获取之后重新在设置到自定义控件。
onDraw()方法实现绘制这个就不多说了。
以下TextView中的属性依然奏效
android:lineSpacingExtra="设置行间距(默认为0.0f)"android:lineSpacingMultiplier="行间距基数(默认为1.0f)"
项目GitHub地址:https://github.com/liming870906/NoBroderTextView.git
android:lineSpacingExtra="设置行间距(默认为0.0f)"android:lineSpacingMultiplier="行间距基数(默认为1.0f)"
效果如下:
更多相关文章
- “罗永浩抖音首秀”销售数据的可视化大屏是怎么做出来的呢?
- Nginx系列教程(三)| 一文带你读懂Nginx的负载均衡
- 不吹不黑!GitHub 上帮助人们学习编码的 12 个资源,错过血亏...
- Android实现简单底部导航栏 Android仿微信滑动切换效果
- android wear端数据和手机端数据
- 五步学会Android的ListView控件
- Android(安卓)重要数据目录
- understand and use android mvc(理解及使用android mvc)
- android中如何美化ListView的背景