概述
Android自定義view繪製顏色的時候,可以通過setShader可以讓view繪製多彩漸變的效果。Android sdk中提供了五個Shader子類供開發者使用,分別是:LinearGradient線性漸變 SweetGradient角度漸變 RadialGradient輻射漸變 BitmapShader圖片shader和ComposeShader組合着色器。本文將結合例子對線性漸變做一個介紹。
LinearGradient 線性漸變
構造函數參數說明
public LinearGradient(float x0, float y0, float x1, float y1,
@ColorInt int color0, @ColorInt int color1,
@NonNull TileMode tile)
該構造函數前四個參數代碼顏色漸變的起點(x0,y0)和結束點(x1,y1)參數color0與color1代表startColor和endColor。TitleModel 有三個值(CLAMP、MIRROR、REPEAT)代表漸變模式。
列子代碼:
public LinearGradient(float x0, float y0, float x1, float y1, @NonNull @ColorInt int colors[],
@Nullable float positions[], @NonNull TileMode tile)
該構造函數前四個參數代碼顏色漸變的起點(x0,y0)和結束點(x1,y1)參數colors數組代表漸變過度顏色,positions數組代表各過度色的起點位置(浮點類型)。TitleModel 有三個值(CLAMP、MIRROR、REPEAT)代表漸變模式。
例子代碼
package com.xol.widget;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import com.xol.util.CommonUtil;
/**
* Created by wwzhang on 2019/3/14
*/
public class LinearGradientView extends View {
private Paint mPaint;
private LinearGradient mLinearGradient;
private int mWidthNum = 3;
private int mHeightNum = 3;
private int[] colorThree;
private int[] colorTwo;
private int mSpace;
private float mWidth = 0;
private float mRectRadius = 5;
private String mContentText = "非淡泊無以明智,非寧靜無以致遠";
public LinearGradientView(Context context) {
super(context);
}
public LinearGradientView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public LinearGradientView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
{
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setTextSize(CommonUtil.sp2px(16, getContext()));
mRectRadius = CommonUtil.dp2px(mRectRadius, getContext());
colorThree = new int[]{
Color.parseColor("#ff0000"),
Color.parseColor("#00ff00"),
Color.parseColor("#0000ff")};
colorTwo = new int[]{Color.parseColor("#ff0000"),
Color.parseColor("#0000ff")};
mSpace = (int) CommonUtil.dp2px(2, getContext());
mPaint.setColor(Color.parseColor("#AAAAAA"));
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawLinearRound(canvas);
}
public void drawLinearRound(Canvas canvas) {
//繪製兩色漸變
int rectHeight = (int) CommonUtil.dp2px(20, getContext());
int space = 10;
//水平clamp
mLinearGradient = new LinearGradient(0, 0, getMeasuredWidth() / 2,
0, colorTwo[0], colorTwo[1], Shader.TileMode.CLAMP);
mPaint.setShader(mLinearGradient);
canvas.drawRect(0, 0 + space, getMeasuredWidth(), rectHeight + space, mPaint);
// 水平mirror
mLinearGradient = new LinearGradient(0, 0, getMeasuredWidth() / 2,
0, colorTwo[0], colorTwo[1], Shader.TileMode.MIRROR);
mPaint.setShader(mLinearGradient);
canvas.drawRect(0, rectHeight + space * 2, getMeasuredWidth(),
(rectHeight << 1) + space * 2, mPaint);
//水平repeat
mLinearGradient = new LinearGradient(0, 0, getMeasuredWidth() / 2,
0, colorTwo[0], colorTwo[1], Shader.TileMode.REPEAT);
mPaint.setShader(mLinearGradient);
canvas.drawRect(0, (rectHeight << 1) + space * 3, getMeasuredWidth(),
(rectHeight << 1) + rectHeight + space * 3, mPaint);
//對角線mirror漸變
mLinearGradient = new LinearGradient(0, 0, 20, 20,
colorTwo[0], colorTwo[1], Shader.TileMode.MIRROR);
mPaint.setShader(mLinearGradient);
canvas.drawRect(0, (rectHeight << 1) + rectHeight + space * 4, getMeasuredWidth(),
(rectHeight << 2) + space * 4, mPaint);
//計算
if (mWidth < 5) {
mWidth = (getMeasuredWidth() - (mWidthNum + 1) * mSpace) / mWidthNum;
mHeightNum = (int) (getMeasuredHeight() - CommonUtil.dp2px(120, getContext()) / mWidth);
}
//繪製三色漸變
int count = 0;
RectF rectF = new RectF();
for (int i = 0; i < mHeightNum; i++) {
rectF.top = i * mWidth + (i + 1) * mSpace + (int) CommonUtil.dp2px(120, getContext());
rectF.bottom = rectF.top + mWidth;
for (int j = 0; j < mWidthNum; j++) {
rectF.left = j * mWidth + (j + 1) * mSpace;
rectF.right = rectF.left + mWidth;
count++;
if (count > 9) {
break;
}
switch (count) {
case 1:
mLinearGradient = new LinearGradient(rectF.left, rectF.top,
rectF.left + (rectF.right - rectF.left) / 2, rectF.top + (rectF.bottom - rectF.top) / 2, colorThree,
new float[]{0.0f, 0.66f, 1.0f}, Shader.TileMode.REPEAT);
mPaint.setShader(mLinearGradient);
break;
case 2:
mLinearGradient = new LinearGradient(rectF.left, rectF.top,
rectF.left + (rectF.right - rectF.left) / 2, rectF.top + (rectF.bottom - rectF.top) / 2, colorThree,
new float[]{0.0f, 0.66f, 1.0f}, Shader.TileMode.MIRROR);
mPaint.setShader(mLinearGradient);
break;
case 3:
mLinearGradient = new LinearGradient(rectF.left, rectF.top,
rectF.left + (rectF.right - rectF.left) / 2, rectF.top + (rectF.bottom - rectF.top) / 2, colorThree,
new float[]{0.0f, 0.66f, 1.0f}, Shader.TileMode.CLAMP);
mPaint.setShader(mLinearGradient);
break;
case 4:
mLinearGradient = new LinearGradient(rectF.left, rectF.top,
rectF.left + (rectF.right - rectF.left) / 2, rectF.top, colorThree,
new float[]{0.0f, 0.66f, 1.0f}, Shader.TileMode.REPEAT);
mPaint.setShader(mLinearGradient);
break;
case 5:
mLinearGradient = new LinearGradient(rectF.left, rectF.top,
rectF.left + (rectF.right - rectF.left) / 2, rectF.top, colorThree,
new float[]{0.0f, 0.66f, 1.0f}, Shader.TileMode.MIRROR);
mPaint.setShader(mLinearGradient);
break;
case 6:
mLinearGradient = new LinearGradient(rectF.left, rectF.top,
rectF.left + (rectF.right - rectF.left) / 2, rectF.top, colorThree,
new float[]{0.0f, 0.66f, 1.0f}, Shader.TileMode.CLAMP);
mPaint.setShader(mLinearGradient);
break;
case 7:
mLinearGradient = new LinearGradient(rectF.left, rectF.top,
rectF.right, rectF.bottom, colorThree,
new float[]{0.0f, 0.66f, 1.0f}, Shader.TileMode.REPEAT);
mPaint.setShader(mLinearGradient);
break;
case 8:
mLinearGradient = new LinearGradient(rectF.left, rectF.bottom,
rectF.right, rectF.bottom, colorThree,
new float[]{0.0f, 0.66f, 1.0f}, Shader.TileMode.REPEAT);
mPaint.setShader(mLinearGradient);
break;
case 9:
mLinearGradient = new LinearGradient(rectF.left, rectF.bottom,
rectF.right, rectF.bottom, colorThree,
new float[]{0.5f, 0.75f, 1.0f}, Shader.TileMode.REPEAT);
mPaint.setShader(mLinearGradient);
break;
default:
break;
}
canvas.drawRoundRect(rectF, mRectRadius, mRectRadius, mPaint);
}
}
}
}
佈局文件引入
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.xol.widget.LinearGradientView
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
運行結果:
線性漸變文字效果實現
閃動的文字
實現原理,通過matrix水平移動線性shader開始的位置,達到文字閃動的效果
歌詞逐字變色效果
實現原理,通過設置線性shader的變色位置,實現文字的逐漸變色。
示例代碼:
package com.xol.widget;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Shader;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import com.xol.util.CommonUtil;
/**
* Created by wwzhang on 2019/3/18
*/
public class LinearGradientTextView extends View implements Runnable {
private Paint mPaint;
private Matrix mMatrix;
private String mText;
private LinearGradient mLinearGradient;
private long mDuration = 50;
private int mTransX = 0;
private Rect rect = new Rect();
private LinearGradient mKrcLinearGradient;
private float[] mfKrc = new float[2];
private String mSingText;
private Paint mSingPaint;
public LinearGradientTextView(Context context) {
super(context);
}
public LinearGradientTextView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public LinearGradientTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
{
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mSingPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mMatrix = new Matrix();
mText = "疏疏晴雨弄斜陽,憑欄久,牆外杏花香";
mSingText = "很愛很愛你所以願意,不牽絆你";
mPaint.setTextSize(CommonUtil.dp2px(16, getContext()));
mSingPaint.setTextSize(CommonUtil.dp2px(16, getContext()));
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (null == mLinearGradient) {
mLinearGradient = new LinearGradient(0, 0, 200, 0,
new int[]{Color.parseColor("#440000"),
Color.parseColor("#ffffff"),
Color.parseColor("#440000")},
new float[]{0.0f, 0.5f, 1.0f}, Shader.TileMode.CLAMP);
mLinearGradient.setLocalMatrix(mMatrix);
mPaint.setShader(mLinearGradient);
mfKrc[0] = 0.0f;
mfKrc[1] = 0.0f;
mKrcLinearGradient = new LinearGradient(0, 0, getMeasuredWidth(), 0, new int[]{
Color.parseColor("#ff0000"),
Color.parseColor("#ffffff")},
mfKrc,
Shader.TileMode.CLAMP);
mSingPaint.setShader(mKrcLinearGradient);
postDelayed(this, mDuration);
}
mPaint.getTextBounds(mText, 0, mText.length(), rect);
canvas.drawText(mText, 0, rect.bottom - rect.top, mPaint);
canvas.drawText(mSingText, 0, getMeasuredHeight() / 2, mSingPaint);
}
@Override
public void run() {
mTransX += 10;
if (mTransX > rect.right - rect.left) {
mTransX = -10;
}
mfKrc[0] += 0.01f;
mfKrc[1] = mfKrc[0];
if (mfKrc[0] > 1.0f) {
mfKrc[0] = 0.0f;
mfKrc[1] = 0.0f;
}
mKrcLinearGradient = new LinearGradient(0, 0, getMeasuredWidth(), 0, new int[]{
Color.parseColor("#ff0000"),
Color.parseColor("#ffffff")},
mfKrc,
Shader.TileMode.CLAMP);
mSingPaint.setShader(mKrcLinearGradient);
mMatrix.setTranslate(mTransX, 0);
mLinearGradient.setLocalMatrix(mMatrix);
invalidate();
postDelayed(this, mDuration);
}
}
佈局文件
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.xol.widget.LinearGradientTextView
android:background="#888888"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
代碼運行效果
希望對您有所幫助!