Android开发:文字描边
转自:http://www.oschina.net/code/snippet_586849_37287
1. [代码][Java]代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | package com.example.testproject; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint.Style; import android.text.TextPaint; import android.util.AttributeSet; import android.view.ViewGroup; import android.widget.TextView; /* * StrokeTextView的目标是给文字描边 * 实现方法是两个TextView叠加,只有描边的TextView为底,实体TextView叠加在上面 * 看上去文字就有个不同颜色的边框了 */ public class StrokeTextView extends TextView { private TextView borderText = null ; ///用于描边的TextView public StrokeTextView(Context context) { super (context); borderText = new TextView(context); init(); } public StrokeTextView(Context context, AttributeSet attrs) { super (context, attrs); borderText = new TextView(context,attrs); init(); } public StrokeTextView(Context context, AttributeSet attrs, int defStyle) { super (context, attrs, defStyle); borderText = new TextView(context,attrs,defStyle); init(); } public void init(){ TextPaint tp1 = borderText.getPaint(); tp1.setStrokeWidth( 4 ); //设置描边宽度 tp1.setStyle(Style.STROKE); //对文字只描边 borderText.setTextColor(getResources().getColor(R.color.border_text)); //设置描边颜色 borderText.setGravity(getGravity()); } @Override public void setLayoutParams (ViewGroup.LayoutParams params){ super .setLayoutParams(params); borderText.setLayoutParams(params); } @Override protected void onMeasure( int widthMeasureSpec, int heightMeasureSpec) { CharSequence tt = borderText.getText(); //两个TextView上的文字必须一致 if (tt== null || !tt.equals( this .getText())){ borderText.setText(getText()); this .postInvalidate(); } super .onMeasure(widthMeasureSpec, heightMeasureSpec); borderText.measure(widthMeasureSpec, heightMeasureSpec); } protected void onLayout ( boolean changed, int left, int top, int right, int bottom){ super .onLayout(changed, left, top, right, bottom); borderText.layout(left, top, right, bottom); } @Override protected void onDraw(Canvas canvas) { borderText.draw(canvas); super .onDraw(canvas); } } |
2. [代码][XML]代码
1 2 3 4 | <? xml version = "1.0" encoding = "utf-8" ?> < resources > < color name = "border_text" >#ffffff</ color > </ resources > |
3. [图片] miao_bian.png
最近在android上搞一个带描边效果的TextView,网上搜索了下都是采用两个TextView在一个layout中进行实现,但细想了下,如果我在一个TextView中让其以不同的方式进行两次描绘不就能够达到效果了吗?由于网上没有看到和我类似的方法,故发出来和大家分享,由于只需要重写protected void onDraw(Canvas canvas);方法即可,故只附上onDraw的实现:
- private boolean m_bDrawSideLine = false; // 默认不采用描边
- /* (non-Javadoc)
- * @see android.widget.TextView#onDraw(android.graphics.Canvas)
- */
- @Override
- protected void onDraw(Canvas canvas) {
- if (m_bDrawSideLine) {
- // 描外层
- //super.setTextColor(Color.BLUE); // 不能直接这么设,如此会导致递归
- setTextColorUseReflection(Color.BLUE);
- m_TextPaint.setStrokeWidth(3); // 描边宽度
- m_TextPaint.setStyle(Style.FILL_AND_STROKE); //描边种类
- m_TextPaint.setFakeBoldText(true); // 外层text采用粗体
- m_TextPaint.setShadowLayer(1, 0, 0, 0); //字体的阴影效果,可以忽略
- super.onDraw(canvas);
- // 描内层,恢复原先的画笔
- //super.setTextColor(Color.BLUE); // 不能直接这么设,如此会导致递归
- setTextColorUseReflection(Color.RED);
- m_TextPaint.setStrokeWidth(0);
- m_TextPaint.setStyle(Style.FILL_AND_STROKE);
- m_TextPaint.setFakeBoldText(false);
- m_TextPaint.setShadowLayer(0, 0, 0, 0);
- }
- super.onDraw(canvas);
- }
- private void setTextColorUseReflection(int color) {
- Field textColorField;
- try {
- textColorField = TextView.class.getDeclaredField("mCurTextColor");
- textColorField.setAccessible(true);
- textColorField.set(color);
- textColorField.setAccessible(false);
- } catch (NoSuchFieldException e) {
- e.printStackTrace();
- } catch (IllegalArgumentException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- }
- m_TextPaint.setColor(color);
- }
以上代码中m_bDrawSideLine为false即和一般的textView无异,只需要将其改为true即可看到描边效果。以上,我只是抛砖引玉,以下发一个小图吧。
package com.zg.mrcheney;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.FontMetrics;
import android.util.AttributeSet;
import android.widget.TextView;
public class StrokeText extends TextView {
private float mBigFontBottom;
private float mBigFontHeight;
private String text;
private Paint mPaint;
private int strokeSize = 1;
public StrokeText(Context context) {
super(context);
init();
}
public StrokeText(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public StrokeText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setTextSize(getTextSize());
mPaint.setColor(getResources().getColor(R.color.font_paint_color));
FontMetrics fm = mPaint.getFontMetrics();
mBigFontBottom = fm.bottom;
mBigFontHeight = fm.bottom - fm.top;
}
@Override
protected void onDraw(Canvas canvas) {
if (strokeSize > 0 && strokeSize < 4) {
float y = getPaddingTop() + mBigFontHeight - mBigFontBottom;
canvas.drawText(text, 0, y - strokeSize, mPaint);
canvas.drawText(text, 0, y + strokeSize, mPaint);
canvas.drawText(text, 0 + strokeSize, y, mPaint);
canvas.drawText(text, 0 + strokeSize, y + strokeSize, mPaint);
canvas.drawText(text, 0 + strokeSize, y - strokeSize, mPaint);
canvas.drawText(text, 0 - strokeSize, y, mPaint);
canvas.drawText(text, 0 - strokeSize, y + strokeSize, mPaint);
canvas.drawText(text, 0 - strokeSize, y - strokeSize, mPaint);
}
super.onDraw(canvas);
}
@Override
public void setText(CharSequence text, BufferType type) {
super.setText(text, type);
this.text = text.toString();
invalidate();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (strokeSize > 0 && strokeSize < 4) {
setMeasuredDimension(getMeasuredWidth() + strokeSize, getMeasuredHeight());
}
}
}