【问题标题】:Draw in Canvas by finger, Android用手指在 Canvas 中绘图,Android
【发布时间】:2013-05-15 01:32:25
【问题描述】:

我需要建立一个用手指在画布上绘图的项目。

如何获取我手指的触摸事件和运动事件然后进行绘制?

【问题讨论】:

标签: android drawing touch android-canvas


【解决方案1】:

使用 Bitmap、Canvas 和 Paint 类绘制线条的教程。 draw-line-on-finger-touchandroiddraw

这是一个使用画布绘制线条的简单类,如下所示。

    public class TestLineView extends View {

    private Paint paint;
    private PointF startPoint, endPoint;
    private boolean isDrawing;

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

    private void init()
    {
        paint = new Paint();
        paint.setColor(Color.RED);
        paint.setStyle(Style.STROKE);
        paint.setStrokeWidth(2);
        paint.setAntiAlias(true);
    }

    @Override
    protected void onDraw(Canvas canvas)
    {
        if(isDrawing)
        {
            canvas.drawLine(startPoint.x, startPoint.y, endPoint.x, endPoint.y, paint);
        }
    }


    @Override
    public boolean onTouchEvent(MotionEvent event)
    {
        switch (event.getAction())
        {
            case MotionEvent.ACTION_DOWN:
                startPoint = new PointF(event.getX(), event.getY());
                endPoint = new PointF();
                isDrawing = true;
                break;
            case MotionEvent.ACTION_MOVE:
                if(isDrawing)
                {
                    endPoint.x = event.getX();
                    endPoint.y = event.getY();
                    invalidate();
                }
                break;
            case MotionEvent.ACTION_UP:
                if(isDrawing)
                {
                    endPoint.x = event.getX();
                    endPoint.y = event.getY();
                    isDrawing = false;
                    invalidate();
                }
                break;
            default:
                break;
        }
        return true;
    }
}

【讨论】:

    【解决方案2】:

    首先浏览 sdk 示例中的 Fingerpaint 演示。

    另一个示例:

    public class MainActivity extends Activity {
    
        DrawingView dv ;
        private Paint mPaint;    
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            dv = new DrawingView(this);
            setContentView(dv);
            mPaint = new Paint();
            mPaint.setAntiAlias(true);
            mPaint.setDither(true);
            mPaint.setColor(Color.GREEN);
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setStrokeJoin(Paint.Join.ROUND);
            mPaint.setStrokeCap(Paint.Cap.ROUND);
            mPaint.setStrokeWidth(12);
        }
    
        public class DrawingView extends View {
    
            public int width;
            public  int height;
            private Bitmap  mBitmap;
            private Canvas  mCanvas;
            private Path    mPath;
            private Paint   mBitmapPaint;
            Context context;
            private Paint circlePaint;
            private Path circlePath;
    
            public DrawingView(Context c) {
                super(c);
                context=c;
                mPath = new Path();
                mBitmapPaint = new Paint(Paint.DITHER_FLAG);
                circlePaint = new Paint();
                circlePath = new Path();
                circlePaint.setAntiAlias(true);
                circlePaint.setColor(Color.BLUE);
                circlePaint.setStyle(Paint.Style.STROKE);
                circlePaint.setStrokeJoin(Paint.Join.MITER);
                circlePaint.setStrokeWidth(4f);
            }
    
            @Override
            protected void onSizeChanged(int w, int h, int oldw, int oldh) {
                super.onSizeChanged(w, h, oldw, oldh);
    
                mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
                mCanvas = new Canvas(mBitmap);
            }
    
            @Override
            protected void onDraw(Canvas canvas) {
                super.onDraw(canvas);
    
                canvas.drawBitmap( mBitmap, 0, 0, mBitmapPaint);
                canvas.drawPath( mPath,  mPaint);
                canvas.drawPath( circlePath,  circlePaint);
            }
    
            private float mX, mY;
            private static final float TOUCH_TOLERANCE = 4;
    
            private void touch_start(float x, float y) {
                mPath.reset();
                mPath.moveTo(x, y);
                mX = x;
                mY = y;
            }
    
            private void touch_move(float x, float y) {
                float dx = Math.abs(x - mX);
                float dy = Math.abs(y - mY);
                if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
                    mPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
                    mX = x;
                    mY = y;
    
                    circlePath.reset();
                    circlePath.addCircle(mX, mY, 30, Path.Direction.CW);
                }
            }
    
            private void touch_up() {
                mPath.lineTo(mX, mY);
                circlePath.reset();
                // commit the path to our offscreen
                mCanvas.drawPath(mPath,  mPaint);
                // kill this so we don't double draw
                mPath.reset();
            }
    
            @Override
            public boolean onTouchEvent(MotionEvent event) {
                float x = event.getX();
                float y = event.getY();
    
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        touch_start(x, y);
                        invalidate();
                        break;
                    case MotionEvent.ACTION_MOVE:
                        touch_move(x, y);
                        invalidate();
                        break;
                    case MotionEvent.ACTION_UP:
                        touch_up();
                        invalidate();
                        break;
                }
                return true;
            }
        }
    }
    

    快照

    解释:

    您正在创建一个视图类,然后扩展视图。您覆盖 onDraw()。您添加手指触摸和移动的路径。您覆盖此目的的 onTouch()。在您的 onDraw() 中,您使用您选择的颜料绘制路径。您应该调用 invalidate() 来刷新视图。

    要选择选项,您可以单击菜单并选择选项。

    以下内容可以作为参考。您可以根据需要修改以下内容。

    public class FingerPaintActivity extends Activity
            implements ColorPickerDialog.OnColorChangedListener {
    
        MyView mv;
        AlertDialog dialog;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            mv= new MyView(this);
            mv.setDrawingCacheEnabled(true);
            mv.setBackgroundResource(R.drawable.afor);//set the back ground if you wish to
            setContentView(mv);
            mPaint = new Paint();
            mPaint.setAntiAlias(true);
            mPaint.setDither(true);
            mPaint.setColor(0xFFFF0000);
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setStrokeJoin(Paint.Join.ROUND);
            mPaint.setStrokeCap(Paint.Cap.ROUND);
            mPaint.setStrokeWidth(20);
            mEmboss = new EmbossMaskFilter(new float[] { 1, 1, 1 },
                    0.4f, 6, 3.5f);
            mBlur = new BlurMaskFilter(8, BlurMaskFilter.Blur.NORMAL);
        }
    
        private Paint       mPaint;
        private MaskFilter  mEmboss;
        private MaskFilter  mBlur;
    
        public void colorChanged(int color) {
            mPaint.setColor(color);
        }
    
        public class MyView extends View {
    
            private static final float MINP = 0.25f;
            private static final float MAXP = 0.75f;
            private Bitmap  mBitmap;
            private Canvas  mCanvas;
            private Path    mPath;
            private Paint   mBitmapPaint;
            Context context;
    
            public MyView(Context c) {
                super(c);
                context=c;
                mPath = new Path();
                mBitmapPaint = new Paint(Paint.DITHER_FLAG);
    
            }
    
            @Override
            protected void onSizeChanged(int w, int h, int oldw, int oldh) {
                super.onSizeChanged(w, h, oldw, oldh);
                mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
                mCanvas = new Canvas(mBitmap);
    
            }
    
            @Override
            protected void onDraw(Canvas canvas) {
                super.onDraw(canvas);
    
                canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
                canvas.drawPath(mPath, mPaint);
            }
    
            private float mX, mY;
            private static final float TOUCH_TOLERANCE = 4;
    
            private void touch_start(float x, float y) {
                //showDialog(); 
                mPath.reset();
                mPath.moveTo(x, y);
                mX = x;
                mY = y;
    
            }
            private void touch_move(float x, float y) {
                float dx = Math.abs(x - mX);
                float dy = Math.abs(y - mY);
                if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
                    mPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
                    mX = x;
                    mY = y;
                }
            }
    
            private void touch_up() {
                mPath.lineTo(mX, mY);
                // commit the path to our offscreen
                mCanvas.drawPath(mPath, mPaint);
                // kill this so we don't double draw
                mPath.reset();
                mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SCREEN));
                //mPaint.setMaskFilter(null);
            }
    
            @Override
            public boolean onTouchEvent(MotionEvent event) {
                float x = event.getX();
                float y = event.getY();
    
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        touch_start(x, y);
                        invalidate();
                        break;
                    case MotionEvent.ACTION_MOVE:
    
                        touch_move(x, y);
                        invalidate();
                        break;
                    case MotionEvent.ACTION_UP:
                        touch_up();
                        invalidate();
                        break;
                }
                return true;
            }
        }
    
        private static final int COLOR_MENU_ID = Menu.FIRST;
        private static final int EMBOSS_MENU_ID = Menu.FIRST + 1;
        private static final int BLUR_MENU_ID = Menu.FIRST + 2;
        private static final int ERASE_MENU_ID = Menu.FIRST + 3;
        private static final int SRCATOP_MENU_ID = Menu.FIRST + 4;
        private static final int Save = Menu.FIRST + 5;
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            super.onCreateOptionsMenu(menu);
    
            menu.add(0, COLOR_MENU_ID, 0, "Color").setShortcut('3', 'c');
            menu.add(0, EMBOSS_MENU_ID, 0, "Emboss").setShortcut('4', 's');
            menu.add(0, BLUR_MENU_ID, 0, "Blur").setShortcut('5', 'z');
            menu.add(0, ERASE_MENU_ID, 0, "Erase").setShortcut('5', 'z');
            menu.add(0, SRCATOP_MENU_ID, 0, "SrcATop").setShortcut('5', 'z');
            menu.add(0, Save, 0, "Save").setShortcut('5', 'z');
    
            return true;
        }
    
        @Override
        public boolean onPrepareOptionsMenu(Menu menu) {
            super.onPrepareOptionsMenu(menu);
            return true;
        }
    
        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            mPaint.setXfermode(null);
            mPaint.setAlpha(0xFF);
    
            switch (item.getItemId()) {
                case COLOR_MENU_ID:
                    new ColorPickerDialog(this, this, mPaint.getColor()).show();
                    return true;
                case EMBOSS_MENU_ID:
                    if (mPaint.getMaskFilter() != mEmboss) {
                        mPaint.setMaskFilter(mEmboss);
                    } else {
                        mPaint.setMaskFilter(null);
                    }
                    return true;
                case BLUR_MENU_ID:
                    if (mPaint.getMaskFilter() != mBlur) {
                        mPaint.setMaskFilter(mBlur);
                    } else {
                        mPaint.setMaskFilter(null);
                    }
                    return true;
                case ERASE_MENU_ID:
                    mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
                    mPaint.setAlpha(0x80);
                    return true;
                case SRCATOP_MENU_ID:
    
                    mPaint.setXfermode(new PorterDuffXfermode(
                            PorterDuff.Mode.SRC_ATOP));
                    mPaint.setAlpha(0x80);
                    return true;
                case Save:
                    AlertDialog.Builder editalert = new AlertDialog.Builder(FingerPaintActivity.this);
                    editalert.setTitle("Please Enter the name with which you want to Save");
                    final EditText input = new EditText(FingerPaintActivity.this);
                    LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
                            LinearLayout.LayoutParams.FILL_PARENT,
                            LinearLayout.LayoutParams.FILL_PARENT);
                    input.setLayoutParams(lp);
                    editalert.setView(input);
                    editalert.setPositiveButton("OK", new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int whichButton) {
    
                            String name= input.getText().toString();
                            Bitmap bitmap = mv.getDrawingCache();
    
                            String path = Environment.getExternalStorageDirectory().getAbsolutePath();
                            File file = new File("/sdcard/"+name+".png");
                            try
                            {
                                if(!file.exists())
                                {
                                    file.createNewFile();
                                }
                                FileOutputStream ostream = new FileOutputStream(file);
                                bitmap.compress(CompressFormat.PNG, 10, ostream);
                                ostream.close();
                                mv.invalidate();
                            }
                            catch (Exception e)
                            {
                                e.printStackTrace();
                            }finally
                            {
    
                                mv.setDrawingCacheEnabled(false);
                            }
                        }
                    });
    
                    editalert.show();
                    return true;
            }
            return super.onOptionsItemSelected(item);
        }
    }
    

    颜色选择器

    public class ColorPickerDialog extends Dialog {
    
        public interface OnColorChangedListener {
            void colorChanged(int color);
        }
    
        private OnColorChangedListener mListener;
        private int mInitialColor;
    
        private static class ColorPickerView extends View {
            private Paint mPaint;
            private Paint mCenterPaint;
            private final int[] mColors;
            private OnColorChangedListener mListener;
    
            ColorPickerView(Context c, OnColorChangedListener l, int color) {
                super(c);
                mListener = l;
                mColors = new int[] {
                        0xFFFF0000, 0xFFFF00FF, 0xFF0000FF, 0xFF00FFFF, 0xFF00FF00,
                        0xFFFFFF00, 0xFFFF0000
                };
                Shader s = new SweepGradient(0, 0, mColors, null);
    
                mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
                mPaint.setShader(s);
                mPaint.setStyle(Paint.Style.STROKE);
                mPaint.setStrokeWidth(32);
    
                mCenterPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
                mCenterPaint.setColor(color);
                mCenterPaint.setStrokeWidth(5);
            }
    
            private boolean mTrackingCenter;
            private boolean mHighlightCenter;
    
            @Override
            protected void onDraw(Canvas canvas) {
                float r = CENTER_X - mPaint.getStrokeWidth()*0.5f;
    
                canvas.translate(CENTER_X, CENTER_X);
    
                canvas.drawOval(new RectF(-r, -r, r, r), mPaint);
                canvas.drawCircle(0, 0, CENTER_RADIUS, mCenterPaint);
    
                if (mTrackingCenter) {
                    int c = mCenterPaint.getColor();
                    mCenterPaint.setStyle(Paint.Style.STROKE);
    
                    if (mHighlightCenter) {
                        mCenterPaint.setAlpha(0xFF);
                    } else {
                        mCenterPaint.setAlpha(0x80);
                    }
                    canvas.drawCircle(0, 0,
                            CENTER_RADIUS + mCenterPaint.getStrokeWidth(),
                            mCenterPaint);
    
                    mCenterPaint.setStyle(Paint.Style.FILL);
                    mCenterPaint.setColor(c);
                }
            }
    
            @Override
            protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
                setMeasuredDimension(CENTER_X*2, CENTER_Y*2);
            }
    
            private static final int CENTER_X = 100;
            private static final int CENTER_Y = 100;
            private static final int CENTER_RADIUS = 32;
    
            private int floatToByte(float x) {
                int n = java.lang.Math.round(x);
                return n;
            }
    
            private int pinToByte(int n) {
                if (n < 0) {
                    n = 0;
                } else if (n > 255) {
                    n = 255;
                }
                return n;
            }
    
            private int ave(int s, int d, float p) {
                return s + java.lang.Math.round(p * (d - s));
            }
    
            private int interpColor(int colors[], float unit) {
                if (unit <= 0) {
                    return colors[0];
                }
                if (unit >= 1) {
                    return colors[colors.length - 1];
                }
    
                float p = unit * (colors.length - 1);
                int i = (int)p;
                p -= i;
    
                // now p is just the fractional part [0...1) and i is the index
                int c0 = colors[i];
                int c1 = colors[i+1];
                int a = ave(Color.alpha(c0), Color.alpha(c1), p);
                int r = ave(Color.red(c0), Color.red(c1), p);
                int g = ave(Color.green(c0), Color.green(c1), p);
                int b = ave(Color.blue(c0), Color.blue(c1), p);
    
                return Color.argb(a, r, g, b);
            }
    
            private int rotateColor(int color, float rad) {
                float deg = rad * 180 / 3.1415927f;
                int r = Color.red(color);
                int g = Color.green(color);
                int b = Color.blue(color);
    
                ColorMatrix cm = new ColorMatrix();
                ColorMatrix tmp = new ColorMatrix();
    
                cm.setRGB2YUV();
                tmp.setRotate(0, deg);
                cm.postConcat(tmp);
                tmp.setYUV2RGB();
                cm.postConcat(tmp);
    
                final float[] a = cm.getArray();
    
                int ir = floatToByte(a[0] * r +  a[1] * g +  a[2] * b);
                int ig = floatToByte(a[5] * r +  a[6] * g +  a[7] * b);
                int ib = floatToByte(a[10] * r + a[11] * g + a[12] * b);
    
                return Color.argb(Color.alpha(color), pinToByte(ir),
                        pinToByte(ig), pinToByte(ib));
            }
    
            private static final float PI = 3.1415926f;
    
            @Override
            public boolean onTouchEvent(MotionEvent event) {
                float x = event.getX() - CENTER_X;
                float y = event.getY() - CENTER_Y;
                boolean inCenter = java.lang.Math.sqrt(x*x + y*y) <= CENTER_RADIUS;
    
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        mTrackingCenter = inCenter;
                        if (inCenter) {
                            mHighlightCenter = true;
                            invalidate();
                            break;
                        }
                    case MotionEvent.ACTION_MOVE:
                        if (mTrackingCenter) {
                            if (mHighlightCenter != inCenter) {
                                mHighlightCenter = inCenter;
                                invalidate();
                            }
                        } else {
                            float angle = (float)java.lang.Math.atan2(y, x);
                            // need to turn angle [-PI ... PI] into unit [0....1]
                            float unit = angle/(2*PI);
                            if (unit < 0) {
                                unit += 1;
                            }
                            mCenterPaint.setColor(interpColor(mColors, unit));
                            invalidate();
                        }
                        break;
                    case MotionEvent.ACTION_UP:
                        if (mTrackingCenter) {
                            if (inCenter) {
                                mListener.colorChanged(mCenterPaint.getColor());
                            }
                            mTrackingCenter = false;    // so we draw w/o halo
                            invalidate();
                        }
                        break;
                }
                return true;
            }
        }
    
        public ColorPickerDialog(Context context,
                                 OnColorChangedListener listener,
                                 int initialColor) {
            super(context);
    
            mListener = listener;
            mInitialColor = initialColor;
        }
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            OnColorChangedListener l = new OnColorChangedListener() {
                public void colorChanged(int color) {
                    mListener.colorChanged(color);
                    dismiss();
                }
            };
    
            setContentView(new ColorPickerView(getContext(), l, mInitialColor));
            setTitle("Pick a Color");
        }
    }
    

    【讨论】:

      【解决方案3】:

      关于上面 Raghunandan 的漂亮代码。

      许多人问如何“清除”绘图。这样做的方法如下:

      public void clearDrawing()
          {
          Utils.Log("RaghunandanDraw, how to clear....");
      
          setDrawingCacheEnabled(false);
          // don't forget that one and the match below,
          // or you just keep getting a duplicate when you save.
      
          onSizeChanged(width, height, width, height);
          invalidate();
      
          setDrawingCacheEnabled(true);
          }
      
      @Override
      protected void onSizeChanged(int w, int h, int oldw, int oldh)
          {
          super.onSizeChanged(w, h, oldw, oldh);
      
          width = w;      // don't forget these
          height = h;
      
          mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
          mCanvas = new Canvas(mBitmap);
          }
      

      许多人问如何“保存”绘图。这样做的方法如下:

      public DrawingView(Context c)
        {
        circlePaint.setStrokeJoin(Paint.Join.MITER);
        circlePaint.setStrokeWidth(4f); 
        etc...
      
        // in the class where you set up the view, add this:
        setDrawingCacheEnabled( true );
        }
      
      public void saveDrawing()
        {
        Bitmap whatTheUserDrewBitmap = getDrawingCache();
        // don't forget to clear it (see above) or you just get duplicates
      
        // almost always you will want to reduce res from the very high screen res
        whatTheUserDrewBitmap =
               ThumbnailUtils.extractThumbnail(whatTheUserDrewBitmap, 256, 256);
        // NOTE that's an incredibly useful trick for cropping/resizing squares
        // while handling all memory problems etc
        // http://stackoverflow.com/a/17733530/294884
      
        // you can now save the bitmap to a file, or display it in an ImageView:
        ImageView testArea = ...
        testArea.setImageBitmap( whatTheUserDrewBitmap );
      
        // these days you often need a "byte array". for example,
        // to save to parse.com or other cloud services
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        whatTheUserDrewBitmap.compress(Bitmap.CompressFormat.PNG, 0, baos);
        byte[] yourByteArray;
        yourByteArray = baos.toByteArray();
        }
      

      希望它对某人有所帮助,因为这对我有所帮助。

      【讨论】:

      • PS 如果你在 Mac 上寻找指纹演示,stackoverflow.com/questions/24164334
      • 你从哪里得到宽度和高度,因为@Raghunandan 没有在他的代码中设置这些变量?是签名区域的尺寸吗?
      • 嘿罗伯塔斯,他们就在 public class DrawingView extends View { ...前两项!不要犹豫再问更多的问题。干杯。是的,当系统首次调用 onSizeChanged 时,它们会“自动”设置。
      • 是的,它们在前两行,但有些它们的值是 0,甚至比在视图上绘制的东西还要多。我刚刚复制并粘贴了有效的@Raghunandan 代码。然后你的clearDrawing 方法被包括在内我得到异常,因为高度和宽度必须> 0。然后我查看了代码,发现这些变量没有设置。所以我问你如何获得宽度和高度的值。附:如果你想刷新绘图区,你必须打电话给invalidate()
      【解决方案4】:

      我认为添加一个东西很重要,如果您使用drawview中的构造函数不正确的布局膨胀,请在类中添加这些构造函数:

      public DrawingView(Context c, AttributeSet attrs) {
          super(c, attrs);
          ...
      }
      
      public DrawingView(Context c, AttributeSet attrs, int defStyle) {
          super(c, attrs, defStyle);
          ...
      }
      

      或者android系统无法对布局文件进行膨胀。我希望这能有所帮助。

      【讨论】:

        【解决方案5】:

        你可以简单地使用这个类:

        public class DoodleCanvas  extends View{
        
            private Paint mPaint;
            private Path mPath;
        
            public DoodleCanvas(Context context, AttributeSet attrs) {
                super(context, attrs);
                mPaint = new Paint();
                mPaint.setColor(Color.RED);
                mPaint.setStyle(Paint.Style.STROKE);
                mPaint.setStrokeJoin(Paint.Join.ROUND);
                mPaint.setStrokeCap(Paint.Cap.ROUND);
                mPaint.setStrokeWidth(10);
                mPath = new Path();
            }
        
        
            @Override
            protected void onDraw(Canvas canvas) {
                canvas.drawPath(mPath, mPaint);
                super.onDraw(canvas);
            }
        
        
            @Override
            public boolean onTouchEvent(MotionEvent event) {
        
                switch (event.getAction()){
        
                    case MotionEvent.ACTION_DOWN:
                        mPath.moveTo(event.getX(), event.getY());
                        break;
        
                    case MotionEvent.ACTION_MOVE:
                        mPath.lineTo(event.getX(), event.getY());
                        invalidate();
                        break;
        
                    case MotionEvent.ACTION_UP:
                        break;
                }
        
                return true;
            }
        }
        

        【讨论】:

          【解决方案6】:

          除了 Ishan 的回答之外,如果您想在没有用户交互的情况下以编程方式绘制,您可以像这样编辑类。

          public class DrawingCanvas extends View {
          
          private Paint mPaint;
          private Path mPath;
          private boolean isUserInteractionEnabled = false;
          
          public DrawingCanvas(Context context, AttributeSet attrs) {
              super(context, attrs);
              mPaint = new Paint();
              mPaint.setColor(Color.RED);
              mPaint.setStyle(Paint.Style.STROKE);
              mPaint.setStrokeJoin(Paint.Join.ROUND);
              mPaint.setStrokeCap(Paint.Cap.ROUND);
              mPaint.setStrokeWidth(10);
              mPath = new Path();
          }
          
          
          @Override
          protected void onDraw(Canvas canvas) {
              canvas.drawPath(mPath, mPaint);
              super.onDraw(canvas);
          }
          
          
          @Override
          public boolean onTouchEvent(MotionEvent event) {
              if (isUserInteractionEnabled) {
                  switch (event.getAction()) {
                      case MotionEvent.ACTION_DOWN:
                          mPath.moveTo(event.getX(), event.getY());
                          break;
                      case MotionEvent.ACTION_MOVE:
                          mPath.lineTo(event.getX(), event.getY());
                          invalidate();
                          break;
                      case MotionEvent.ACTION_UP:
                          break;
                  }
              }
          
              return true;
          }
          
          public void moveCursorTo(float x, float y) {
              mPath.moveTo(x, y);
          }
          
          public void makeLine(float toX, float toY) {
              mPath.lineTo(toX, toY);
          }
          
          public void setUserInteractionEnabled(boolean userInteractionEnabled) {
              isUserInteractionEnabled = userInteractionEnabled;
          }
          }
          

          然后像这样使用它

          drawingCanvas.setUserInteractionEnabled(true) // to enable user interaction
          drawingCanvas.setUserInteractionEnabled(true) // to disable user interaction
          

          以编程方式绘制

          drawingCanvas.moveCursorTo(70f, 70f) // Move the cursor (Define starting point)
          drawingCanvas.makeLine(200f, 200f) // End point (To where you need to draw)
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-05-05
            • 2012-06-11
            • 1970-01-01
            • 2014-11-18
            • 2021-04-02
            相关资源
            最近更新 更多