你能解释一下TextView + Gravity + SingleLine和Canvas的行为吗?

ben*_*n75 8 android canvas textview

我有一个自定义TextView,它的onDraw方法被覆盖,在文本视图周围绘制一个红色边框.

当我将引力 设置为除左边以外的其他东西并且 singleLine = true时:不绘制边框.

  • 有什么理由吗?
  • 有没有解决方法?

以下屏幕截图说明了问题:第二个textView没有边框 在此输入图像描述

TL表示TOP | LEFT; C表示CENTER; SL意味着单行; T意味着真实; F表示错误

这是代码(可以复制/粘贴和运行 - 不需要布局文件)

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.Gravity;
import android.widget.RelativeLayout;
import android.widget.TextView;


public class MyActivity extends Activity {

    private final int TEXT_VIEW_WIDTH_PX = 400;
    private final int TEXT_VIEW_HEIGHT_PX = 60;
    private Paint borderPaint = new Paint();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        RelativeLayout rootView = new RelativeLayout(this);
        getWindow().setContentView(rootView);

        borderPaint.setColor(Color.RED);

        MyTextView text1 = makeTextView("Grav=TL ; SL=F",100);
        rootView.addView(text1);

        MyTextView text2 = makeTextView("Grav=C ; SL=T",200);
        //combination of the 2 following attributes cause the issue
        text2.setSingleLine(true);
        text2.setGravity(Gravity.CENTER);
        rootView.addView(text2);

        MyTextView text3 = makeTextView("Grav=C ; SL=F",300);
        text3.setGravity(Gravity.CENTER);
        rootView.addView(text3);

        MyTextView text4 = makeTextView("Grav=TL ; SL=T",400);
        text4.setSingleLine(true);
        rootView.addView(text4);
    }

    /**
     * Custom TextView with red border
     */
    private class MyTextView extends TextView {

        private MyTextView(Context context) {
            super(context);
        }

        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            canvas.drawLine(1,1,1,TEXT_VIEW_HEIGHT_PX-1,borderPaint);
            canvas.drawLine(1,1,TEXT_VIEW_WIDTH_PX-1,1,borderPaint);
            canvas.drawLine(TEXT_VIEW_WIDTH_PX-1,1,TEXT_VIEW_WIDTH_PX-1,TEXT_VIEW_HEIGHT_PX-1,borderPaint);
            canvas.drawLine(1,TEXT_VIEW_HEIGHT_PX-1,TEXT_VIEW_WIDTH_PX-1,TEXT_VIEW_HEIGHT_PX-1,borderPaint);
        }
    }


    /**
     * create a MyTextView with 'text' context and located at x=50 ; y=marginTop
     * (nothing relevant for the issue here)
     */
    private MyTextView makeTextView(String text, int marginTop){
        MyTextView textView = new MyTextView(this);
        textView.setText(text);
        RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(TEXT_VIEW_WIDTH_PX,TEXT_VIEW_HEIGHT_PX);
        lp.topMargin = marginTop;
        lp.leftMargin = 50;
        textView.setLayoutParams(lp);
        return textView;
    }

}
Run Code Online (Sandbox Code Playgroud)

And*_* T. 7

感谢pskink的深入研究(来自对我的另一个答案的评论):

如果你想知道为什么自定义onDraw不绘制任何东西,只需要Log.d的值canvas.getMatrix().

[它]似乎画布被翻译/水平滚动(至少在我的情况下)左边8159像素,所以调用canvas.translate(8159, 0)修复了问题,当然8159不是一个神奇的数字,可以变化.

我发现它,看到VERY_WIDE常数TextView,它设置为16384(2**14),在我的情况下TextView宽度为66,现在(16384-66)/ 2 == 8159,瞧!

...但是VERY_WIDE是私有的,所以你无法访问它:-(

从这里开始,我想知道是否可以通过编程方式检索偏移量,并确保它可以轻松实现getScrollX().这种方法通过取消水平滚动来转换画布而不是"黑客"单行.它更自然地显示单行.

内部定制TextView:

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    // translate the canvas before drawing onto it, fixing the position
    canvas.translate(getScrollX(), 0);

    canvas.drawLine(1, 1, 1, TEXT_VIEW_HEIGHT_PX - 1, borderPaint);
    canvas.drawLine(1, 1, TEXT_VIEW_WIDTH_PX - 1, 1, borderPaint);
    canvas.drawLine(TEXT_VIEW_WIDTH_PX - 1, 1, TEXT_VIEW_WIDTH_PX - 1,
        TEXT_VIEW_HEIGHT_PX - 1, borderPaint);
    canvas.drawLine(1, TEXT_VIEW_HEIGHT_PX - 1, TEXT_VIEW_WIDTH_PX - 1,
        TEXT_VIEW_HEIGHT_PX - 1, borderPaint);
}
Run Code Online (Sandbox Code Playgroud)

此代码尚未针对所有情况进行彻底测试.我只确认了OP提供的4个案例