一个涂鸦画板控件

这次带来一个涂鸦画板控件。之前一个项目里需要做一个功能:用户在屏幕上签名,然后将签名保存成图片。于是就顺手写了这个

控件,起个名字叫DrawView,这里拿出来给大家分享一下。


首先说一下原理。原理其实很简单,我们在屏幕上画的一笔,本质上就是一堆坐标点的集合,把这个集合保存在Path中,然后调用

canvas.drawPath就可以把这条线画出来了。而触控产生的坐标点可以在onTouchEvent里采集。


上DrawView本体:

DrawView.java:

public class DrawView extends View {
    private Context context;

    // 线宽
    private int lineWidth;

    // 线颜色
    private int lineColor;

    private Paint paint;
    private ArrayList list;

    public DrawView(Context context) {
        this(context, null);
    }

    public DrawView(Context context, AttributeSet attrs) {
        this(context, attrs, -1);
    }

    public DrawView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

    private void init(Context context) {
        this.context = context;

        if (paint == null) paint = new Paint();
        if (list == null) list = new ArrayList<>();

        lineWidth = lineWidth != 0 ? lineWidth : dp2px(5);
        lineColor = lineColor != 0 ? lineColor : Color.parseColor("#000000");

        paint.setStrokeWidth(lineWidth);
        paint.setColor(lineColor);
        paint.setStyle(Paint.Style.STROKE);
        paint.setAntiAlias(true);
        paint.setStrokeCap(Paint.Cap.ROUND);
        // 抗锯齿,使线条圆滑
        paint.setPathEffect(new CornerPathEffect(200));

        for (int i = 0; i < list.size(); i++) {
            list.get(i).reset();
        }
        list.clear();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        for (int i = 0; i < list.size(); i++) {
            // 画线
            canvas.drawPath(list.get(i), paint);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                Path path = new Path();
                path.moveTo(event.getX(), event.getY());
                path.lineTo(event.getX(), event.getY());
                list.add(path);
                invalidate();
                break;
            case MotionEvent.ACTION_MOVE:
                list.get(list.size() - 1).lineTo(event.getX(), event.getY());
                invalidate();
                break;
        }

        return true;
    }

    /**
     * 画面重置
     */
    public void reset() {
        init(context);
        invalidate();
    }

    /**
     * 将当前画面保存成图片
     *
     * @param path 保存路径
     * @param name 图片名称
     * @return 是否保存成功
     */
    public boolean save(String path, String name) {
        setDrawingCacheEnabled(true);
        Bitmap bitmap = Bitmap.createBitmap(getDrawingCache());
        setDrawingCacheEnabled(false);
        if (bitmap != null) {
            File dir = new File(path);
            if (!dir.exists()) dir.mkdir();
            File file = new File(path, name);
            try {
                FileOutputStream fos = new FileOutputStream(file);
                bitmap.compress(Bitmap.CompressFormat.JPEG, 70, fos);
                fos.flush();
                fos.close();
                try {
                    MediaStore.Images.Media.insertImage(context.getContentResolver(), file.getAbsolutePath(), name, null);
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
                context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + path + name)));

                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        } else {
            return false;
        }
    }

    /**
     * 设置线宽
     *
     * @param width 线宽,单位dp
     */
    public void setLineWidth(int width) {
        this.lineWidth = dp2px(lineWidth);
        init(context);
    }

    /**
     * 设置线颜色
     *
     * @param color 颜色值
     */
    public void setLineColor(int color) {
        this.lineColor = color;
        init(context);
    }

    private int dp2px(float dipValue) {
        float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dipValue * scale + 0.5f);
    }
}


然后就可以用了,上MainActivity.java和activity_main.xml:

MainActivity.java:

public class MainActivity extends Activity {
    private DrawView drawView;
    private Button clearButton, saveButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        drawView = (DrawView) findViewById(R.id.draw_view);
        clearButton = (Button) findViewById(R.id.clear_button);
        saveButton = (Button) findViewById(R.id.save_button);

        drawView.setLineWidth(15);
        drawView.setLineColor(getResources().getColor(R.color.colorAccent));

        clearButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                drawView.reset();
            }
        });
        saveButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (drawView.save(Environment.getExternalStorageDirectory().getPath(), "signature.jpeg")) {
                    Toast.makeText(MainActivity.this, "Succeed", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(MainActivity.this, "Failed", Toast.LENGTH_SHORT).show();
                }
            }
        });
    }
}
activity_main.xml:




    

    

        


代码很简单,没什么好讲的。唯一需要注意的是务必给控件设置一个非透明的背景,否则保存成的图片会一片漆黑。

 

运行一下看一下效果:

                                                                 一个涂鸦画板控件_第1张图片

控件支持设置线宽和线的颜色,调用相应的方法即可,这里就不演示了。

 

最后附上源码地址:点击打开链接

 

这次的内容就到这里,我们下次再见。

你可能感兴趣的:(自定义控件)