一个功能强大的画图板(一)

    **首先在这里声明下,此博客用到了一些博主的博客内容,但是因为电脑系统重装丢了写文件,找不到当时的博客的地址了,如果有知道的还请想告。**
有写博客这个想法很久了,但是因为各种原因没有执行,现在终于下定决心去努力做好这件事了。主要是这不仅可以分享我在学习工作中的心得,而且能够很好的整理我自己的知识思路可谓是双赢的局面。那么闲话好说开始我的第一篇技术博客吧!
既然是图片编辑那么就要有图片我们的图片可以是直接拍照,也可以从相册里选,相关代码比较简单,如下:
/**
     * 在这里我设置了requestWindowFeature(Window.FEATURE_NO_TITLE)属性,但是发现失效,后来研究发现是因为
     * 我们以前继承的是Activity ,而现在继承的是AppCompatActivity,所以此代码失效。生效代码如下
     * @param savedInstanceState
     */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
        if (getSupportActionBar()!=null){
            getSupportActionBar().hide();
        }
        }

 @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.take_photo:
                if (isSdcardExisting()){
                    Intent intent=new Intent("android.media.action.IMAGE_CAPTURE");
                    intent.putExtra(MediaStore.EXTRA_OUTPUT,getImageUri());
                    intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY,0);
                    startActivityForResult(intent,CAMERA_REQUEST_CODE);
                }else {
                    Toast.makeText(v.getContext(), "请插入sd卡", Toast.LENGTH_LONG)
                            .show();
                }
                break;
            case R.id.photos:
                Intent intent =new Intent(Intent.ACTION_GET_CONTENT);
                intent.addCategory(Intent.CATEGORY_OPENABLE);
                intent.setType("image/*");
                startActivityForResult(intent,IMAGE_REQUEST_CODE);
                break;
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (resultCode!=RESULT_OK){
            return;
        }else{
            if (requestCode==IMAGE_REQUEST_CODE){
                EditImage(data.getData());
            }else if (requestCode==CAMERA_REQUEST_CODE){

                if (isSdcardExisting()){
                    EditImage(getImageUri());
                }else {
                    Toast.makeText(this, "请插入sd卡", Toast.LENGTH_LONG)
                            .show();
                }
            }else if (requestCode==RESIZE_REQUEST_CODE){
                if (data!=null){
                    showImage(data);
                }
            }
        }
        super.onActivityResult(requestCode, resultCode, data);

    }
 /**
     * 跳转至照片编辑页面
     * @param uri
     */
    public void EditImage(Uri uri) {
        Intent intent = new Intent("com.android.camera.action.CROP");
        intent.setDataAndType(uri, "image/*");
        intent.putExtra("crop", "true");
        intent.putExtra("aspectX", 1);
        intent.putExtra("aspectY", 1);
        intent.putExtra("outputX", 150);
        intent.putExtra("outputY", 150);
        intent.putExtra("return-data", true);
        startActivityForResult(intent, RESIZE_REQUEST_CODE);
    }

这里只贴出来需要跳转的三个系统类,至于如何判断是否存在sd卡以及跳转至主页面的具体操作大家可以自己写下,比较简单。
好了,下面就是我们关键地方了,我们自定义的view,一开始就是一堆初始化:

    private final String TAG=this.getClass().getSimpleName();
    //背景位图
    private Bitmap bitmap_bg=null;
    //前景位图
    private Bitmap bitmap_fg=null;
    //用于画图的画布
    private Canvas mCanvas;
    //画笔
    private Paint mPaint;
    //橡皮
    private Paint mEraser;
    private Path mPath;
    private Matrix mMatrix;
    //画笔的宽度
    private int paintWidth=6;
    //橡皮的大小
    private int eraserWidth=15;
    //图片的规定宽高
    private int bitmapWidth=488;
    private int bitmapHeight=680;
    //图片的原宽高
    private int oldBitmapWidth;
    private int oldBitmapHeight;
    private float scaleX;
    private float scaleY;
    private boolean isStart = true;
    private float lastX;
    private float lastY;
    private paint paintState=paint.PEN;
    /**
     * 判断笔的状态
     */
    private enum paint{
        PEN,ERASER;
    }

 private void init(){
        setFocusableInTouchMode(true); // 确保能接收到触屏事件
        setFocusable(true);
        mMatrix=new Matrix();
        mPath=new Path();
        initPaint();
        initEraser();
    }

    /**
     * 初始化画笔
     */
    private void initPaint(){
        mPaint=new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setColor(Color.RED);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeWidth(paintWidth);

    }
    private void initEraser(){
        mEraser=new Paint();
        mEraser.setAntiAlias(true);
        mEraser.setDither(true);
        mEraser.setStyle(Paint.Style.STROKE);
        mEraser.setStrokeJoin(Paint.Join.ROUND);
        mEraser.setStrokeCap(Paint.Cap.ROUND);
        mEraser.setStrokeWidth(eraserWidth);
        mEraser.setColor(Color.TRANSPARENT);
        mEraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
    }

通过代码我们可以看出我们是分了前景和后景图的,这样我们在后期的时候操作起来就比较方便了,可以单独的处理前景图和后景图,发现这不是和我们的面向对象语言的封装的特性不谋而合,哈哈。这里面还有一个关键对我们以后的功能拓展起到关键的作用,就是我们将mCanvas中的所有内容通过构造方法保存到了前景图中,这样我们后续的只需要将前景图呈现到初始画布上就可以了,而前景图的放大缩小,平移等操作将只在mCanvas画布上进行,最重要的是我们的画笔不在需要在进行边界的检测了,因为他只会画到我们的前景图上,是不是发现很爽,实现起来非常简单了。
好了图片有了,也初始化了,那么我们就将进行绘画了,说道绘画那肯定少不了我们的触摸事件:

 @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getActionMasked()){
            case MotionEvent.ACTION_DOWN:
                onTouchDown(event);
                invalidate();
                break;
            case MotionEvent.ACTION_MOVE:
                onTouchMove(event);
                if (paintState==paint.PEN){
                    mCanvas.drawPath(mPath,mPaint);
                }else if (paintState==paint.ERASER){
                    mCanvas.drawPath(mPath,mEraser);
                }
                invalidate();
                break;
            case MotionEvent.ACTION_UP:
                onTouchUp(event);
                invalidate();
                break;
            case MotionEvent.ACTION_CANCEL:
                break;
            default:
                break;
        }
        return true;
    }

    private void  onTouchDown(MotionEvent event){
        isStart=true;
        onTouchMove(event);
    }
    private void  onTouchMove(MotionEvent event){
        float x;
        float y;        
        x=event.getX();
        y=event.getY();
        drawPoint(x,y);
    }
    private void  onTouchUp(MotionEvent event){
        onTouchMove(event);
        isStart=true;
    }

    private void drawPoint(float x, float y){
        //判断是否是起始点
        if (isStart){
            setStartPoint(x,y);
        }else {
            float dx=Math.abs(x-lastX);
            float dy=Math.abs(y-lastY);
            if (dx>=3 || dy>=3){
                mPath.quadTo(lastX, lastY, x, y);
            }

            Log.e(TAG,"move....");
            lastX = x;
            lastY = y;
        }
    }

    private void setStartPoint(float x, float y){
        lastX=x;
        lastY=y;
        mPath.reset();
        mPath.moveTo(x,y);
        isStart=false;
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (bitmap_bg!=null){
            canvas.drawBitmap(bitmap_bg,mMatrix,mPaint);
        }
        if (bitmap_fg!=null){
            canvas.drawBitmap(bitmap_fg,0,0,mPaint);

        }
    }

好了,一气呵成,基本实现了绘画的功能了,大家会发现我们的绘画操作基本是在前景图上进行的,我们拓展起功能来就方便多了,接下来我们就要给他添加更加强大的功能了,缩放和平移功能,而且我们的画图板可是在缩放平移后还可以继续正常绘画呢,希望大家继续关注我的下一篇博客。
源码下载链接:画图板(一)

你可能感兴趣的:(Android技术系列)