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

来源:互联网 发布:怪物猎人ol n卡优化 编辑:程序博客网 时间:2024/05/21 07:00

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

在Paint有一个方法

mPaint.setShader(Shader shader);

Shader有五个子类:

Shader五个子类

BitmapShader,
ComposeShader,
LinearGradient,
RadialGradient,
SweepGradient

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

Shader.TileMode有三种模式:

  1. Shader.TileMode.CLAMP 最后一个像素进行拉伸填充
  2. Shader.TileMode.MIRROR 镜像
  3. 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()) {            case 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));

线性1

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

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

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

线性2

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

构造 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));

效果:

线性3

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

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,就不累赘了

效果是这个样子

角度1

角度2

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));

效果:

径向1

例 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));

径向2

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

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

2 0
原创粉丝点击