前段時間的需求,涉及到大量帶各種效果的字體的使用,比如描邊、漸變、陰影等。一般情況下,我們在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點了,睡覺睡覺,狗命要緊。。。