专注收集记录技术开发学习笔记、技术难点、解决方案
网站信息搜索 >> 请输入关键词:
您当前的位置: 首页 > 图形/图像

Android图形图像之自定义控件属性(demo:刮刮乐与击码以及图片的缓存)

发布时间:2011-06-27 19:19:21 文章来源:www.iduyao.cn 采编人员:星星草
Android图形图像之自定义控件属性(demo:刮刮乐与打码以及图片的缓存)

概述:

此部分内容涉及到android的自定义View、自定义属性和Android图形图像处理的综合应用:Bitmap、Path、Matrix、Canvas。
图片打码以及如何缓存打码后的图片都是日常极有可能用到的,而刮图也并不是用不到。
下面的demo写的是一个的刮刮乐例程,里面涉及到如何自定义控件属性,以及如何存储处理后的图片,注释很详细,看注释即可。
结果演示:
这里写图片描述

文件保存后的结果:
这里写图片描述

Demo

新建一个自定义View:

public class MyBitMapViewSec extends View {

    private int width;
    private int height;
    private float x;
    private float y;
    private float old_x;
    private float old_y;

    private Paint mPaintCircle;
    private Paint mPaintRect;
    private Bitmap mBitmap;
    private Bitmap mBitmapGround;

    private Matrix matrix;
    private Path mPath;
    private Canvas mCanvasBm;
    public MyBitMapViewSec(Context context) {
        super(context);
    }
    //
    public MyBitMapViewSec(Context context, AttributeSet attrs) {
        //attrs是这个View在xml布局中的所有属性的集合
        super(context, attrs);
        //将attrs解析为TypedArray类的对象
        final TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.selfish);
        //得到xml中本自定义View的self_background属性的内容,并强制转换为BitmapDrawable类型
        BitmapDrawable dra = (BitmapDrawable) a.getDrawable(R.styleable.selfish_self_background);
        if(dra!=null){
            //如果dra不为空,就将dra赋值给mBitmapGround
            mBitmapGround = dra.getBitmap();
        }else {
            //mBitmapGround里传入的是一张图片
            mBitmapGround = BitmapFactory.decodeResource(getResources(),R.mipmap.qingxin);
        }
        //得到xml中本自定义View的self_paintWidth属性中的内容,如果得不到就给个默认值30
        float paintWidth = a.getDimension(R.styleable.selfish_self_paintWidth,30);

        mPaintCircle = new Paint();
        mPaintCircle.setColor(Color.YELLOW);

        mPaintRect = new Paint();
        //XOR:交叠和被交叠部分均不显示;DST_OVER:自身交叠部分不显示;SRC_OVER交叠部分只显示自己
        PorterDuffXfermode mode = new PorterDuffXfermode(PorterDuff.Mode.XOR);
        mPaintRect.setXfermode(mode);
        mPaintRect.setStrokeWidth(paintWidth);
        mPaintRect.setStrokeJoin(Paint.Join.ROUND);//设置联接部分样式
        mPaintRect.setStrokeCap(Paint.Cap.ROUND);//设置中间部分样式:圆形
        mPaintRect.setStyle(Paint.Style.FILL_AND_STROKE);

        mPath = new Path();
        matrix = new Matrix();

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
        height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
        setMeasuredDimension(width, height);

        //这一句不能放到构造方法中,是因为还没有得到width和height的值
        mBitmap = Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888);
        mCanvasBm = new Canvas(mBitmap);//自定义一个画布,画布材料是Bitmap对象
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        matrix.reset();
        //下面两行的作用是放大图片,并绘制出来
        matrix.postScale((float)width/mBitmapGround.getWidth(),(float)height/mBitmapGround.getHeight());
        canvas.drawBitmap(mBitmapGround,matrix,null);
        //画一个蒙板
        mCanvasBm.drawRect(0,0,width,height,mPaintCircle);
        //将path画出,因为mPaintRect的模式为PorterDuff.Mode.XOR,所以画图时会让交叠部分都不显示,从而显示出底部图片来
        mCanvasBm.drawPath(mPath,mPaintRect);
        //这一步的意义是:将mCanvasBm在mBitmap上绘制的内容画出
        canvas.drawBitmap(mBitmap,0,0,null);

    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                y = event.getY();
                x = event.getX();
                //CW是Path移动方向:顺时针
                //mPath.addCircle(x,y,50,Path.Direction.CW);
                mPath.moveTo(x,y);
                //重新绘制,就是重新调用onDraw()方法
                invalidate();
                //更新old_x、old_y的值
                old_x = x;
                old_y = y;
                return true;
            case MotionEvent.ACTION_MOVE:
                y = event.getY();
                x = event.getX();
                //将mPath移动到上一个位置
                mPath.moveTo(old_x, old_y);
                //绘制贝塞尔曲线,((x + old_x) / 2, (y + old_y) / 2)作为控制点,(x, y)作为结束点
                mPath.quadTo((x + old_x) / 2, (y + old_y) / 2, x, y);
                invalidate();
                old_x = x;
                old_y = y;
                return true;
        }
        return super.onTouchEvent(event);
    }
}

如果用的是android studio,在res/value路径下新建一个文件,命名随意,我这里叫selfish,内容如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="selfish" >
        <attr name="self_background" format="reference"></attr>
        <attr name="self_paintWidth" format="dimension|reference"></attr>
    </declare-styleable>
</resources>

上面的打码中:attr代表我的自定View的属性,我这里添加了两个属性;declare-styleabl是给自定义控件添加自定义属性用的,它是一个属性集。

这个文件以及它的属性会在布局文件中用到,用它之前必须要声明:
xmlns:selfish=”http://schemas.android.com/apk/res-auto”
之后我就可以在我的自定义View——com.example.administrator.selfdefinedview.widget.MyBitMapViewSec中调用selfish属性集中的两个属性:在代码中可以看到他们:
*selfish:self_background=”@mipmap/aa”
selfish:self_paintWidth=”100dp”*

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:selfish="http://schemas.android.com/apk/res-auto"
              xmlns:tools="http://schemas.android.com/tools"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical">

    <Button
        android:id="@+id/button_resolve"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Save Picture"/>

    <com.example.administrator.selfdefinedview.widget.MyBitMapViewSec
        android:id="@+id/my_slider"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        selfish:self_background="@mipmap/aa"
        selfish:self_paintWidth="100dp"/>

</LinearLayout>

关于缓存View中的图片的打码,在主函数中写出:

public class TimerActivity extends Activity {

    private Button mButtonResolve;
    private MyBitMapViewSec myBitMapViewSec;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_timer);

        mButtonResolve = (Button) findViewById(R.id.button_resolve);
        myBitMapViewSec = (MyBitMapViewSec) findViewById(R.id.my_slider);
        mButtonResolve.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //将缓存开启
                myBitMapViewSec.setDrawingCacheEnabled(true);
                //getDrawingCache(true)得到当前myBitMapViewSec的缓存
                Bitmap bitmap = myBitMapViewSec.getDrawingCache(true);
                //得到存储这个位图文件bitmap的路径
                File file = new File(Environment.getExternalStorageDirectory(),System.currentTimeMillis()+".jpg");
                if (!file.exists()){
                    try {
                        file.createNewFile();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                try {
                    //将bitmap转为JPEG格式,保持原来大小写入file文件
                    bitmap.compress(Bitmap.CompressFormat.JPEG,100,new FileOutputStream(file));
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

至于图片打码该怎么写呢?很简单,只需修改onDraw()方法,把美女图画到自己声明的画布上,然后把黄色背景用onDraw()方法自带的canvas上,最后位置互换即可,这样,滑动频幕的地方会显示出底部的黄色,代码如下:

protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //画一个蒙板
        canvas.drawRect(0, 0, width, height, mPaintCircle);
        //将path画出,因为mPaintRect的模式为PorterDuff.Mode.XOR,所以画图时会让交叠部分都不显示,从而显示出底部图片来
        matrix.reset();
        //下面两行的作用是放大图片,并绘制出来
        matrix.postScale((float) width / mBitmapGround.getWidth(), (float) height / mBitmapGround.getHeight());
        mCanvasBm.drawBitmap(mBitmapGround, matrix, null);

        mCanvasBm.drawPath(mPath, mPaintRect);
        //这一步的意义是:将mCanvasBm在mBitmap上绘制的内容画出
        canvas.drawBitmap(mBitmap,0,0,null);

    }

结果演示:
这里写图片描述

版权声明:本文为博主原创文章,未经博主允许不得转载。

1楼mr_lihaimeng3小时前
可以啊,BB
Re: NiZhuanXingHeIT3小时前
回复mr_lihaimengn抽死你
友情提示:
信息收集于互联网,如果您发现错误或造成侵权,请及时通知本站更正或删除,具体联系方式见页面底部联系我们,谢谢。

其他相似内容:

热门推荐: