自定义View实现擦除蒙版显示图片功能/自定义View的存储/自定义View的属性

来源:互联网 发布:青柠软件密码 编辑:程序博客网 时间:2024/06/05 18:26

自定义View实现擦除蒙版显示图片功能

1.首先找到一张图片,利用BitmapFactory.decodeResource()方法得到它,作为画布的最底层将其绘制到画布的最底层

canvas.drawBitmap(mBitmapBackground,new Rect(0,0,mBitmapBackground.getWidth(),mBitmapBackground.getHeight()),                new Rect(0,0,width,heigth),null);//将第一个Rect的图片作为来源,来填充第二个Rect的区域

2.创建一个和画布大小一模一样的Bitmap,但里面什么都没有,然后以这个Bitmap为新的画布创建一个新的画布

//创建一个位图        mBitmap=Bitmap.createBitmap(width,heigth, Bitmap.Config.ARGB_8888);        mcanvasBit=new Canvas(mBitmap);//创建一个新的画布,是基于Bitmap即把Bitmap当做一个画布        //在Ondraw方法中         canvas.drawBitmap(mBitmap,0,0,null);

3.在Bitmap的画布上画上一层蒙版

mcanvasBit.drawRect(0, 0, width, heigth, mPaintCircle);//在Bitmap上画一个矩形。相当于一个蒙版//mPaintCircle只需要设置颜色即可

4.在Bitmap的画布上绘制一个路径,该路径代表用手点击屏幕,并在屏幕上移动的位置,该路径的画笔一定要设置成为XOR模型,同时还需要设置宽度(因为绘制的路径是线性的路径在第5部里)同时需要设置起始位置的形状(即点击屏幕不动时系统默认的形状,在这里设置为圆形)设置沿路径填充的形状(即手在屏幕上移动时,会不停的绘制该形状用来填充移动过的区域在这里设置为圆形,这样比方形好看的多)最后将画笔Style设置为FILL_AND_STROKE(填充和描边)

        mPaintRect.setStrokeJoin(Paint.Join.ROUND);//起始位置的形状,设置为圆形        mPaintRect.setStrokeCap(Paint.Cap.ROUND);//绘制中间时使用的形状        mPaintRect.setStrokeWidth(60);        mPaintRect.setStyle(Paint.Style.FILL_AND_STROKE);//将格式设置为填充并且空心        //PorterDuff.Mode为枚举类,一共有16个枚举值:每个枚举值代表不同的model        PorterDuffXfermode mode=new PorterDuffXfermode(PorterDuff.Mode.XOR);        mPaintRect.setXfermode(mode);

5.确定移动的位置和移动距离需要在onTouchEvent上面case:ACTION_DOWN和ACTION_MOVE,当ACTION_DOWN时需要记录当前这个点的位置,然后保存
当ACTION_MOVE时首先需要找到上个点的位置,然后得到最新点的位置,然后用mPath.lineTo来得到该路径,最后重新保存这个最新的点,这样就完成了不断更新触摸位置,同时能够记录该路径,最后调用 mcanvasBit.drawPath(mPath,mPaintRect);画出该路径

@Override    public boolean onTouchEvent(MotionEvent event) {        switch (event.getAction()){            case MotionEvent.ACTION_DOWN:                X=event.getX();//得到当前点击的位置                Y=event.getY();                mPath.moveTo(X,Y);//将该位置设置为Path的起点                XOld=X;//将该位置保存                YOld=Y;                invalidate();                return true;//必须要return true,否则不做处理            case MotionEvent.ACTION_MOVE:                //得到移动到的位置                X=event.getX();                Y=event.getY();                mPath.moveTo(XOld,YOld);//首先移动到之前的那个点                mPath.lineTo(X,Y);//然后移动到新的位置                invalidate();                //重新保存这个点                XOld=X;                YOld=Y;                return true;        }        return super.onTouchEvent(event);    }

自定义View的存储

1.首先在Activity中找到这个自定义的View,然后设置绘画缓存为true

2.创建一个Bitmap然后得到绘画的缓存

 mBitPicture.setDrawingCacheEnabled(true);//设置自定义View可以当做缓存                Bitmap bit=mBitPicture.getDrawingCache(true);//创建一个Bitmap,得到自定义View的缓存

3.最后创建一个File将Bitmap写入该File文件里就能保存自定义View的图片了

    //第一个参数设置文件压缩格式                    //第二个参数设置文件压缩尺寸大小(0~100),PNG格式图片可以忽略这个设置                    //第三个参数是输出的位置                    bit.compress(Bitmap.CompressFormat.PNG,100,new FileOutputStream(file));//设置为Png格式

自定义View的属性

1.首先在res的values文件夹下创建一个xml文件,在文件里面创建declare-styleable,表示自定义的属性,然后创建属性,包括属性的name和format,其中format表示接受的数据类型,xml文件如下:

 <declare-styleable name="customView">        <attr name="change_picture" format="reference"></attr>        <attr name="change_paint" format="dimension|reference"></attr>    </declare-styleable>

2.在布局xml文件下声明已经创建的属性集合,在Androidstudio中只需要在后面加上res-auto就可以自己去寻找了,但是在eclipse中需要加上包名

xmlns:customview="http://schemas.android.com/apk/res-auto"

3.声明之后就可以在自己创建的View上添加属性了

customview:change_picture="@mipmap/ali"    customview:change_paint="50sp"

4.在View类中找到该属性

 final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.customView);        BitmapDrawable drawable= (BitmapDrawable) a.getDrawable(R.styleable.customView_change_picture);        if (drawable!=null){            mBitmapBackground=drawable.getBitmap();        }else {            mBitmapBackground= BitmapFactory.decodeResource(getResources(), R.mipmap.cluo);//为Bitmap设置来源        }        int paintWidth=a.getDimensionPixelOffset(R.styleable.customView_change_paint,30);

所有代码

public class BitmapPicture extends View {    private int width;    private int heigth;    private float X;    private float Y;    private float XOld;    private float YOld;    private Path mPath;    private Bitmap mBitmap;    private Bitmap mBitmapBackground;    private Paint mPaintBackground;    private Paint mPaintCircle;    private Paint mPaintRect;    private Canvas mcanvasBit;    public BitmapPicture(Context context) {        super(context);    }    public BitmapPicture(Context context, AttributeSet attrs) {        super(context, attrs);        final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.customView);        BitmapDrawable drawable= (BitmapDrawable) a.getDrawable(R.styleable.customView_change_picture);//找到图片并强制造型成为BitmapDrawable        if (drawable!=null){            mBitmapBackground=drawable.getBitmap();        }else {            mBitmapBackground= BitmapFactory.decodeResource(getResources(), R.mipmap.cluo);//为Bitmap设置来源        }        int paintWidth=a.getDimensionPixelOffset(R.styleable.customView_change_paint,30);//得到xml文档中chang_paint属性的值,第二个参数是默认值        mPath=new Path();        mPaintBackground=new Paint();        mPaintBackground.setColor(Color.GRAY);        mPaintCircle=new Paint();        mPaintCircle.setColor(Color.CYAN);        mPaintCircle.setAntiAlias(true);        mPaintRect=new Paint();        mPaintRect.setColor(Color.GRAY);        mPaintRect.setAntiAlias(true);//抗锯齿        mPaintRect.setStrokeJoin(Paint.Join.ROUND);//起始位置的形状,设置为圆形//设置画笔进入的形状,当画笔的Style设置为Stroke或者FillAndStroke时使用        mPaintRect.setStrokeCap(Paint.Cap.ROUND);//绘制中间时使用的形状//设置笔帽的形式,当画笔的Style设置为Stroke或者FillAndStroke时使用        mPaintRect.setStrokeWidth(paintWidth);        mPaintRect.setStyle(Paint.Style.FILL_AND_STROKE);//将格式设置为填充并且空心        //PorterDuff.Mode为枚举类,一共有16个枚举值:每个枚举值代表不同的model        PorterDuffXfermode mode=new PorterDuffXfermode(PorterDuff.Mode.XOR);        mPaintRect.setXfermode(mode);    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        width=getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);        heigth=getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);        setMeasuredDimension(width,heigth);        //创建一个位图        mBitmap=Bitmap.createBitmap(width,heigth, Bitmap.Config.ARGB_8888);        mcanvasBit=new Canvas(mBitmap);//创建一个新的画布,是基于Bitmap即把Bitmap当做一个画布    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);//        canvas.drawColor(Color.GRAY);//设置一个背景色//        canvas.drawBitmap(mBitmap,0,0,mPaintBackground);//将Bitmap画到画布上        canvas.drawBitmap(mBitmapBackground,new Rect(0,0,mBitmapBackground.getWidth(),mBitmapBackground.getHeight()),                new Rect(0,0,width,heigth),null);//将第一个Rect的图片作为来源,来填充第二个Rect的区域        canvas.drawBitmap(mBitmap,0,0,null);//        mcanvasBit.drawCircle(width/2,heigth/2,width/2,mPaintCircle);//Bitmap上画一个圆        mcanvasBit.drawRect(0, 0, width, heigth, mPaintCircle);//在Bitmap上画一个矩形。相当于一个蒙版        mcanvasBit.drawPath(mPath,mPaintRect);//画出路径,经路径上的设置为透明    }    @Override    public boolean onTouchEvent(MotionEvent event) {        switch (event.getAction()){            case MotionEvent.ACTION_DOWN:                X=event.getX();//得到当前点击的位置                Y=event.getY();                mPath.moveTo(X,Y);//将该位置设置为Path的起点                XOld=X;//将该位置保存                YOld=Y;                invalidate();                return true;//必须要return true,否则不做处理            case MotionEvent.ACTION_MOVE:                //得到移动到的位置                X=event.getX();                Y=event.getY();                mPath.moveTo(XOld,YOld);//首先移动到之前的那个点                mPath.lineTo(X,Y);//然后移动到新的位置                invalidate();                //重新保存这个点                XOld=X;                YOld=Y;                return true;        }        return super.onTouchEvent(event);    }}

xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    xmlns:customview="http://schemas.android.com/apk/res-auto"    android:orientation="vertical"    android:layout_width="match_parent"    android:layout_height="match_parent"><com.my.mywidget.widget.BitmapPicture    android:id="@+id/bitmap_picture"    android:layout_width="match_parent"    android:layout_height="0dip"    android:layout_weight="1"    customview:change_picture="@mipmap/ali"    customview:change_paint="50sp"    />    <Button        android:id="@+id/button_save"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="保存"/></LinearLayout>

Acitvity

public class BitmapPictureActivity extends AppCompatActivity {    private Button mBtnSave;    private BitmapPicture mBitPicture;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.btimap_picture);        mBitPicture= (BitmapPicture) findViewById(R.id.bitmap_picture);        mBtnSave= (Button) findViewById(R.id.button_save);        mBtnSave.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                Toast.makeText(BitmapPictureActivity.this, "成功保存图片", Toast.LENGTH_SHORT).show();//                mBitPicture.setBackgroundResource(R.mipmap.aixi);                //这两句话是将自定义View设置为可以保存                mBitPicture.setDrawingCacheEnabled(true);//设置自定义View可以当做缓存                Bitmap bit=mBitPicture.getDrawingCache(true);//创建一个Bitmap,得到自定义View的缓存                File file=new File(Environment.getExternalStorageDirectory(),System.currentTimeMillis()+".png");//文件保存路径                if (!file.exists()){                    try {                        file.createNewFile();                    } catch (IOException e) {                        e.printStackTrace();                    }                }                try {                    //第一个参数设置文件压缩格式                    //第二个参数设置文件压缩尺寸大小(0~100),PNG格式图片可以忽略这个设置                    //第三个参数是输出的位置                    bit.compress(Bitmap.CompressFormat.PNG,100,new FileOutputStream(file));//设置为Png格式                } catch (FileNotFoundException e) {                    e.printStackTrace();                }            }        });    }}

customView

<?xml version="1.0" encoding="utf-8"?><resources>    <declare-styleable name="customView">        <attr name="change_picture" format="reference"></attr>        <attr name="change_paint" format="dimension|reference"></attr>    </declare-styleable></resources>
0 0