6

我目前正在扩展 TextView,在文本周围添加轮廓。到目前为止,我遇到的唯一问题是我无法将“大纲”正确定位在文本后面。如果我像下面描述的那样对扩展类进行编码,我会得到一个如下所示的标签:

注意:在上面的截图中,我将填充颜色设置为白色,描边颜色设置为黑色。

我究竟做错了什么?

public class OutlinedTextView extends TextView {
    /* ===========================================================
     * Constants
     * =========================================================== */
    private static final float OUTLINE_PROPORTION = 0.1f;

    /* ===========================================================
     * Members
     * =========================================================== */
    private final Paint mStrokePaint = new Paint();
    private int mOutlineColor = Color.TRANSPARENT;

    /* ===========================================================
     * Constructors
     * =========================================================== */
    public OutlinedTextView(Context context) {
        super(context);
        this.setupPaint();
    }
    public OutlinedTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.setupPaint();
        this.setupAttributes(context, attrs);
    }
    public OutlinedTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        this.setupPaint();
        this.setupAttributes(context, attrs);
    }

    /* ===========================================================
     * Overrides
     * =========================================================== */
    @Override
    protected void onDraw(Canvas canvas) {
        // Get the text to print
        final float textSize = super.getTextSize();
        final String text = super.getText().toString();

        // setup stroke
        mStrokePaint.setColor(mOutlineColor);
        mStrokePaint.setStrokeWidth(textSize * OUTLINE_PROPORTION);
        mStrokePaint.setTextSize(textSize);
        mStrokePaint.setFlags(super.getPaintFlags());
        mStrokePaint.setTypeface(super.getTypeface());

        // Figure out the drawing coordinates
        //mStrokePaint.getTextBounds(text, 0, text.length(), mTextBounds);

        // draw everything
        canvas.drawText(text,
                super.getWidth() * 0.5f, super.getBottom() * 0.5f,
                mStrokePaint);
        super.onDraw(canvas);
    }

    /* ===========================================================
     * Private/Protected Methods
     * =========================================================== */
    private final void setupPaint() {
        mStrokePaint.setAntiAlias(true);
        mStrokePaint.setStyle(Paint.Style.STROKE);
        mStrokePaint.setTextAlign(Paint.Align.CENTER);
    }
    private final void setupAttributes(Context context, AttributeSet attrs) {
        final TypedArray array = context.obtainStyledAttributes(attrs,
                R.styleable.OutlinedTextView);
        mOutlineColor = array.getColor(
                R.styleable.OutlinedTextView_outlineColor, 0x00000000);
        array.recycle(); 

        // Force this text label to be centered
        super.setGravity(Gravity.CENTER_HORIZONTAL);
    }
}
4

4 回答 4

5

呸,那是我的愚蠢。我只需要更改注释掉的行:

super.getPaint().getTextBounds(text, 0, text.length(), mTextBounds);

另外,为了实际渲染文本,我需要平均这个视图的高度和文本的高度:

// draw everything
canvas.drawText(text,
    super.getWidth() * 0.5f, (super.getHeight() + mTextBounds.height()) * 0.5f,
    mStrokePaint);

整个代码现在如下所示:

public class OutlinedTextView extends TextView {
    /* ===========================================================
     * Constants
     * =========================================================== */
    private static final float OUTLINE_PROPORTION = 0.1f;

    /* ===========================================================
     * Members
     * =========================================================== */
    private final Paint mStrokePaint = new Paint();
    private final Rect mTextBounds = new Rect();
    private int mOutlineColor = Color.TRANSPARENT;

    /* ===========================================================
     * Constructors
     * =========================================================== */
    public OutlinedTextView(Context context) {
        super(context);
        this.setupPaint();
    }
    public OutlinedTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.setupPaint();
        this.setupAttributes(context, attrs);
    }
    public OutlinedTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        this.setupPaint();
        this.setupAttributes(context, attrs);
    }

    /* ===========================================================
     * Overrides
     * =========================================================== */
    @Override
    protected void onDraw(Canvas canvas) {
        // Get the text to print
        final float textSize = super.getTextSize();
        final String text = super.getText().toString();

        // setup stroke
        mStrokePaint.setColor(mOutlineColor);
        mStrokePaint.setStrokeWidth(textSize * OUTLINE_PROPORTION);
        mStrokePaint.setTextSize(textSize);
        mStrokePaint.setFlags(super.getPaintFlags());
        mStrokePaint.setTypeface(super.getTypeface());

        // Figure out the drawing coordinates
        super.getPaint().getTextBounds(text, 0, text.length(), mTextBounds);

        // draw everything
        canvas.drawText(text,
                super.getWidth() * 0.5f, (super.getHeight() + mTextBounds.height()) * 0.5f,
                mStrokePaint);
        super.onDraw(canvas);
    }

    /* ===========================================================
     * Private/Protected Methods
     * =========================================================== */
    private final void setupPaint() {
        mStrokePaint.setAntiAlias(true);
        mStrokePaint.setStyle(Paint.Style.STROKE);
        mStrokePaint.setTextAlign(Paint.Align.CENTER);
    }
    private final void setupAttributes(Context context, AttributeSet attrs) {
        final TypedArray array = context.obtainStyledAttributes(attrs,
                R.styleable.OutlinedTextView);
        mOutlineColor = array.getColor(
                R.styleable.OutlinedTextView_outlineColor, 0x00000000);
        array.recycle(); 

        // Force this text label to be centered
        super.setGravity(Gravity.CENTER_HORIZONTAL);
    }
}
于 2010-12-04T00:26:40.100 回答
4

一段时间以来,我一直在处理其中一些示例,因为似乎没有一个完全正确,一旦我终于掌握了文本发生的事情并戴上我的数学帽子,我将我的 onDraw 更改为如下所示,无论文本大小或它包含的视图大小和形状如何,它都可以完美放置......

@Override
protected void onDraw(Canvas canvas) {
    if (!isInEditMode()){
        // Get the text to print
        final float textSize = super.getTextSize();
        final String text = super.getText().toString();

        // setup stroke
        mStrokePaint.setColor(mOutlineColor);
        mStrokePaint.setStrokeWidth(textSize * mOutlineSize);
        mStrokePaint.setTextSize(textSize);
        mStrokePaint.setFlags(super.getPaintFlags());
        mStrokePaint.setTypeface(super.getTypeface());

        // draw everything
        canvas.drawText(text,
                (this.getWidth()-mStrokePaint.measureText(text))/2, this.getBaseline(),
                mStrokePaint);
    }
    super.onDraw(canvas);
}

事实证明,数学和 Rect 计算也比使用的许多解决方案少得多。

编辑:忘了提到我在初始化时复制了 super 的 textalign 并且不要强迫它居中。此处计算的 drawText 位置始终是描边文本的正确居中位置。

于 2011-04-27T22:09:27.783 回答
2

我一直在努力让它工作一段时间,我有一个解决方案,但它仅适用于特殊情况!可以获取用于绘制文本Layout的对象。TextView您可以创建此对象的副本并在onDraw(Canvas)方法中使用它。

    final Layout originalLayout = super.getLayout();
    final Layout layout = new StaticLayout(text, mStrokePaint,
    originalLayout.getWidth(), originalLayout.getAlignment(),
    originalLayout.getSpacingMultiplier(), originalLayout.getSpacingAdd(), true);

    canvas.save();
    canvas.translate( layout.getLineWidth(0) * 0.5f, 0.0f );
    layout.draw(canvas);
    canvas.restore();

但我确信这不是绘制轮廓的好方法。我不知道如何跟踪TextView.getLayout()对象的变化。它也不适用于 multilineTextView和不同的重力。最终这段代码的性能很差,因为它Layout在每次绘制时都分配一个对象。我不完全了解它是如何工作的,所以我不想使用它。

于 2010-12-03T20:45:09.487 回答
0

类中有一些属性,TextView例如android:shadowColor、和。在我看来,他们做的事情和你想要实现的一样。所以也许你应该先尝试一个简单的。android:shadowDxandroid:shadowDyandroid:shadowRadiusTextView

于 2010-12-03T06:53:39.260 回答