自定义View(二-番外2-Shader)

From AigeStudio(http://blog.csdn.net/aigestudio)Power by Aige

跟着爱哥打天下

自定义控件其实很简单4:

setShader(Shader shader)

Shader有五个子类:
BitmapShader、ComposeShader、LinearGradient、RadialGradient、SweepGradient

BitmapShader:

这五个Shader里最异类的是BitmapShader,因为只有它是允许我们载入一张图片来给图像着色

BitmapShader (Bitmap bitmap, Shader.TileMode tileX, Shader.TileMode tileY)

只有一个含参的构造方法,而其他的四个兄弟姐妹呢都有两个

Shader.TileMode里有三种模式:CLAMP、MIRROR和REPETA
边缘拉伸(先作用Y轴,再作用与X轴)、镜像、重复

public class BrickView extends View {
    /**
     * 画笔
     */
    private Paint mPaint;

    /**
     * 描边画笔
     */
    private Paint mStrokePaint;

    /**
     * Bitmap着色器
     */
    private BitmapShader bitmapShader;

    /**
     * 触摸点坐标
     */
    private float posX, posY;

    /**
     * 构造器
     */
    public BrickView(Context context) {
        this(context, null);
    }

    public BrickView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public BrickView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        initPaint();

    }

    /**
     * 初始化画笔
     */
    private void initPaint() {
        mPaint = new Paint();

         /*
         * 实例化描边画笔并设置参数
         */
        mStrokePaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
        mStrokePaint.setColor(0xFF000000);
        mStrokePaint.setStyle(Paint.Style.STROKE);
        mStrokePaint.setStrokeWidth(5);

        //生成BitmapShader
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher_round);
        bitmapShader = new BitmapShader(bitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
        mPaint.setShader(bitmapShader);

    }


    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawColor(Color.DKGRAY);

         /*
         * 绘制圆和描边
         */
        canvas.drawCircle(posX, posY, 300, mPaint);
        canvas.drawCircle(posX, posY, 300, mStrokePaint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        /*
         * 手指移动时获取触摸点坐标并刷新视图
         */
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            posX = event.getX();
            posY = event.getY();

            invalidate();
        }
        if (event.getAction() == MotionEvent.ACTION_MOVE) {
            posX = event.getX();
            posY = event.getY();

            invalidate();
        }
        return true;
    }
}

这里写图片描述

BitmapShader是从画布的左上方开始着色,设置着色器前为我们的着色器设置了一个变换矩阵,可以更换位置

只是加载了一张图片,然后在XY轴无限重复,圆形的区域为绘制显示的区域(不是在整个屏幕中重复,而是只是在绘制的区域中重复,只不过因为坐标的问题才如此)

LinearGradient:线性渐变

LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1, Shader.TileMode tile)    
LinearGradient(float x0, float y0, float x1, float y1, int[] colors, float[] positions, Shader.TileMode tile)  

前面四个参数也是定义坐标的不扯了colors是一个int型数组,我们用来定义所有渐变的颜色,positions表示的是渐变的相对区域,其取值只有0到1,上面的代码中我们定义了一个[0, 0.1F, 0.5F, 0.7F, 0.8F],意思就是红色到黄色的渐变起点坐标在整个渐变区域(left, top, right, bottom定义了渐变的区域)的起点,而终点则在渐变区域长度 * 10%的地方,而黄色到绿色呢则从渐变区域10%开始到50%的地方以此类推,positions可以为空

public class ShaderView2 extends View {
    /**
     * 画笔
     */
    private Paint mPaint;

    /**
     * 构造器
     */
    public ShaderView2(Context context) {
        this(context, null);
    }

    public ShaderView2(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ShaderView2(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        initPaint();

    }

    /**
     * 初始化画笔
     */
    private void initPaint() {
        mPaint = new Paint();

//        mPaint.setShader(new LinearGradient(0, 0, 300, 300, Color.RED, Color.YELLOW, Shader.TileMode.REPEAT));
//        mPaint.setShader(new LinearGradient(0, 0, 600, 600, new int[] { Color.RED, Color.YELLOW, Color.GREEN, Color.CYAN, Color.BLUE }, new float[] { 0, 0.1F, 0.5F, 0.7F, 0.8F }, Shader.TileMode.MIRROR));
        mPaint.setShader(new LinearGradient(0, 0, 600, 600, new int[] { Color.RED, Color.YELLOW, Color.GREEN, Color.CYAN, Color.BLUE }, null, Shader.TileMode.MIRROR));

    }

    @Override
    protected void onDraw(Canvas canvas) {

        canvas.drawRect(0, 0, 600, 600, mPaint);
    }

}

这里写图片描述

感觉开始有点跟不上了,得一遍又一遍的梳理代码逻辑:

public class ReflectView extends View {
    /**
     * 画笔
     */
    private Paint mPaint;

    /**
     * 位图
     */
    private Bitmap mSrcBitmap, mRefBitmap;

    /**
     * 混合模式
     */
    private PorterDuffXfermode mXfermode;


    /**
     * 构造器
     */
    public ReflectView(Context context) {
        this(context, null);
    }

    public ReflectView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ReflectView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        initPaint();

    }

    /**
     * 初始化画笔
     */
    private void initPaint() {
        //获取源图
        mSrcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bitmap4);

        //实例化一个矩阵对象
        Matrix matrix = new Matrix();
        //图像倒过来
        matrix.setScale(1F, -1F);

        //生成倒影图
        mRefBitmap = Bitmap.createBitmap(mSrcBitmap, 0, 0, mSrcBitmap.getWidth(), mSrcBitmap.getHeight(), matrix, true);

        mPaint = new Paint();

        //设置渐变
        mPaint.setShader(new LinearGradient(0, mSrcBitmap.getHeight(), 0, mSrcBitmap.getHeight() + mSrcBitmap.getHeight() / 4, 0xAA000000, Color.TRANSPARENT, Shader.TileMode.CLAMP));

        mXfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);


    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawColor(Color.BLACK);
        canvas.drawBitmap(mSrcBitmap, 0, 0, null);

        //新建一个图层,并在上面进行DST_IN操作,不然有影响
        int sc = canvas.saveLayer(0, mSrcBitmap.getHeight(), mRefBitmap.getWidth(), mSrcBitmap.getHeight() * 2, null, Canvas.ALL_SAVE_FLAG);

        //紧接下面绘制倒影Bitmap
        canvas.drawBitmap(mRefBitmap, 0, mSrcBitmap.getHeight(), null);

        //取DST的交集部分
        mPaint.setXfermode(mXfermode);

        //绘制矩形,渐变开始位置为倒影的开始位置,渐变方向是垂直从上到下,高度为倒影的1/4,渐变模式为边界像素拉伸,也就是透明拉伸,
        //取出交集为整个倒影,然后渐变到1/4开始透明
        canvas.drawRect(0, mSrcBitmap.getHeight(), mRefBitmap.getWidth(), mSrcBitmap.getHeight() * 2, mPaint);

        mPaint.setXfermode(null);

        canvas.restoreToCount(sc);

    }

}

这里写图片描述

SweepGradient:

梯度渐变,也称之为扫描式渐变,因为其效果有点类似雷达的扫描效果,他也有两个构造方法:

SweepGradient(float cx, float cy, int color0, int color1)  
public class ShaderView2 extends View {
    /**
     * 画笔
     */
    private Paint mPaint;

    /**
     * 构造器
     */
    public ShaderView2(Context context) {
        this(context, null);
    }

    public ShaderView2(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ShaderView2(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        setLayerType(LAYER_TYPE_SOFTWARE, null);

        initPaint();

    }

    /**
     * 初始化画笔
     */
    private void initPaint() {
        mPaint = new Paint();

//        mPaint.setShader(new LinearGradient(0, 0, 0, 300, Color.RED, Color.TRANSPARENT, Shader.TileMode.CLAMP));
//        mPaint.setShader(new LinearGradient(0, 0, 600, 600, new int[] { Color.RED, Color.YELLOW, Color.GREEN, Color.CYAN, Color.BLUE }, new float[] { 0, 0.1F, 0.5F, 0.7F, 0.8F }, Shader.TileMode.MIRROR));
//        mPaint.setShader(new LinearGradient(0, 0, 600, 600, new int[] { Color.RED, Color.YELLOW, Color.GREEN, Color.CYAN, Color.BLUE }, null, Shader.TileMode.MIRROR));
        mPaint.setShader(new SweepGradient(300, 300, Color.RED, Color.YELLOW));

    }

    @Override
    protected void onDraw(Canvas canvas) {

        canvas.drawRect(0, 0, 600, 600, mPaint);
    }

}

这里写图片描述

SweepGradient(float cx, float cy, int[] colors, float[] positions)  

RadialGradient:
径向渐变,径向渐变说的简单点就是个圆形中心向四周渐变的效果,他也一样有两个构造方法

RadialGradient (float centerX, float centerY, float radius, int centerColor, int edgeColor, Shader.TileMode tileMode)  
RadialGradient(float centerX, float centerY, float radius, int colors[], float stops[], TileMode tileMode)

在之前的代码上加上shader:

mPaint.setShader(new RadialGradient(293, 440, mBitmap.getHeight() * 7 / 8, Color.TRANSPARENT, Color.BLACK, Shader.TileMode.CLAMP));

但是效果没出来,好像setShader对drawBitmap没什么作用,然后在最后画一个同等大小的矩形,进行渲染。

canvas.drawRect(0, 0, mBitmap.getWidth(), mBitmap.getHeight(), mPaint);

ComposeShader
就是组合Shader的意思,顾名思义就是两个Shader组合在一起作为一个新Shader
两个构造函数:

ComposeShader (Shader shaderA, Shader shaderB, Xfermode mode)  
ComposeShader (Shader shaderA, Shader shaderB, PorterDuff.Mode mode)  

PorterDuff.Mode在Xfermode之下,是Xfermode的子类,其余的两个子类已经在API16之后过时了


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值