Android描邊字體的實現

        前段時間的需求,涉及到大量帶各種效果的字體的使用,比如描邊、漸變、陰影等。一般情況下,我們在Android開發中用到花裏胡哨字體的情況不多。但是,拿到了這樣的需求,我們還是要實現這樣一款支持多種效果的字體。其實,網上也有一些實現各種效果字體的方法。這篇博客,將把描邊,漸變,陰影等結合到一起,實現一款自定義的文本框。

一.擼代碼前的思考

        在開始動手之前,我們先明確一下需求。需求就是:一款支持描邊、漸變、陰影效果的字體。爲了實現上述的需求,我們需要做下面的工作:

1.文本框具有描邊的屬性

(1)是否描邊:isStroke

(2)描邊的顏色:strokeColor

(3)描邊的寬度:strokeWidth

2.文本框具有顏色漸變的屬性

(1)是否漸變:isGradient

(2)漸變是否是豎向的:isVertical

(3)漸變的起始顏色:startColor

(4)漸變的終止顏色:endColor

3.文本框具有陰影的屬性

(1)是否顯示陰影:isShadow

(2)陰影的顏色:shadowColor

(3)x方向的陰影:shadowX

(4)y方向的陰影:shadowY

(5)陰影的半徑:shadowRadius

二.開始擼代碼

1.在values文件夾下創建attrs.xml文件,把我們需求裏的屬性都定義好:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="GradientTextView">
        <attr name="startColor" format="color" />
        <attr name="endColor" format="color" />
        <attr name="strokeColor" format="color"/>
        <attr name="strokeWidth" format="dimension"/>
        <attr name="isStroke" format="boolean" />
        <attr name="isGradient" format="boolean" />
        <attr name="isVertical" format="boolean" />
        <attr name="isShadow" format="boolean"/>
        <attr name="shadowX" format="integer"/>
        <attr name="shadowY" format="integer"/>
        <attr name="shadowRadius" format="integer"/>
        <attr name="shadowColor" format="color"/>
    </declare-styleable>
</resources>

2.初始化屬性:

private void initAttrs(Context context, AttributeSet attrs) {
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.GradientTextView);
        startColor = ta.getColor(R.styleable.GradientTextView_startColor, 0xfffff8);
        endColor = ta.getColor(R.styleable.GradientTextView_endColor, 0xffd007);
        strokeColor = ta.getColor(R.styleable.GradientTextView_strokeColor, 0x2a1505);
        strokeWidth = ta.getDimension(R.styleable.GradientTextView_strokeWidth, 0);
        isStroke = ta.getBoolean(R.styleable.GradientTextView_isStroke, false);
        isGradient = ta.getBoolean(R.styleable.GradientTextView_isGradient, false);
        isVertical = ta.getBoolean(R.styleable.GradientTextView_isVertical, true);
        useTypeface = ta.getBoolean(R.styleable.GradientTextView_useTypeface, false);
        isShadow = ta.getBoolean(R.styleable.GradientTextView_isShadow, false);
        shadowX = ta.getInt(R.styleable.GradientTextView_shadowX, 1);
        shadowY = ta.getInt(R.styleable.GradientTextView_shadowY, 1);
        shadowRadius = ta.getInt(R.styleable.GradientTextView_shadowRadius, 1);
        shadowColor = ta.getColor(R.styleable.GradientTextView_shadowColor, 0x000000);
}

3.根據屬性判斷是否需要應用效果:

(1)描邊

        這裏簡單說下描邊的實現:其實就是繪製兩個不一樣大的TextView,大一點的就是描邊的顏色,小一點的就是我們需要的字體的顏色,因此,我們需要創建一個新的TextView來實現描邊:

if (isStroke) {
        backGroundText = new TextView(context, attrs);
        TextPaint tp1 = backGroundText.getPaint();
        tp1.setStrokeWidth(strokeWidth);
        tp1.setStyle(Paint.Style.STROKE);
        backGroundText.setTextColor(strokeColor);
        backGroundText.setGravity(getGravity());
        }

(2)漸變

        漸變的實現,其實就是設置一個Shader,也就是LinearGradient。說起Linear,我們就想起LinearLayout的Vertical和Horizontal屬性,LinearGradient也需要一個標誌着橫向或者豎向的屬性。因此,我們需要根據橫向漸變還是豎向漸變去設置對應的shader:

if (isGradient) {
            if (isVertical) {
                mLinearGradient = new LinearGradient(0, 0, 0,
                        this.getPaint().getTextSize(),
                        startColor,
                        endColor,
                        Shader.TileMode.CLAMP);
            } else {
                mLinearGradient = new LinearGradient(0, 0, this.getWidth(),
                        0,
                        startColor,
                        endColor,
                        Shader.TileMode.CLAMP);
            }
        }

(3)陰影

        陰影的實現,不得不說,確實費了些時間。我們都知道TextView本身就支持陰影效果。但是,我們自定義的字體,如果直接使用自帶的陰影效果,會非常模糊,根本不是陰影的效果。因此,陰影的效果也需要我們自己去實現。實現的要點是:爲TextView設置Layer,在設置完後,必須清空Layer再去繪製其他的地方。在這裏,我就直接把所有的繪製貼出來了:

@Override
    protected void onDraw(Canvas canvas) {
        if (isShadow) {
            getPaint().setShadowLayer(shadowRadius, shadowX, shadowY, shadowColor);
            getPaint().setShader(null);
            super.onDraw(canvas);

            getPaint().clearShadowLayer();
            getPaint().setShader(mLinearGradient);
            super.onDraw(canvas);
        } else {
            if (isStroke) {
                if (backGroundText != null) {
                    CharSequence tt = backGroundText.getText();
                    if (tt == null || !tt.equals(this.getText())) {
                        backGroundText.setText(getText());
                        this.postInvalidate();
                    }
                }
                backGroundText.draw(canvas);
            }
            if (isGradient) {
                this.getPaint().setShader(mLinearGradient);
            }
        }
        super.onDraw(canvas);
    }

大家看到上面的代碼,可能有些疑惑,在這裏簡單的說明一下:

(1)如果直接應用TextView自帶的陰影屬性,會很模糊,其實是把漸變的shader作爲了陰影。因此,我們設置layer,同時設置shader爲空。

(2)設置完layer後,先繪製陰影。繪製完陰影后,清空layer,設置漸變的屬性,繼續繪製漸變的效果。

(3)如果我們的文本內容是會變化的,那麼我們需要及時同步描邊的字體和文本內容的一致。因此,判斷有描邊的屬性時,我們需要做一下文本的同步。

三.在佈局文件中使用

    <com.example.mygradient.GradientTextView
        android:id="@+id/tv2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="12:45"
        android:textSize="18sp"
        app:endColor="#ffd007"
        app:isGradient="true"
        app:isStroke="false"
        app:isVertical="true"
        app:isShadow="true"
        app:shadowColor="#df000000"
        app:shadowRadius="1"
        app:shadowX="1"
        app:shadowY="1"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/tv1"
        app:startColor="#fffff8"
        app:useTypeface="false" />

        以上就是多效果文本框的實現,核心的代碼都已經給出,需要說明的地方也已經在上面詳細說明了。一不小心就凌晨1點了,睡覺睡覺,狗命要緊。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章