TextView完全去除上下边距

最近项目里遇到一些要完全去除TextView上下边距的场景。但是设置includeFontPadding为false之后,并不能完全去除上边距或者下边距。


TextView完全去除上下边距_第1张图片


于是想从绘制过程中就移除上线边距。于是从网上查资料结合源码分析问题。

第一步:弄清楚上下边距的原理。这个参考 这篇文章自定义控件之绘图篇( 五):drawText()详解_启舰-CSDN博客,详细写了内部的view五线谱的原理。

第二步:集成TextView,重新设置view的高度和边距。有了第一步的基础之后,就明白对于“上面的按钮”来说,上边距就是top-ascent,下边距就是bottom-descent。接下来有一件事是确定要做的,那就是重写onMeasure方法,想达到“下面的按钮”的效果,高度肯定减去上面算出来的上和下边距。但是,做完之后发现问题了,view中文字绘制时是通过paint.drawText实现的,方法里会有一个baseline的参数,那么Y轴上的绘制起始点,其实还是以整个view是包含上下边距来计算的,那么可以想一想会出现什么效果?对的,那就是文字的下半部分会被截断一些,而所谓的这些的距离其实就是上边距的空白的高度。于是乎,这里就出现了2个解决方案。

第一个方案:在ondraw里执行setScrollY方法,把view竖直上移,然后再执行super.ondraw(),但发现view会闪。说明view多刷新了一次,个人理解的意思是在,设置setScrollY的时候,控件已经绘制好了并显示了,再次移动view会让其再绘制一次。于是考虑将操作放在ondraw方法执行之前。那么再结合view绘制过程的三个方法的执行顺序,只要再onlayout或onMeasure里提前操作即可。

下面附上完整代码:


public class NoTopBottomSpaceTextView extends AppCompatTextView {

    public NoTopBottomSpaceTextView(Context context) {

        super(context);

        init();

    }

    public NoTopBottomSpaceTextView(Context context, @Nullable AttributeSet attrs) {

        super(context, attrs);

        init();

    }

    public NoTopBottomSpaceTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {

        super(context, attrs, defStyleAttr);

        init();

    }

    private void init() {

        setGravity(getGravity() | Gravity.CENTER_VERTICAL);

        setIncludeFontPadding(false);

    }

    @Override

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        Paint.FontMetrics fm = getPaint().getFontMetrics();

        if (fm != null) {

            int padding = (int) Math.abs(fm.bottom - fm.descent);

            int width = getMeasuredWidth();

            int height = getMeasuredHeight();

            if (getText().toString().contains("g")

                    || getText().toString().contains("y")

                    || getText().toString().contains("p")) {

                setMeasuredDimension(width, height - padding);

                if (getScrollY() != (int)(fm.ascent-fm.top)) {

                    setScrollY((int) (fm.ascent - fm.top));

                }

                setScrollY((int) Math.abs(fm.top - fm.ascent));

            } else {

                setMeasuredDimension(width, height - padding - (int) (getTextSize() * 0.1));

                setScrollY((int) Math.abs(fm.top - fm.ascent) - (int) (getTextSize() * 0.1));

            }

        }

    }

}

你可能感兴趣的:(TextView完全去除上下边距)