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

私はしばらくの間、これらの例のいくつかをプラグインしてきました.次のようになり、テキストのサイズや、含まれているビューのサイズと形状に関係なく、完全に収まります...

@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 の計算がはるかに少ないことが判明しました。

編集:初期化でスーパーのテキストアラインをコピーし、強制的に中央に配置しないことを忘れていました。ここで計算された 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()オブジェクトの変更を追跡する方法がわかりません。TextViewまた、複数行の s や異なる重力では機能しません。Layoutそして最終的に、このコードは描画ごとにオブジェクトを割り当てるため、パフォーマンスが非常に低下します。仕組みがよくわからないので、使わないほうがいいです。

于 2010-12-03T20:45:09.487 に答える
0

TextViewクラスには、 、 、 などandroid:shadowColorandroid:shadowDxいくつかの属性がありandroid:shadowDyますandroid:shadowRadius。彼らはあなたが実装したいのと同じことをしているように思えます。ですからTextView、最初はシンプルなものを試してみてください。

于 2010-12-03T06:53:39.260 に答える