Android自定义视图更新指定视图的一部分

时间:2017-07-20 15:12:45

标签: java android draw android-custom-view

我通过从AppCompatImageView扩展一个类来实现一个绘图应用程序,它工作得很好,但是当绘制很多路径时,它的速度会降低

绘制任何新路径时是否可以,只绘制添加到视图中的新路径?

换句话说,只需更新视图的特定部分并且不必每次都更新所有视图。

PaintView.java

import android.content.Context;
import android.graphics.*;
import android.support.annotation.ColorInt;
import android.support.annotation.IntRange;
import android.support.v7.widget.AppCompatImageView;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.Stack;


public class PaintView extends AppCompatImageView implements View.OnTouchListener {

   private int defaultColor = 0xffff0000;
   private int defaultLineStrokeWidth = 4;
   private int defaultAlpha = 255;
   private int currentPathIndex = 0;
   private boolean isTouchDown = false;
   private boolean showBounds = false;
   private boolean isDeleteMode = false;

   private Paint linePaint;
   private Paint rectPaint;
   private Stack<PathHolder> paths;
   private Stack<PathHolder> memoryList;

   public GestureView(Context context) {
      super(context);
      init();
   }

   public GestureView(Context context, AttributeSet attrs) {
      super(context, attrs);
      init();
   }

   public GestureView(Context context, AttributeSet attrs, int defStyleAttr) {
      super(context, attrs, defStyleAttr);
      init();
   }

   private void init() {
      setOnTouchListener(this);

      setBackgroundColor(Color.WHITE);

      linePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
      linePaint.setStrokeWidth(defaultLineStrokeWidth);
      linePaint.setDither(true);
      linePaint.setAntiAlias(true);
      linePaint.setColor(Color.BLACK);
      linePaint.setStyle(Paint.Style.STROKE);
      linePaint.setStrokeCap(Paint.Cap.ROUND);
      linePaint.setStrokeJoin(Paint.Join.ROUND);
      linePaint.setPathEffect(new CornerPathEffect(10));

      rectPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
      rectPaint.setStrokeWidth(0.5f);
      rectPaint.setAntiAlias(true);
      rectPaint.setColor(Color.RED);
      rectPaint.setStyle(Paint.Style.STROKE);

      paths = new Stack<>();
      memoryList = new Stack<>();
   }

   public void setPaintColor(@ColorInt int color) {
      defaultColor = color;
   }

   public void showBounds(boolean show) {
      showBounds = show;
      invalidate();
   }

   public void setDeleteMode(boolean deleteMode) {
      this.isDeleteMode = deleteMode;
      invalidate();
   }

   public void setLineStrokeWidth(int width) {
      if (width > 0) {
         defaultLineStrokeWidth = width;
      } else {
         Log.e("GestureView", "Stroke width can't be zero or less.");
      }
   }

   public void setLineAlpha(@IntRange(from = 0, to = 255) int alpha) {
      defaultAlpha = alpha;
   }

   public int getDefaultLineStrokeWidth() {
      return defaultLineStrokeWidth;
   }

   public void clearScreen() {
      currentPathIndex = 0;
      paths.clear();
      memoryList.clear();

      invalidate();
   }

   @Override
   protected void onDraw(Canvas canvas) {
      if (paths.size() > 0) {
         for (int i = 0; i < paths.size(); i++) {
            paths.get(i).setColor(paths.get(i).getColor() != 0 ? paths.get(i).getColor() : defaultColor);
            paths.get(i).setStrokeWidth(paths.get(i).getStrokeWidth() != 0 ? paths.get(i).getStrokeWidth() : defaultLineStrokeWidth);
            paths.get(i).setAlpha(paths.get(i).getAlpha() != 0 ? paths.get(i).getAlpha() : defaultAlpha);

            linePaint.setColor(paths.get(i).getColor());
            linePaint.setStrokeWidth(paths.get(i).getStrokeWidth());
            linePaint.setAlpha(paths.get(i).getAlpha());

            canvas.drawPath(paths.get(i).getPath(), linePaint);
            paths.get(i).getPath().computeBounds(paths.get(i).getRect(), true);

            if (showBounds && (!isTouchDown || currentPathIndex != i)) {
               canvas.drawRect(paths.get(i).getRect(), rectPaint);
            }
         }
      }
   }

   @Override
   public boolean onTouch(View view, MotionEvent motionEvent) {
      if (isDeleteMode) {
         for (int i = 0; i < paths.size(); i++) {
            if (RectF.intersects(paths.get(i).getRect(), new RectF(motionEvent.getX(), motionEvent.getY(), motionEvent.getX(), motionEvent.getY()))) {
               memoryList.push(paths.get(i));
               paths.remove(i);
               currentPathIndex--;
               invalidate();
               break;
            }
         }
      } else {
         switch (motionEvent.getAction()) {
            case MotionEvent.ACTION_DOWN:
               isTouchDown = true;

               Path path = new Path();
               path.moveTo(motionEvent.getX(), motionEvent.getY());

               RectF rectF = new RectF();
               path.computeBounds(rectF, true);

               PathHolder pathHolder = new PathHolder();
               pathHolder.setPath(path);
               pathHolder.setRect(rectF);

               paths.add(currentPathIndex, pathHolder);
               break;

            case MotionEvent.ACTION_UP:
               isTouchDown = false;
               paths.get(currentPathIndex).getPath().lineTo(motionEvent.getX(), motionEvent.getY());
               currentPathIndex++;
               invalidate();
               break;

            case MotionEvent.ACTION_MOVE:
               paths.get(currentPathIndex).getPath().lineTo(motionEvent.getX(), motionEvent.getY());
               invalidate();
               break;
         }
      }
      return true;
   }

   public void undo() {
      if (paths.isEmpty()) {
         return;
      }
      memoryList.push(paths.pop());
      currentPathIndex--;
      invalidate();
   }

   public void redo() {
      if (memoryList.isEmpty()) {
         return;
      }
      paths.push(memoryList.pop());
      currentPathIndex++;
      invalidate();
   }

   public Bitmap getCaptureBitmap() {
      setDrawingCacheEnabled(true);
      return getDrawingCache();
   }

   public void saveCaptureTo(String path, int quality) {
      Bitmap b = getCaptureBitmap();
      try {
         b.compress(Bitmap.CompressFormat.PNG, quality, new FileOutputStream(path));
      } catch (FileNotFoundException e) {
         Log.e(GestureView.class.getSimpleName(), e.getMessage());
      }
   }
}

1 个答案:

答案 0 :(得分:0)

因此,当您在Canvas上绘图时,您必须再次绘制整个Canvas。根据我的理解,每当onDraw被调用(60ps)

时,你基本上都会使用一张新纸