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

来源:互联网 发布:ubuntu输入法乱码 编辑:程序博客网 时间:2024/05/16 22:06

这里写图片描述
   如果你对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

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

2、DST与SRC

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

3、设置xfermode

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

4、添加上手势监听

//手势监听    @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、完整代码
布局

<?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

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就可以了。
下面将修改的中点代码提取出来

画笔

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

手势监听

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);    }

下面是完整代码

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);    }}
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();        }    }}
0 0
原创粉丝点击