安卓开发 自定义TextView 去除默认内边距

一.搜到的大部分的解决办法

1.网上方法的效果

在xml文件中对TextView设置: includeFontPadding=false

加上以上属性之后,文本的高度明显变小了,但是没有达到我们预想的效果(文字紧贴边框),而是在上下留了一部分距离。

具体效果可以查看第二部分中的对比图

 

2.失效的原因

在了解这个原因前需要对TextView中文本的绘制有一点了解,具体查看文末参考文章中启航大佬的介绍文章。

对应下图,top和bottom之间的高度,就是默认的TextView的高度

includeFontPadding=false属性取消的是top和ascent之间bottom和descent之间的两个空白区域。

但是也看的出来,在ascent和descent中间的文字,距离两条线还是有一定距离,这也就是在设置includeFontPadding=false属性后继续留着的空白部分。

 

安卓开发 自定义TextView 去除默认内边距_第1张图片

(图来自启航大佬的文章)

 

具体从源码中可以看出这个过程

查看TextView的源码中查找mIncludePad属性,发现都是进到一个BoringLayout

在其中查找includepad,在其init()方法中找到以下部分。

其中metrics为系统提供的用于查询top,ascent,descent,bottom四个属性的一个对象

 

安卓开发 自定义TextView 去除默认内边距_第2张图片

 

二.自定义view实现效果

 

1.最终效果对比图

中间的为普通的TextView

安卓开发 自定义TextView 去除默认内边距_第3张图片

 

2 自定义的思路

首先系统提供了一个用于检测包裹住的文字所需最小的矩形的方法。

 

/**
 * 获取指定字符串所对应的最小矩形,以(0,0)点所在位置为基线
 * @param text   要测量最小矩形的字符串
 * @param start  要测量起始字符在字符串中的索引
 * @param end    所要测量的字符的长度
 * @param bounds 接收测量结果
 */
public void getTextBounds(String text, int start, int end, Rect bounds);

自定义View

onMeasure

中把宽高设置为上述最小矩形的宽高

onDraw

由于宽高被重新设置了,所以canvas中原点要进行位移,才能使得文本正常显示。

 

3 具体代码

public class MyNoPaddingTextView extends android.support.v7.widget.AppCompatTextView {
    private Rect minRect;

    public MyNoPaddingTextView(Context context) {
        super(context);
    }

    public MyNoPaddingTextView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public MyNoPaddingTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (minRect == null) {
            //minRect用来获取文字显示所需要最小区域的左上角和右下角  坐标
            //该坐标是以(0,0)为基准的矩形坐标
            minRect = new Rect();
        }
        getPaint().getTextBounds(getText().toString(), 0, getText().length(), minRect);
        final int width = minRect.width();
        final int height = minRect.height();
        setMeasuredDimension(width, height);
    }
    
    @Override
    protected void onDraw(Canvas canvas) {
        final String text = getText().toString();
        final int left = minRect.left;
        final int top = minRect.top;
        Paint paint = getPaint();
        paint.setColor(getCurrentTextColor());
        /*此时文字的基线在(0,0),要达到刚好包裹文字的效果,相当于把以(0,0)为基线的minRect 移动到合适的位置
        x轴上由于左边内边距的存在,所以需要左移minRect.left距离
        y轴上相当于把mingRect的顶点向下移动minRect.top距离
        */
        canvas.drawText(text, -left, -top, paint);
    }
}

4.补充

(1)如果需要修改或者了解,一定要看参考文献中启航大佬的文章,介绍的很详细,避免走弯路。

(2)对于wrap_content的文本效果是可以满足的,如果需要指定文本大小,则需要在onMeasure中重写一下。

(3)使用本文中的代码时,xml中的padding会失效,如果有左右padding的需求,可以通过onMeasure和onDraw中getPaddingLeft()等方法判断一下,测试过是可以实现padding效果的。

(4)只测试了wrap_content的效果(效果有用了),要是有别的问题大家可以一起讨论解决。

 

 

参考文章:

启航 drawText()详解: https://blog.csdn.net/harvic880925/article/details/50423762

另一种自定义view实现效果 :https://blog.csdn.net/qq1282675628/article/details/79146859

去掉内边距(但是只去掉了上面部分):https://blog.csdn.net/Ab0510/article/details/52219464

 

 

 

你可能感兴趣的:(安卓开发,Android,Bug)