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:
activity_main.xml: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(); } } }); } }
<?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.