您的位置:首页 > 移动开发 > Android开发

Android 绘图进阶(二):Xfermode(画笔风格)绘制涂层

2015-09-18 10:05 260 查看



   如果你对PorterDuff与Xfermode不够了解可以参看我之前的博客Android 绘图进阶(一),上篇博客介绍了Xfermode的SRC_IN的画笔风格的使用实例,这篇博客介绍一下它的一种涂层效果(XOR)。

方案一:圆形画板擦

一、思路




  根据graphic图我们可以使用看出Xor效果实现的就是相交部分会露出底部图片。因此我们需要设置一个底部的背景(BitmapBackground),我是赵丽颖粉丝,就选择了她的图片作为背景,之后还需要绘制DST与SRC涂层,由于Xfermode的使用必须基于一张Bitmap,因此我们需要给要绘制的DST与SRC涂层创建一个Bitmap,并为它创建一个新的画布,将该Bitmap绘制到新建的画布上面,并将DST与SRC绘图绘制在上面。最后添加上手势监听就可以了。

二、代码示例

1、跟之前一样先创建用于绘制DST与SRC的Bitmap与它Canvas

[code]//width、height是在onMeasure方法中获得的因此要在onMeasure创建bitmap
//并设置Bitmap的大小充满屏幕
mBitmap=Bitmap.createBitmap(width, height, Config.ARGB_8888);
        //创建Bitmap图的画布
            BitmapCanvas=new Canvas(mBitmap);


2、DST与SRC

[code]//系统默认先画的为DST
        BitmapCanvas.drawRect(0, 0, width, height, mpaintcircle);
        //后绘制的为SRC
        BitmapCanvas.drawPath(mpath, mpaintrect);
        //将bitmap图片绘制到画布上面
        canvas.drawBitmap(mBitmap, 0, 0, null);


3、设置xfermode

[code]//给画笔设置Xfermode
        PorterDuffXfermode mode=new PorterDuffXfermode(PorterDuff.Mode.XOR);    
        mpaintrect.setXfermode(mode);


4、添加上手势监听

[code]//手势监听
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:{
            x=event.getX();
            y=event.getY();
            //为了不是单纯的绘制一个圆,使用Path路径
            mpath.addCircle(x, y, 50, Direction.CW);
            invalidate();
            return true;
        }       
        case MotionEvent.ACTION_MOVE:
            x=event.getX();
            y=event.getY();
                mpath.addCircle(x, y, 50, Direction.CW);
                invalidate();
                return true;            
        default:
            break;
        }
        return super.onTouchEvent(event);
    }


5、完整代码

布局

[code]<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" 
 >

    <com.example.myview.MyBitmapView2
        android:id="@+id/slider"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
        </RelativeLayout>


创建继承View的class

[code]public class MyBitmapView2 extends View{
    private int width;
    private int height;
    private Paint mpaintcircle;
    private Paint mpaintrect;
    //用于绘制DST与SRC的Bitmap
    private Bitmap mBitmap;
    //背景
    private Bitmap mBitmapBackground;
    //DST与SRC的画布
    private Canvas BitmapCanvas;
    private Bitmap back;
    //用于绘制圆路径
    private Path mpath;
    public MyBitmapView2(Context context) {
        super(context);

    }

    public MyBitmapView2(Context context, AttributeSet attrs) {
        super(context, attrs);
        //设置dst画笔
        mpaintcircle=new Paint();
        mpaintcircle.setColor(Color.YELLOW);

        //设置src画笔的颜色
        mpaintrect=new Paint();
        mpaintrect.setColor(Color.GREEN);
        //给画笔设置Xfermode
        PorterDuffXfermode mode=new PorterDuffXfermode(PorterDuff.Mode.XOR);    
        mpaintrect.setXfermode(mode);
        mpath=new Path();
    }

    @Override
    protected void onDraw(Canvas canvas) {

        super.onDraw(canvas);
        //画布的背景图片,矩形区域由back确定
         canvas.drawBitmap(mBitmapBackground, new Rect(0,0,back.getWidth(),back.getHeight()), new Rect(0,0,width,height), null);
//系统默认先画的为DST
        BitmapCanvas.drawRect(0, 0, width, height, mpaintcircle);
        //后绘制的为SRC
        BitmapCanvas.drawPath(mpath, mpaintrect);
        //将bitmap图片绘制到画布上面
        canvas.drawBitmap(mBitmap, 0, 0, null);

    }
    private float x;
    private float y;
    //手势监听
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:{
            x=event.getX();
            y=event.getY();
            //为了不是单纯的绘制一个圆,使用Path路径
            mpath.addCircle(x, y, 50, Direction.CW);
            invalidate();
            return true;
        }       
        case MotionEvent.ACTION_MOVE:
            x=event.getX();
            y=event.getY();
                mpath.addCircle(x, y, 50, Direction.CW);
                invalidate();
                return true;            
        default:
            break;
        }
        return super.onTouchEvent(event);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //
        width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
        height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
        //告知父布局该View的大小
        setMeasuredDimension(width, height);
        mBitmap=Bitmap.createBitmap(width, height, Config.ARGB_8888);
        //创建Bitmap图的画布
        BitmapCanvas=new Canvas(mBitmap);
        //创建Bitmap背景图片
mBitmapBackground=BitmapFactory.decodeResource(getResources(), R.drawable.zly);
//创建它的原因是为了绘制mBitmapBackground时,确定矩形区域(全屏)
         back=Bitmap.createBitmap(width, height, Config.ARGB_8888);
    }
}


这样我们的涂层效果就***好了!

方案二:线型画板擦




可以看到我们上面的图片的画板擦的形状是圆形的,这里想要把它进一步修改为线型的板擦,我们只需要修改我们手势监听部分的mpath和画笔的线型圆角与中间连线的圆形连接以及非填充Style就可以了。

下面将修改的中点代码提取出来

画笔

[code] //注:使用setStrokeCap与setStrokeJoin必须先设置style
        mpaintrect.setStyle(Style.STROKE);
        mpaintrect.setStrokeCap(Cap.ROUND);
        mpaintrect.setStrokeJoin(Join.ROUND);


手势监听

[code]private float old_x;
    private float old_y;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:{
            x=event.getX();
            y=event.getY();
        //mpath.addCircle(x, y, 50, Direction.CW);
            mpath.moveTo(x, y);
            invalidate();
            old_x=x;
            old_y=y;
            return true;
        }       
        case MotionEvent.ACTION_MOVE:   
            x=event.getX();
            y=event.getY();
                  //每次移动都从落下位置划线到移动位置
            mpath.moveTo(old_x,old_y);
            //这里可以使用lineto也可以使用正余弦曲线
            mpath.lineTo(x,y);
            //mpath.rQuadTo((x+old_x)/2,(y+old_y), x, y);
            //刷新UI
            invalidate();
            old_x=x;
            old_y=y;
            return true;            
        default:
            break;
        }

        return super.onTouchEvent(event);
    }


下面是完整代码

[code]
public class MyBitmapView2 extends View{
    private int width;
    private int height;
    private Paint mpaintcircle;
    private Paint mpaintrect;
    private Bitmap mBitmap;
    private Bitmap mBitmapBackground;
    private Canvas BitmapCanvas;
    private Bitmap back;
    private Path mpath;
    public MyBitmapView2(Context context) {
        super(context);

    }

    public MyBitmapView2(Context context, AttributeSet attrs) {
        super(context, attrs);
        //设置圆形画笔
        mpaintcircle=new Paint();
        mpaintcircle.setColor(Color.YELLOW);

        //设置矩形画笔的颜色
        mpaintrect=new Paint();
        mpaintrect.setColor(Color.GREEN);
        //给画笔设置mode
        PorterDuffXfermode mode=new PorterDuffXfermode(PorterDuff.Mode.XOR);    
        mpaintrect.setXfermode(mode);
        //注:使用setStrokeCap与setStrokeJoin必须先设置style
        mpaintrect.setStyle(Style.STROKE);
        mpaintrect.setStrokeCap(Cap.ROUND);
        mpaintrect.setStrokeJoin(Join.ROUND);
        mpaintrect.setStrokeWidth(30);
        mpath=new Path();
    }

    @Override
    protected void onDraw(Canvas canvas) {

        super.onDraw(canvas);
        //画布的背景色
        canvas.drawBitmap(mBitmapBackground,0,0, null);
        //在bitmap图的画布上绘制圆形与矩形
       // BitmapCanvas.drawCircle(width/2, height/2, width/2, mpaintcircle);//dst
        BitmapCanvas.drawRect(0, 0, width, height, mpaintcircle);//src
        BitmapCanvas.drawPath(mpath, mpaintrect);
        //将bitmap图片绘制到画布上面
        canvas.drawBitmap(mBitmap, 0, 0, null);

    }
    private float x;
    private float y;
    private float old_x;
    private float old_y;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:{
            x=event.getX();
            y=event.getY();
        //mpath.addCircle(x, y, 50, Direction.CW);
            mpath.moveTo(x, y);
            invalidate();
            old_x=x;
            old_y=y;
            return true;
        }       
        case MotionEvent.ACTION_MOVE:   
            x=event.getX();
            y=event.getY();

            mpath.moveTo(old_x,old_y);
            mpath.lineTo(x,y);
            //mpath.rQuadTo((x+old_x)/2,(y+old_y), x, y);
            invalidate();
            old_x=x;
            old_y=y;
            return true;            
        default:
            break;
        }

        return super.onTouchEvent(event);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
        height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
        setMeasuredDimension(width, height);
        mBitmap=Bitmap.createBitmap(width, height, Config.ARGB_8888);
        //创建Bitmap图的画布
        BitmapCanvas=new Canvas(mBitmap);

        mBitmapBackground=BitmapFactory.decodeResource(getResources(), R.drawable.zly);
         back=Bitmap.createBitmap(width, height, Config.ARGB_8888);
//      Canvas canva=new Canvas(mBitmapBackground);
//      canva.drawBitmap(mBitmapBackground,  new Rect(0,0,mBitmapBackground.getWidth(),mBitmapBackground.getHeight()), new Rect(0,0,width,height), null);
    }
}


[code]package com.example.myview;

public class MainActivity_bitmap2 extends Activity implements OnClickListener{
    private Button mbtn_bitmap2;
    private MyBitmapView2 bitmap2;
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.bitmap_view2);
        mbtn_bitmap2=(Button) findViewById(R.id.btn_bitmapview2);
        bitmap2=(MyBitmapView2) findViewById(R.id.bitmap2);
        mbtn_bitmap2.setOnClickListener(this);
    }
    @Override
    public void onClick(View v) {
        File file=new File(Environment.getExternalStorageDirectory(),System.currentTimeMillis()+".jpg");
        bitmap2.invalidate();
        bitmap2.setDrawingCacheEnabled(true);
         Bitmap bitmapnew=bitmap2.getDrawingCache();
         if(!file.exists()){
             try {
                file.createNewFile();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
         }
         try {
             Log.d("路径", file.getAbsolutePath());
            bitmapnew.compress(CompressFormat.JPEG,100, new FileOutputStream(file));
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: