美文网首页Android知识Android开发Android开发
自定义View-第二十步:PorterDuffXfermode

自定义View-第二十步:PorterDuffXfermode

作者: crossroads | 来源:发表于2017-02-27 10:52 被阅读64次

    前言

    根据启舰大大 的博客所学习的自定义View。

    准备

    使用离屏绘制

    //新建图层  
    int layerID = canvas.saveLayer(0,0,width,height,mPaint,Canvas.ALL_SAVE_FLAG);  
      
    //TODO 核心绘制代码  
      
    //还原图层  
    canvas.restoreToCount(layerID);  
    

    一、方法介绍

    public PorterDuffXfermode(PorterDuff.Mode mode)  
    

    二、举个栗子

    点击时书面上升,不点击时水面下降。


    目标图片live_zan 源图片heartflow
    public class PorterDuffXfermodeMineView extends View {
        private PorterDuffXfermode porterDuffXfermode;
        private Bitmap disBitmap;
        private Paint paint;
        private Bitmap scrBitmap;
        private int top;
        public Timer timer;
    
    
        public PorterDuffXfermodeMineView(Context context) {
            super(context);
            init(context);
        }
    
        public PorterDuffXfermodeMineView(Context context, AttributeSet attrs) {
            super(context, attrs);
            init(context);
        }
    
        public PorterDuffXfermodeMineView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init(context);
        }
    
        private void init(Context context) {
    
            //设置模式,源图像和目标图像相交的地方绘制源图像,在不相交的地方绘制目标图像。
            porterDuffXfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP);
    
            //初始化画笔
            paint = new Paint(Paint.ANTI_ALIAS_FLAG);
            paint.setFilterBitmap(true);
            paint.setDither(true);
    
            //获取dst图片
            disBitmap = ((BitmapDrawable) ContextCompat.getDrawable(context, R.mipmap.live_zan)).getBitmap();
    
            //获取src图片
            scrBitmap = ((BitmapDrawable) ContextCompat.getDrawable(context, R.mipmap.heartflow)).getBitmap();
    
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            int height = disBitmap.getHeight();
            //使用离屏绘制
            canvas.saveLayer(0, 0, disBitmap.getWidth(), height, null, Canvas.ALL_SAVE_FLAG);
    
            //一定要先绘制目标图像!!!
            canvas.drawBitmap(disBitmap, 0, 0, paint);
    
            //再设置paint的xfermode模式!!!
            paint.setXfermode(porterDuffXfermode);
    
            //高度<=目标图像的1/3时,不再下降
            if (top < height / 3) {
                top = height / 3;
                if (timer != null) {
                    timer.cancel();
                    timer = null;
                }
            }
            else if (height + 10 < top) {
                //高度最大为目标高度+10,主要是让覆盖后没有空白
                top = height + 10;
            }
    
            //绘制源图像
            canvas.drawBitmap(scrBitmap, 0, height - top, paint);
    
            paint.setXfermode(null);
    
            //还原画布
            canvas.restore();
        }
    
        //点击时水面上升,不点击时则自动下降
        public void click(boolean isClick) {
            if (isClick) {
                if (timer != null) {
                    timer.cancel();
                    timer = null;
                }
                top = top + 2;
            }
            else {
                top = top - 2;
                if (timer == null) {
                    timer = new Timer();
                    timer.schedule(new TimerTask() {
                        @Override
                        public void run() {
                            top = top - 2;
                            postInvalidate();
                        }
                    }, 500, 100);
                }
            }
            postInvalidate();
        }
    
    }
    
        <com.crossroads.demo.demo.PorterDuffXfermodeMineView
            android:layout_centerInParent="true"
            android:id="@+id/heartView"
            android:layout_width="60dp"
            android:layout_height="60dp"/>
    
    public class MainActivity extends Activity {
        PorterDuffXfermodeMineView heartView;
    
        Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                if (heartView != null) {
                    heartView.click(false);
                }
            }
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            heartView = (PorterDuffXfermodeMineView) findViewById(R.id.heartView);
            heartView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    zanStart();
                }
            });
        }
    
        private void zanStart() {
            handler.removeMessages(1);
            if (heartView != null) {
                heartView.click(true);
            }
            handler.sendEmptyMessageDelayed(1, 1000);
        }
    
    }
    

    刮刮卡效果,大家可以尝试自己写一下

    简易刮刮卡效果
    public class MineView extends View {
        Bitmap coverBitmap;
        Bitmap answerBitmap;
        Path path;
        Paint paint;
        Bitmap bitmapPath;
    
        public MineView(Context context) {
            this(context, null);
        }
    
        public MineView(Context context, AttributeSet attrs) {
            super(context, attrs);
            init();
        }
    
        private void init() {
            setLayerType(View.LAYER_TYPE_SOFTWARE, null);
            //初始化画笔
            paint = new Paint();
            paint.setStyle(Paint.Style.STROKE);
            paint.setStrokeCap(Paint.Cap.ROUND);
            paint.setStrokeWidth(30);
            paint.setAntiAlias(true);
            //初始化
            path = new Path();
            coverBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.bear);//覆盖图
            answerBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.answer);//谜底
            bitmapPath = Bitmap.createBitmap(coverBitmap.getWidth(),coverBitmap.getHeight(), Bitmap.Config.ARGB_8888);//用于存储路径
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            //绘制谜底
            canvas.drawBitmap(answerBitmap,0,0,paint);
            //canvas调用saveLayer之后,开启了一个新的透明图层。绘制完成后再合并到上一个图层上
            canvas.saveLayer(0, 0, getWidth(), getHeight(), null, Canvas.ALL_SAVE_FLAG);
    
            //将手指行为保存并绘制路径
            Canvas canvas1 = new Canvas(bitmapPath);
            canvas1.drawPath(path, paint);
            canvas.drawBitmap(bitmapPath,0,0,paint);
    
            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
            //绘制覆盖图
            canvas.drawBitmap(coverBitmap,0,0,paint);
            paint.setXfermode(null);
            canvas.restore();
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            float x = event.getX();
            float y = event.getY();
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    path.moveTo(x, y);
                    return true;
                case MotionEvent.ACTION_MOVE:
                    path.lineTo(x, y);
                    postInvalidate();
                    break;
            }
            return super.onTouchEvent(event);
        }
    
    //   启舰大大的touch事件是这样实现的,给大家贴出来,看看,肉眼没看出来用贝塞尔曲线效果和普通的有啥区别~
    //    @Override
    //    public boolean onTouchEvent(MotionEvent event) {
    //        float mPreX = event.getX();
    //        float mPreY = event.getY();
    //        switch (event.getAction()) {
    //            case MotionEvent.ACTION_DOWN:
    //                path.moveTo(event.getX(),event.getY());
    //                mPreX = event.getX();
    //                mPreY = event.getY();
    //                return true;
    //            case MotionEvent.ACTION_MOVE:
    //                float endX = (mPreX+event.getX())/2;
    //                float endY = (mPreY+event.getY())/2;
    //                path.quadTo(mPreX,mPreY,endX,endY);
    //                mPreX = event.getX();
    //                mPreY =event.getY();
    //                postInvalidate();
    //                break;
    //        }
    //        return super.onTouchEvent(event);
    //    }
    }
    
    

    后记

    1.刚刚看到一个 手把手教你画一个 逼格满满圆形水波纹loadingview Android的效果。
    2.关于saveLayer的详细介绍请进入http://blog.csdn.net/harvic880925/article/details/51317746 ,蛮重要的,大家前往看看吧,这里不再赘述了O(∩_∩)O~

    相关文章

      网友评论

        本文标题:自定义View-第二十步:PorterDuffXfermode

        本文链接:https://www.haomeiwen.com/subject/esvwwttx.html