Android之文字描边

来源:互联网 发布:python能开发界面吗 编辑:程序博客网 时间:2024/06/07 19:03

结果是最不重要的,重要的是过程
* [问题] 本文主要解决白色背景下,白色的文字看不见的问题
* [解决思路] 给文字加阴影,ios下很好解决,苹果提供了很好 View.layer.shadow**属性,奈何android虽然提供了,但是效果不好, 解决方案是利用TextView在onDraw的时候,获取到画笔,先进行一次比默认大小的文字内容稍微大一点的绘制,然后再进行一次默认大小的文字内容的绘制,这样就产生出了描边效果
* [效果图] 这里写图片描述 这里写图片描述
* [核心代码分析] 这个方案可以使用在自定义view时加阴影,如果你画一个矩形,就可以使用这段代码加一圈阴影

    // 绘制阴影,使用空心画笔,宽度加宽    mPaint.setColor(mShadowColor);    mPaint.setStyle(Paint.Style.STROKE);    mPaint.setStrokeWidth(3);    mPaint.setFakeBoldText(true); // 外层text采用粗体    // todo 此处需要执行绘制操作    // 正常绘制,恢复画笔    mPaint.setStyle(Paint.Style.FILL);    mPaint.setStrokeWidth(0);    mPaint.setFakeBoldText(false);

比如画阴影矩形

 private void drawInternal(Canvas canvas) {        drawShadow(canvas, mUpBarRect);        mPaint.setColor(mColor);        canvas.drawRoundRect(mUpBarRect, mBarRoundX, mBarRoundY, mPaint);    }    private void drawShadow(Canvas canvas, RectF rect) {        mPaint.setColor(mShadowColor);        mPaint.setStyle(Paint.Style.STROKE);        mPaint.setStrokeWidth(3);        mPaint.setFakeBoldText(true); // 外层text采用粗体        canvas.drawRoundRect(rect, mBarRoundX, mBarRoundY, mPaint);        mPaint.setStyle(Paint.Style.FILL);        mPaint.setStrokeWidth(0);        mPaint.setFakeBoldText(false);    }

附上完整代码:

/** * TextView 文字描边 * 是利用TextView在onDraw的时候,获取到画笔,先进行一次比默认大小的文字内容稍微大一点的绘制,然后再进行一次默认大小的文字内容的绘制,这样就产生出了描边效果 * Created by slack * on 17/9/6 下午3:43 */public class WrapTextView extends AppCompatTextView {    private @ColorInt int mBorderColor = Color.GRAY;    private @ColorInt int mInnerColor = Color.WHITE;    private boolean mBorderText = true;    private TextPaint mTextPaint;    public WrapTextView(Context context) {        this(context, null);    }    public WrapTextView(Context context, @Nullable AttributeSet attrs) {        this(context, attrs, android.R.attr.textViewStyle);    }    public WrapTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        mTextPaint = this.getPaint();        mInnerColor = getCurrentTextColor();    }    /**     * onDraw  draw border first     */    @Override    protected void onDraw(Canvas canvas) {        if(mBorderText) {            // 描外层            setTextColorUseReflection(mBorderColor);            mTextPaint.setStrokeWidth(2); // 描边宽度            mTextPaint.setStyle(Paint.Style.STROKE); // 画笔空心            mTextPaint.setFakeBoldText(true); // 外层text采用粗体            super.onDraw(canvas);            // 描内层,恢复原先的画笔            setTextColorUseReflection(mInnerColor);            mTextPaint.setStrokeWidth(0);            mTextPaint.setStyle(Paint.Style.FILL);            mTextPaint.setFakeBoldText(false);        }        super.onDraw(canvas);    }    /**     * 使用反射的方法进行字体颜色的设置     * 其实就是 this.setTextColor(); 但是这个系统方法里会调用invalidate(); 最终的效果导致这段代码无限循环     * 反射部分:     * 1. Class.getDeclaredField(String name); 返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段(包括私有成员)     * 2. 获取私有属性的时候必须先设置Accessible为true,然后才能获取     * 3. 通过Field.get(Object obj)获取属性的值,通过Field.set(Object obj,value)重新设置新的属性值     */    private void setTextColorUseReflection(int color) {        Field textColorField;        try {            textColorField = TextView.class.getDeclaredField("mCurTextColor");            textColorField.setAccessible(true);            textColorField.set(this, color);            textColorField.setAccessible(false);        } catch (NoSuchFieldException e) {            e.printStackTrace();        } catch (IllegalArgumentException e) {            e.printStackTrace();        } catch (IllegalAccessException e) {            e.printStackTrace();        }        mTextPaint.setColor(color);    }}