Android PorterDuff.Mode.DST_OUT 刮彩票

我在学习 PorterDuff.Mode 实现图片混排模式的时候发现有一个很好玩,那就是 PorterDuff.Mode.DST_OUT

它会把两者相交的地方擦去,这这不就有点像刮彩票一样么?

Android 提供的 18 种图片混排模式

Android PorterDuff.Mode.DST_OUT 刮彩票 实现步骤

先说说原理,就是两个 Bitmap,一前一后,前面的是一层涂层,后面的是中奖信息

然后通过一个 Path 来记录用户绘制出来的图形,然后为我们的画笔设置 DST_OUT 的模式,那么 与 Path 重叠部分的 DST(目标图),也就是涂层,会变成透明

  1. 首先我们需要两个 Bitmap,用来存储涂层和中奖信息

  2. 接着设置下画笔,圆角,笔宽,抗锯齿等

  3. 定义一个 Path,即用户绘制区域的方法,设置 Xfermode 后画区域

  4. 重写 onTouchEvent()

  5. 重写 onDraw() 方法,先绘制背景图片,调用用户绘制区域的方法,再绘制前景图片

范例


  1. 创建一个 空的 Android 项目 cn.twle.android.Lottery

  2. 定义一个自定义 View LotteryView.java

    package cn.twle.android.lottery;
    
    import android.annotation.SuppressLint;
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.Canvas;
    import android.graphics.Paint;
    import android.graphics.Path;
    import android.graphics.PorterDuff;
    import android.graphics.PorterDuffXfermode;
    import android.graphics.Xfermode;
    import android.util.AttributeSet;
    import android.util.DisplayMetrics;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.WindowManager;
    
    public class LotteryView extends View {
    
        private Paint mPaint = new Paint();
        private Path mPath = new Path();
        private Canvas mCanvas;
        private Bitmap mBeforeBitmap;
        private Bitmap mBackBitmap;
        private int mLastX,mLastY;
        private int width,height=200,top = 0;
        private Xfermode mXfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);
    
        public LotteryView(Context context) {
            this(context, null);
        }
    
        public LotteryView(Context context, AttributeSet attrs) {
            super(context, attrs);
    
            WindowManager wm = (WindowManager) context.
                    getSystemService(Context.WINDOW_SERVICE);
            DisplayMetrics dm = new DisplayMetrics();
            wm.getDefaultDisplay().getMetrics(dm);
    
            width = dm.widthPixels;
            top   = (dm.heightPixels-280) / 2;
    
            init();
        }
    
        public LotteryView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    
        private void init() {
    
            mBackBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
            Canvas c = new Canvas(mBackBitmap);
            Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
    
            c.drawColor(0xFFDDDDDD);
    
            p.setColor(0xFF000000);
            p.setTextSize(48.0f);
            p.setTextAlign(Paint.Align.CENTER);
    
            Paint.FontMetrics fontMetrics = p.getFontMetrics();
            float tp = fontMetrics.top;        // 为基线到字体上边框的距离
            float tb = fontMetrics.bottom;  // 为基线到字体下边框的距离
    
            int cY = (int) (height/2 - tp/2 - tb/2);//基线中间点的y轴计算公式
    
            c.drawText("简单教程,简单编程",width/2,cY,p);
    
            mBeforeBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    
            mCanvas = new Canvas(mBeforeBitmap);
            p.setColor(0xFF666666);
            mCanvas.drawRect(0,0,width,height,p);
    
            //画笔相关的设置
            mPaint.setAntiAlias(true);
            mPaint.setDither(true);
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setStrokeJoin(Paint.Join.ROUND); // 圆角
            mPaint.setStrokeCap(Paint.Cap.ROUND); // 圆角
            mPaint.setStrokeWidth(80);    // 设置画笔宽
        }
    
        private void drawPath() {
            mPaint.setXfermode(mXfermode);
            mCanvas.drawPath(mPath, mPaint);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
    
            canvas.drawBitmap(mBackBitmap, 0, top, null);
            drawPath();
            canvas.drawBitmap(mBeforeBitmap, 0, top, null);
        }
    
        @SuppressLint("ClickableViewAccessibility")
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            int action = event.getAction();
            int x = (int) event.getX();
            int y = (int) event.getY() - top;
            switch (action)
            {
                case MotionEvent.ACTION_DOWN:
                    mLastX = x;
                    mLastY = y;
                    mPath.moveTo(mLastX, mLastY);
                    break;
                case MotionEvent.ACTION_MOVE:
    
                    int dx = Math.abs(x - mLastX);
                    int dy = Math.abs(y - mLastY);
    
                    if (dx > 3 || dy > 3)
                        mPath.lineTo(x, y);
    
                    mLastX = x;
                    mLastY = y;
                    break;
            }
            invalidate();
            return true;
        }
    }
    
  3. 修改 activity_main.xml

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <cn.twle.android.lottery.LotteryView
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    </RelativeLayout>
    

Android 基础教程

关于   |   FAQ   |   我们的愿景   |   广告投放   |  博客

  简单教程,简单编程 - IT 入门首选站

Copyright © 2013-2022 简单教程 twle.cn All Rights Reserved.