本节导言:

上节咱们写了关于Xfermode与PorterDuff运用的第一个比如:圆角&圆形图片ImageView的完结, 咱们领会到了PorterDuff.Mode.DST_IN给咱们带来的优点,本节咱们持续来写比如练练手, 还记得8.3.2 绘图类实战示例给咱们带来的拔掉美人衣服的完结吗?

其时咱们的完结计划是,将手指触碰区域邻近的20*20个像素点设置为通明,效果图是这样的:

不知道你有没有发现一个问题,咱们擦美人衣服的时分,擦洗的时分都是方块的,可是咱们画图板 画图的时分,划线都是很滑润的,有没有办法将两者结合起来,咱们擦衣服时也是油滑的呢? 答案肯定是有的,便是运用Xfermode咯!本节咱们运用另一个形式,DST_OUT形式! 在不相交的当地制作目标图

假如你忘记了某个形式或许连18种形式都没见过的话,那么请移步: Android根底入门教程——8.3.5 Paint API之—— Xfermode与PorterDuff详解(二) 别的,仍是要贴下PorterDuff.Mode的效果图:

嗯,话不多说,开端本节内容~


1.要完结的效果图以及完结流程剖析:

要完结的效果图

嗯,不知道你看了那个Gif图多少次了呢?不知道图中是否合适咱们的口味,小猪 是从他人的APP上扒下来的,别问我编号或许留邮箱什么的,我什么都不知道~找番什么的, 问群里的老司机——基神吧,好的,咱们来剖析下完结流程吧~

  • 咱们来说说原理,其实便是两个Bitmap,一前一后,前面的是穿戴衣服的,后边的是没穿衣服的, 然后经过一个Path来记载用户制作出来的图形,然后为咱们的画笔设置DST_OUT的形式,那么 与Path堆叠部分的DST(目标图),便是穿戴衣服的图,会变成通明!好哒,很简略! 咱们再渐渐细化!
  • 首要咱们需求两个Bitmap,用来存储前后两张图片,这儿咱们让两个Bitmap都全屏!
  • 接着设置下画笔,圆角,笔宽,抗锯齿等!
  • 再接着界说一个画Path,即用户制作区域的办法,设置Xfermode后画区域罢了!
  • 然后重写onTouchEvent办法,这部分和之前的自界说画图板是相同的!
  • 最终重写onDraw()办法,先制作布景图片,调用用户制作区域的办法,再制作远景图片!

或许看上去有点杂乱,其实不然,代码超简略的说~


2.代码完结:

直接就一个自界说View——StripMeiZi.java

/**
 * Created by Jay on 2015/10/25 0025.
 */
public class StripMeiZi 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 screenW, screenH; //屏幕宽高
    private Xfermode mXfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);


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

    public StripMeiZi(Context context, AttributeSet attrs) {
        super(context, attrs);
        screenW = ScreenUtil.getScreenW(context);
        screenH = ScreenUtil.getScreenH(context);
        init();
    }


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

    private void init() {
        //背面图片,这儿让它全屏
        mBackBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.meizi_back);
        mBackBitmap = Bitmap.createScaledBitmap(mBackBitmap, screenW, screenH, false);
        //前面的图片,并制作到Canvas上
        mBeforeBitmap = Bitmap.createBitmap(screenW, screenH, Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas(mBeforeBitmap);
        mCanvas.drawBitmap(BitmapFactory.decodeResource(getResources(),
                R.mipmap.meizi_before), null, new RectF(0, 0, screenW, screenH), null);
        //画笔相关的设置
        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, 0, null);
        drawPath();
        canvas.drawBitmap(mBeforeBitmap, 0, 0, null);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction();
        int x = (int) event.getX();
        int y = (int) event.getY();
        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;
    }
}

布局代码activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.jay.xfermodedemo2.StripMeiZi
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</RelativeLayout>

3.代码示例下载:


本节小结:

好的,本节咱们写了Xfermode与PorterDuff的另一个实战比如——手撕美人衣服的Demo,相比起咱们之前 那种撕美人衣服(让接触点邻近20*20的像素点变成通明)的办法文雅多了~代码也简略很多是吧,有没有 领会到Android图画混排Xfermode给咱们带来的优点,或许关于自界说控件的重要性!嗯,还等什么, 翻开你的IDE,把代码撸一遍,尝尝手撕美人衣服的快感吧~