[英]How to correctly draw text in an extended class for TextView?
我目前正致力于扩展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);
}
}
呸,这对我来说很愚蠢。 我只需要更改注释掉的行:
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);
}
}
我已经暂时搁置了一些这些例子,因为似乎没有一个正确排列,并且一旦我终于掌握了文本发生的事情并把我的数学帽子放在上面,我就改变了我的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);
}
结果证明,数学和矩形计算要远远少于许多使用的解决方案。
编辑:忘记提及我在初始化中复制超级文本标志并且不要强制它居中。 此处计算的drawText位置始终是描边文本的正确居中位置。
我一直试图让它工作一段时间,我有一个解决方案,但它仅适用于特殊情况! 可以获取TextView
用于绘制文本的Layout
对象。 您可以创建此对象的副本,并在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
和不同的重力。 最终这段代码的性能非常差,因为它在每次绘制时都会分配一个Layout
对象。 我不明白它究竟是如何工作的,所以我不想使用它。
TextView
类中有一些属性,如android:shadowColor
, android:shadowDx
, android:shadowDy
和android:shadowRadius
。 在我看来,他们做同样的事情你想要实现。 所以也许你应该先尝试一个简单的TextView
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.