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

android实现画板功能

2015-10-27 23:36 519 查看
上一篇博客实现了android自定义圆形图像这篇博客给大家实现基于xfermode的遮罩层画板功能。首先我会先实现一个简单的画板功能。

实现简单的画板功能

这里我们的画板是全屏实现的,所以先写一个工具类ScreenUtil来获得屏幕的宽和高的值。

ScreenUtil.java

[code]public static int[] getScreenSize(Context context) {
        int screenSize[] = new int[2];

        WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);

        Display metrics =  windowManager.getDefaultDisplay();
        screenSize[0] =  metrics.getWidth();
        screenSize[1] =  metrics.getHeight();
        return screenSize;
    }


这里我将宽和高封装到了一个整型数组里然后然后返回该数组。

新建DrawView类继承自View

这里我们新建一个DrawView extends View ,然后在构造方法里进行初始化,DrawView的属性如下:

[code]private Paint mPaint = null;  //用于绘制路径的画笔
private Path mPath = null; //用户触摸的路径
private Bitmap desBitmap = null; 
private Canvas mCanvas = null;
private float preX; //上一次的触摸点x坐标
private float preY; //上一次触摸点y坐标
private static final int MIN_SLOP = 5;  //最小的滑动距离


在构造方法中进行初始化:

[code]mPath = new Path(); 

mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);//设置画笔抗锯齿和抗抖动
mPaint.setStyle(Paint.Style.STROKE); //设置画笔为实心
mPaint.setStrokeCap(Paint.Cap.ROUND); //设置画笔笔触为圆形
mPaint.setStrokeJoin(Paint.Join.ROUND); //设置画笔接触点为圆形
mPaint.setStrokeWidth(30);  //画笔的宽度
mPaint.setColor(Color.GREEN); //画笔的颜色

//获取当前屏幕的宽和高
int screenWidth = ScreenUtil.getScreenSize(getContext())[0];
int screenHeight = ScreenUtil.getScreenSize(getContext())[1];

//创建一个BITMAP
desBitmap = Bitmap.createBitmap(screenWidth,screenHeight,Config.ARGB_8888);
//创建一个和当前bitmap大小相同的画布
mCanvas = new Canvas(desBitmap);
//绘制当前画布的填充色
mCanvas.drawColor(Color.parseColor("#cccccc"));


重写onDraw方法

[code]//将desBitmap绘制到当前view的canvas中
canvas.drawBitmap(desBitmap, 0, 0, null);
//绘制path,即用户滑动的路径
mCanvas.drawPath(mPath, mPaint);


这里还需要重写onTouchEvent方法,用来根据用户手指的滑动位置,实现mPath具体的绘制工作。

重写onTouchEvent方法

[code]@Override
public boolean onTouchEvent(MotionEvent event) {

    Log.d(TAG, "the onTouchEvent runs....");
    //获取当前手指相对当前view接触的x,y坐标
    /**
     * 获取当前手指相对当前手机屏幕坐标,接触的x,y坐标
     * event.getRawX()
     * event.getRawY()
     */
    float currentX = event.getX();
    float currentY = event.getY();

    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            Log.d(TAG, "the action_down runs....");
            //当用户按下时候,将mPath重置,并且将起始点移动到当前坐标
            mPath.reset();
            mPath.moveTo(currentX, currentY);
            //记录上次触摸的坐标,注意ACTION_DOWN方法只会执行一次
            preX = currentX;
            preY = currentY;
            break;
        case MotionEvent.ACTION_MOVE:
            Log.d(TAG, "the action_move runs....");
            //ACTION_MOVE方法会多次执行,计算用户水平和垂直方向滑动的距离
            int dx = (int) Math.abs(currentX- preX);
            int dy = (int) Math.abs(currentY - preY);
            //如果滑动的距离大于规定的值
            if (dx > MIN_SLOP || dy > MIN_SLOP) {
                mPath.quadTo(preX, preY, currentX, currentY);
                //重新为上一次的触摸点赋值
                preX = currentX;
                preY = currentY;
            }
            break;
        }

        invalidate();//重新绘制当前view
        return true;
    }


这里在onTouchEvent方法最后返回true表示当前view会消耗掉该事件,如果事件返回false,会将事件再次返回给其父控件来执行。Path可以实现两点之间的平滑过渡。

此时效果如下:



使用xfermode实现遮罩层画板

好了,到现在为止我们已经知道如何实现一个基本的画板功能,下面通过结合PorterDuffXfermode来实现遮罩层的画板功能。核心代码如下:

[code]private void init() {

        mPath = new Path();

        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeWidth(40);
        mPaint.setColor(Color.argb(20,255,0,0));
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));

        //获取屏幕的宽高
        int screenWidth = ScreenUtil.getScreenSize(getContext())[0];
        int screenHeight = ScreenUtil.getScreenSize(getContext())[1];

        //创建一个遮罩层,并且使用单独的canvas绘制
        mDesBitmap = Bitmap.createBitmap(screenWidth, screenHeight, Config.ARGB_8888);
        mDrawCanvas = new Canvas(mDesBitmap);
        mDrawCanvas.drawColor(Color.parseColor("#cccccc"));

        //获取需要被遮罩的图片并且将其缩放值屏幕大小
        mSrcBimap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_back);
        mSrcBimap = Bitmap.createScaledBitmap(mSrcBimap, screenWidth, screenHeight, false);

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        ////先绘制原图像,然后绘制和原图像相同大小的遮罩层
        canvas.drawBitmap(mSrcBimap, 0, 0, null);
        canvas.drawBitmap(mDesBitmap, 0, 0, null);
        //根据mPaint设置的setXfermode来绘制用户滑动的path
        mDrawCanvas.drawPath(mPath, mPaint);
    }


主要增加了如下几步:

首先创建一个和当前屏幕相同大小的mDrawCanvas对象,并且使用颜色将其填充。

[code]/创建一个遮罩层,并且使用单独的canvas绘制
mDesBitmap = Bitmap.createBitmap(screenWidth, screenHeight, Config.ARGB_8888);
mDrawCanvas = new Canvas(mDesBitmap);       mDrawCanvas.drawColor(Color.parseColor("#cccccc"));


为画笔设置Xfermode,也就是以那种方式来显示重叠的部分。

[code]mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));


获取需要被隐藏的图片。

[code]//获取需要被遮罩的图片并且将其缩放值屏幕大小
mSrcBimap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_back);
mSrcBimap = Bitmap.createScaledBitmap(mSrcBimap, screenWidth, screenHeight, false);


先绘制原图像,然后绘制和原图像相同大小的遮罩层

[code]canvas.drawBitmap(mSrcBimap, 0, 0, null);
canvas.drawBitmap(mDesBitmap, 0, 0, null);


重写onTouchEvent,并且根据mPaint设置的setXfermode来绘制用户滑动的path

[code]mDrawCanvas.drawPath(mPath, mPaint);


onTouchEvent方法是一样的处理方式,这里只是多了一个XferMode的设置。

效果如下:



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