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

自定义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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值