A doodle board control

Keywords: Android xml Java encoding

This time, it brings a doodle control. In the previous project, a function needs to be done: the user signs on the screen, and then saves the signature as a picture. So I wrote this

Control, named DrawView, here to share with you.


First of all, let's talk about the principle. The principle is actually very simple. The one we draw on the screen is essentially a set of coordinate points, which is saved in Path and then called.

canvas.drawPath can draw this line. The coordinate points generated by touch can be collected in onTouchEvent.


Upper DrawView body:

DrawView.java:

public class DrawView extends View {
    private Context context;

    // line width
    private int lineWidth;

    // Line color
    private int lineColor;

    private Paint paint;
    private ArrayList<Path> 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);
        // Anti aliasing, smooth lines
        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++) {
            // Draw line
            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;
    }

    /**
     * Screen reset
     */
    public void reset() {
        init(context);
        invalidate();
    }

    /**
     * Save the current picture as a picture
     *
     * @param path Save path
     * @param name Picture name
     * @return Save successfully
     */
    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;
        }
    }

    /**
     * Set lineweight
     *
     * @param width Line width in dp
     */
    public void setLineWidth(int width) {
        this.lineWidth = dp2px(lineWidth);
        init(context);
    }

    /**
     * Set line color
     *
     * @param color Color value
     */
    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);
    }
}


Then you can use main activity.class and activity main.xml:

MainActivity.class:

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:

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

    <com.min.drawview.DrawView
        android:id="@+id/draw_view"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:background="#ffffff" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="20dp"
        android:orientation="horizontal">

        <Button
            android:id="@+id/clear_button"
            android:layout_width="0dp"
            android:layout_height="40dp"
            android:layout_margin="10dp"
            android:layout_weight="1"
            android:text="clear" />

        <Button
            android:id="@+id/save_button"
            android:layout_width="0dp"
            android:layout_height="40dp"
            android:layout_margin="10dp"
            android:layout_weight="1"
            android:text="save" />

    </LinearLayout>

</LinearLayout>


The code is very simple, nothing to say. The only thing to notice is to make sure to set a non transparent background for the control, otherwise the saved image will be dark.

 

Run it to see the effect:

                                                                

Control supports setting line width and line color. Just call the corresponding method, which is not shown here.

 

Finally, the source address is attached: Click to open the link

 

This time we'll see you next time.

Posted by Hexxx on Thu, 30 Apr 2020 23:49:42 -0700