Recently, a new requirement was encountered in the project, which required the ability to draw different ICONS, text, and tracks on images. The native ImageView doesn’t cut it so you have to implement it yourself.

Before we start, we need to think about the functions we need to use. The requirements are to be able to draw ICONS, text and free “doodle” on the displayed image. Therefore, Imageview will override onTouchEvent (MotionEvent event) and onDraw (Canvas Canvas). In onTouchEvent (MotionEvent Event), the first step is to determine which of the current operation is to draw an image, text, or track. ACTION_DOWN, MotionEvent.ACTION_MOVE, and MotionEvent.ACTION_UP. Finally, call postInvalidate() to redraw the content to the screen.

At the beginning, due to insufficient consideration, after setting various conditions in onTouchEvent (MotionEvent Event), postInvalidate() was called at the end of the method to redraw, and then each effect was drawn in the method onDraw (Canvas Canvas). The result is that this drawing overwrites the previous one. After many attempts, a solution was found. Create an empty Canvas, then create a blank Bitmap based on the width and height of the image displayed, and set the created blank Bitmap to the empty Canvas through Canvas. setBitmap(Bitmap Bitmap). In this way, future ICONS and text will be drawn on the empty canvas first. DrawBitmap (cacheBitmap, 0, 0, null) in onDraw (Canvas Canvas) when the “blank” bitmap is drawn to the screen, the desired effect is achieved.

Here is the complete code:

import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; import android.support.v7.widget.AppCompatImageView; import android.util.AttributeSet; import android.view.MotionEvent; Public class DrawImageView extends AppCompatImageView {private int MODE = -1; public Paint mPaint; // Path private path mPath; Private String mContent; Private Bitmap mIcon; Private float mPreX; private float mPreX; private float mPreY; public Bitmap mCacheBitmap; public Canvas mCacheCanvas; public DrawImageView (Context context, AttributeSet attrs) { super (context, attrs); init (); } private void init () { mPaint = new Paint (); mPaint.setAntiAlias (true); mPath = new Path (); mCacheCanvas = new Canvas (); } public void mode (int mode) {mode = mode; Public void setTextStyle (String Content, int color, int textSize, Paint.Style paintStyle) { mContent = content; mPaint.setColor (color); mPaint.setStyle (paintStyle); mPaint.setTextSize (textSize); } public void setLineStyle (int color, int lineWidth,Paint.Style paintStyle) { mPaint.setStyle (paintStyle); mPaint.setStrokeWidth (lineWidth); mPaint.setColor (color); Public void setIcon (Bitmap icon) {mIcon = icon; } @override public Boolean onTouchEvent (MotionEvent) {switch (MODE) {case 0: switch (event.getAction ()) { case MotionEvent.ACTION_DOWN: mPreX = event.getX (); mPreY = event.getY (); return true; case MotionEvent.ACTION_UP: mCacheCanvas.drawText (mContent, mPreX, mPreY, mPaint); break; } break; Case 1:// icon switch (event.getAction ()) {case motionEvent.action_down: mPreX = event.getx (); mPreY = event.getY (); return true; case MotionEvent.ACTION_UP: mCacheCanvas.drawBitmap (mIcon, mPreX, mPreY, mPaint); break; } break; Case 2:// Finger trace switch (event.getAction ()) {case motionEvent.action_down: mPreX = event.getx (); mPreY = event.getY (); mPath.moveTo (mPreX, mPreY); return true; case MotionEvent.ACTION_MOVE: float endX = (mPreX + event.getX ()) / 2; float endY = (mPreY + event.getY ()) / 2; mPath.quadTo (mPreX, mPreY, endX, endY); mPreX = event.getX (); mPreY = event.getY (); break; case MotionEvent.ACTION_UP: mCacheCanvas.drawPath (mPath, mPaint); mPath.reset (); break; } break; } postInvalidate (); return super.onTouchEvent (event); } @Override protected void onDraw (Canvas canvas) { super.onDraw (canvas); if (mCacheBitmap ! = null) canvas.drawBitmap (mCacheBitmap, 0, 0, null); if (! mPath.isEmpty ()) canvas.drawPath (mPath, mPaint); }}Copy the code

Use in code

public class MainActivity extends AppCompatActivity { private DrawImageView drawImageView; @Override protected void onCreate (Bundle savedInstanceState) { super.onCreate (savedInstanceState); setContentView (R.layout.activity_main); drawImageView = (DrawImageView) findViewById (R.id.image); drawImageView.getViewTreeObserver ().addOnGlobalLayoutListener (new ViewTreeObserver.OnGlobalLayoutListener () { @Override public void onGlobalLayout () { drawImageView.getViewTreeObserver ().removeOnGlobalLayoutListener (this); drawImageView.mCacheBitmap = Bitmap.createBitmap (drawImageView.getWidth (), drawImageView.getHeight (), Bitmap.Config.ARGB_8888); drawImageView.mCacheCanvas.setBitmap (drawImageView.mCacheBitmap); }}); Button iconBtn = (Button) findViewById (R.id.btn_icon); iconBtn.setOnClickListener (new View.OnClickListener () { @Override public void onClick (View v) { Bitmap bitmap= BitmapFactory.decodeResource (getResources (),R.drawable.icon); drawImageView.mode (1); drawImageView.setIcon (bitmap); }}); Button textBtn = (Button) findViewById (R.id.btn_text); textBtn.setOnClickListener (new View.OnClickListener () { @Override public void onClick (View v) { drawImageView.mode (0); DrawImageView. SetTextStyle (" this is a test ", Color BLUE, 10, Paint, style.css. The FILL); }}); Button lineBtn = (Button) findViewById (R.id.btn_line); lineBtn.setOnClickListener (new View.OnClickListener () { @Override public void onClick (View v) { drawImageView.mode (2); drawImageView.setLineStyle (Color.RED,10,Paint.Style.STROKE); }}); }}Copy the code

Effect of operation:

The first fully customized control, for the record, this short dozens of lines of code, to bring their own is more confidence boost.