您的位置:首页 > 移动开发 > Android开发

Android自定义控件之Shader(着色器/渲染器)

2016-10-08 22:27 162 查看

Android自定义控件之Shader(着色器/渲染器)

在Paint有一个方法

mPaint.setShader(Shader shader);


Shader有五个子类:



BitmapShader,

ComposeShader,

LinearGradient,

RadialGradient,

SweepGradient

在这几种子类的构造中可能会用到Shader.TileMode

Shader.TileMode有三种模式:

Shader.TileMode.CLAMP 最后一个像素进行拉伸填充

Shader.TileMode.MIRROR 镜像

Shader.TileMode.REPEAT 重复

1.BitmapShader : 用一张图片进行着色

它只有一个构造方法:

/**
* @param bitmap    着色中使用的位图
* @param tileX     X方向上绘图模式
* @param tileY     Y方向上绘图模式
*/
BitmapShader (Bitmap bitmap, Shader.TileMode tileX, Shader.TileMode tileY)


学习了这些知识点可以做一个小练习,望远镜效果

public class TelescopeView extends View {

//画笔:一个绘制圆的画笔,一个绘制边框的画笔
private Paint mPaint,strokePaint;
//圆心
private float posX, posY;
//半径
private int radios = 200;
//是否显示望远镜头
private boolean isShow;

public TelescopeView(Context context) {
this(context, null);
}

public TelescopeView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

public TelescopeView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
//初始化
private void init() {
//创建望远镜画笔
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
//设置图片着色器
mPaint.setShader(new BitmapShader(BitmapFactory.decodeResource(getResources(), R.mipmap.one_bg), Shader.TileMode.REPEAT, Shader.TileMode.MIRROR));

//创建边框画笔
strokePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
strokePaint.setStyle(Paint.Style.STROKE);
strokePaint.setColor(Color.BLACK);
strokePaint.setStrokeWidth(10);

}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.GRAY);
if (isShow) {
canvas.drawCircle(posX, posY, radios, mPaint);
canvas.drawCircle(posX,posY, radios,strokePaint);
}
}

@Override
public boolean onTouchEvent(MotionEvent event) {

switch (event.getAction()) {
c
e7cd
ase MotionEvent.ACTION_DOWN:
isShow = true;
posX = event.getX();
posY = event.getY();
postInvalidate();
break;
case MotionEvent.ACTION_MOVE:
posX = event.getX();
posY = event.getY();
postInvalidate();
break;
case MotionEvent.ACTION_UP:
isShow = false;
postInvalidate();
break;
}

return true;
}
}




2.LinearGradient 线性着色器

构造:

/**
@param x0       开始的X坐标
@param y0       开始的Y坐标
@param x1       结束的X坐标
@param y1       结束的Y坐标
@param  color0  起始的颜色
@param  color1  结束的颜色
@param  tile    TileMode模式
*/
public LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1,
TileMode tile)


/** Create a shader that draws a linear gradient along a line.
@param x0           开始的X坐标
@param y0           开始的Y坐标
@param x1           结束的X坐标
@param y1           结束的Y坐标
@param  colors      颜色组
@param  positions   这个参数可以为null,
如果为null则所有颜色均匀分布,
如果不为空则数组个数必须与颜色的个数相等,
并且元素大小在0-1之间,代表从百分之多少开始对应的颜色
@param  tile        TileMode模式
*/
public LinearGradient(float x0, float y0, float x1, float y1, int colors[], float positions[],
TileMode tile)


了解了构造就可以来简单实现以下了

构造 1:

public LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1,TileMode tile)

mPaint.setShader(new LinearGradient(0,0,getWidth(),getHeight(), Color.RED,Color.GREEN, Shader.TileMode.CLAMP));




因为在这行代码中我设置的是自定义控件整个的大小,所以Shader.TileMode改变了并看不出来什么影响。

如果我设置成这样就可以看出效果了

mPaint.setShader(new LinearGradient(0,0,getWidth()/2,getHeight()/2, Color.RED,Color.GREEN, Shader.TileMode.REPEAT));




变成了这个样子,其他效果可以自己来做一做

构造 2:

public LinearGradient(float x0, float y0, float x1, float y1, int colors[], float positions[],TileMode tile)

mPaint.setShader(new LinearGradient(0,0,getWidth(),getHeight(),new int[]{Color.BLUE,Color.CYAN,Color.RED,Color.YELLOW,Color.GREEN},new float[]{0,0.3f,0.7f,0.8f,0.9f}, Shader.TileMode.MIRROR));


效果:



用这个着色器可以做一个小练习,图片的倒影效果,附上自定义控件代码

public class ReflectionsView extends View {

//倒影和源图的间距
private static final int JULI = 10;
//画笔
private Paint mPaint;
//源图和倒影图
private Bitmap srcBit,daoBit;
//图片的起始X,Y
private int bitX,bitY;
//倒影图片的起始和宽高
float startX,startY, daoWid, daoHei;

public ReflectionsView(Context context) {
this(context,null);
}

public ReflectionsView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}

public ReflectionsView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}

private void init(Context context) {
//获取源图
srcBit = BitmapFactory.decodeResource(getResources(), R.mipmap.one_bg);
//通过矩阵翻转源图生成倒影
Matrix matrix = new Matrix();
matrix.setScale(1f,-1f);
//生成倒影图
daoBit = Bitmap.createBitmap(srcBit,0,srcBit.getHeight()-srcBit.getHeight()/3,srcBit.getWidth(),srcBit.getHeight()/3,matrix,true);
//获取屏幕宽高
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics dm = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(dm);
int sWid = dm.widthPixels;
int sHei = dm.heightPixels;
bitX = sWid/2-srcBit.getWidth()/2;
bitY = sHei/2-srcBit.getHeight()/2;

startX = bitX+srcBit.getWidth()/2;
startY = bitY+ JULI +srcBit.getHeight();
daoWid = startX;
daoHei = startY + srcBit.getHeight()/3;
//设置线性着色器
LinearGradient linearGradient = new LinearGradient(startX,startY, daoWid, daoHei,0x55000000, Color.TRANSPARENT, Shader.TileMode.CLAMP);
//创建画笔
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
//设置着色器
mPaint.setShader(linearGradient);
//设置混合模式Xfermode;
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));

}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//绘制源图
canvas.drawBitmap(srcBit,bitX,bitY,null);
//保存画布,用于处理Xfermode
int sl = canvas.saveLayer(bitX,startY,bitX+srcBit.getWidth(), daoHei,null,Canvas.ALL_SAVE_FLAG);
//绘制源图
canvas.drawBitmap(daoBit,bitX,bitY+ JULI +srcBit.getHeight(),null);
//绘制倒影的矩形
canvas.drawRect(0,0,getWidth(),getHeight(),mPaint);
//还原
canvas.restoreToCount(sl);

}
}




3.SweepGradient 角度渐变着色器

构造:

/**
* @param cx       该中心的X坐标
* @param cy       该中心的Y坐标
* @param color0   起始颜色
* @param color1   结束颜色
*/
public SweepGradient(float cx, float cy, int color0, int color1)


/**
* A subclass of Shader that draws a sweep gradient around a center point.
*
* @param cx        该中心的X坐标
* @param cy        该中心的Y坐标
* @param colors    颜色组
* @param positions 这个参数可以为null,
如果为null则所有颜色均匀分布,
如果不为空则数组个数必须与颜色的个数相等,
并且元素大小在0-1之间,代表从百分之多少开始对应的颜色
*/
public SweepGradient(float cx, float cy,
int colors[], float positions[])


这个类使用是蛮简单的,类似LinearGradient,就不累赘了

效果是这个样子





4.RadialGradient 径向渐变着色器

构造:

/**
@param centerX     圆心的X坐标
@param centerY     圆心的Y坐标
@param radius      径向渐变半径
@param centerColor 中心起始颜色
@param edgeColor   结束颜色
@param tileMode    TileMode模式
*/
public RadialGradient(float centerX, float centerY, float radius, int centerColor, int edgeColor, TileMode tileMode)


/** Create a shader that draws a radial gradient given the center and radius.
@param centerX  圆心的X坐标
@param centerY  圆心的Y坐标
@param radius   径向渐变半径
@param colors   颜色组
@param stops    这个参数可以为null,
如果为null则所有颜色均匀分布,
如果不为空则数组个数必须与颜色的个数相等,
并且元素大小在0-1之间,代表从百分之多少开始对应的颜色
@param tileMode TileMode模式
*/
public RadialGradient(float centerX, float centerY, float radius,
int colors[], float stops[], TileMode tileMode)


例 1:

mPaint.setShader(new RadialGradient(getWidth()/2,getHeight()/2,getWidth(), Color.YELLOW,Color.RED, Shader.TileMode.CLAMP));


效果:



例 2:

mPaint.setShader(new RadialGradient(getWidth()/2,getHeight()/2,getWidth(), new int[]{Color.BLUE,Color.CYAN,Color.RED,Color.YELLOW,Color.GREEN},null, Shader.TileMode.CLAMP));




这个有点吓人了,噗噗噗,将就看吧,嘿嘿

5.ComposeShader 着色器组合

构造:

/**
@param shaderA  渲染器A,Shader及其子类对象
@param shaderB  渲染器B,Shader及其子类对象
@param mode     两种渲染器组合的模式,ProterDuff.Mode对象
*/
public ComposeShader(Shader shaderA, Shader shaderB, PorterDuff.Mode mode)


/**
@param shaderA  渲染器A,Shader及其子类对象
@param shaderB  渲染器B,Shader及其子类对象
@param mode     两种渲染器组合的模式,Xfermode对象
*/
public ComposeShader(Shader shaderA, Shader shaderB, Xfermode mode)


使用方法也很简单

linearGradient = new LinearGradient(0,0,200,200,new int[]{Color.RED,Color.YELLOW,Color.WHITE,Color.BLACK,Color.CYAN},null, Shader.TileMode.REPEAT);
radialGradient = new RadialGradient(getWidth()/2,getHeight()/2,60,new int[]{Color.RED,Color.YELLOW,Color.WHITE,Color.BLACK,Color.CYAN},null, Shader.TileMode.MIRROR);
composeShader = new ComposeShader(linearGradient, radialGradient, PorterDuff.Mode.ADD);


效果:



注:混合着色器需要关闭硬件加速,否则无法显示。

setLayerType(LAYER_TYPE_SOFTWARE,null);


本文在之后会更新对应着色器的实例,向望远镜那样的。

我是个走在android“不归路”上的小白~~希望可以和大神们学习到更多东西

最后附上aigestudio大神的非常好的学习系列文章:http://blog.csdn.net/column/details/androidcustomview.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: