【问题标题】:Android drawing a line to follow your fingerAndroid画一条线跟随你的手指
【发布时间】:2011-05-17 01:40:43
【问题描述】:

我想做的是画一条沿着我的手指的线。我创建了 一个自定义视图,我有一个可以使用的onTouchEvent()

我可以在onDraw() 方法中画一条静态线,而不费力。

我不确定如何在手指移动时画出线条。

  public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN: {
            Log.e(TAG, " - DOWN -");
            Log.e(TAG, " getX: " + event.getX());
            break;
        }
        case MotionEvent.ACTION_UP: {
            Log.e(TAG, " - UP -");
            Log.e(TAG, " getX: " + event.getX());
            break;
        }
        }
        return true;
    }

有没有做过一段时间的小伙伴可以给点建议?

我是否需要在onTouchEvent() 上设置坐标并不断使视图无效 那么小线段画出来了吗?

最后,我只想能够用手指在屏幕上涂鸦 这个实验。

【问题讨论】:

  • 已发布答案,但请先尝试自行寻找答案。正如您在我的回答中看到的那样,已经有很多类似的东西了,Google 搜索就是您的朋友。

标签: android drawing touch-event


【解决方案1】:

您只跟踪 up 和 down 事件。也跟踪 ACTION_MOVE 事件。请注意,即使人的手指没有明显移动,它也会持续跟踪。你的代码应该是这样的:

ACTION_DOWN:存储位置。

ACTION_MOVE:如果位置与存储位置不同,则从存储位置到当前位置画一条线,并将存储位置更新为当前位置。

ACTION_UP:停止。

在 ACTION_MOVE 位中,最好检查该位置是否距离存储的位置至少 2 或 3 个像素。如果您要存储所有绘图点,以便稍后对数据进行处理,那么可能会将其增加到 10 个像素,这样您就不会因为一条简单的线而得到数百个点。

【讨论】:

  • 好消息!今晚我会玩这个。线条的实际绘制应该在 onDraw 方法中完成,虽然正确吗?我会将行信息存储在操作中,然后调用 invalidate 来触发 onDraw 以完成工作吗?
  • 哦,是的,当然,您不会在事件处理程序中进行绘图。您需要以某种方式存储绘图点,然后在 onDraw 中绘制线条。
  • 现在很好用!谢谢。我会给你+1,但我的排名显然不够高:(
  • 很好解释! @AndrewSmith
【解决方案2】:

这就是我最终要做的。希望这可以帮助其他一些初学者入门。

我有一个 Sprite 类,它代表我想在屏幕上移动的对象:

   public class Sprite {
    private final String TAG = "Sprite";
    private Drawable drawable;
    private int x; // the X coordinate
    private int y; // the Y coordinate
    private boolean touched; // if droid is touched/picked up
    private Speed speed; // the speed with its directions

    public Sprite(Drawable drawable, int x, int y) {
        this.drawable = drawable;
        this.x = x;
        this.y = y;
        this.speed = new Speed();
    }

    public void draw(Canvas canvas) {
        drawable.setBounds(new Rect(x, y, x+drawable.getIntrinsicWidth(), y+drawable.getIntrinsicHeight()));
        drawable.draw(canvas);
    }

    public void move() {
        if (!touched) {
            x += (speed.getXv() * speed.getxDirection());
            y += (speed.getYv() * speed.getyDirection());
        }
    }

    public void handleActionDown(int eventX, int eventY) {
        if (eventX >= (x - bitmap.getWidth() / 2) && (eventX <= (x + bitmap.getWidth() / 2))) {
            if (eventY >= (y - bitmap.getHeight() / 2) && (y <= (y + bitmap.getHeight() / 2))) {
                // droid touched
                setTouched(true);
            } else {
                setTouched(false);
            }
        } else {
            setTouched(false);
        }
    }
}

然后我有一个主游戏循环。它循环并调用我的 mainPanel 的渲染和更新方法,如下所示:

    public void render(Canvas canvas) {
    canvas.drawColor(Color.BLACK);
    sprite.draw(canvas);
}

public void update() {
    sprite.move();
}

精灵移动的位置在动作事件捕获中处理:

        if (event.getAction() == MotionEvent.ACTION_MOVE) {
        // the gestures
        if (sprite.isTouched()) {
            sprite.setX((int) event.getX());
            sprite.setY((int) event.getY());
        }
    }

希望这会有所帮助。如果我修剪得太多,有什么你不知道的,请告诉我。

下一步,让物体顺着线走!

【讨论】:

  • 速度课有什么?你能解释一下吗?
【解决方案3】:

触摸事件与可检索的指针计数列表相关联,如下所示:

     int p = event.getPointerCount();

遍历这些和绘制点可能会导致连续 出现的行

if (event.getAction() == MotionEvent.ACTION_MOVE
    || event.getAction() == MotionEvent.ACTION_DOWN) {

  int p = event.getPointerCount();
     for (int i = 0; i < p; i++) { 
       c.drawPoint(event.getX(i), event.getY(i), paint);
     }
}

假设paint 已经设置并且c 是画布,在绘制之前可能需要锁定(例如在多线程应用程序中)。

【讨论】:

    【解决方案4】:

    对于新手,此代码将帮助您创建涂鸦图像并将其导出为 Png 图像 这里是Complete CODE,这个活动类也包含一个视图类..

    public class MainActivity extends Activity {
        private Bitmap DrawBitmap;
        private Canvas mCanvas;
        private Path mPath;
        private Paint DrawBitmapPaint;
        RelativeLayout Rl;
        CustomView View;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            View = new CustomView(this);
            Rl = (RelativeLayout) findViewById(R.id.Rel);
            Rl.addView(View);
            mPaint = new Paint();
            mPaint.setAntiAlias(true);
            mPaint.setDither(true);
            mPaint.setColor(getResources()
                    .getColor(android.R.color.holo_green_dark));
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setStrokeJoin(Paint.Join.ROUND);
            mPaint.setStrokeCap(Paint.Cap.ROUND);
            mPaint.setStrokeWidth(20);
    
        }
    
        private Paint mPaint;
    
        public class CustomView extends View {
    
            @SuppressWarnings("deprecation")
            public CustomView(Context c) {
    
                super(c);
                Display Disp = getWindowManager().getDefaultDisplay();
                DrawBitmap = Bitmap.createBitmap(Disp.getWidth(), Disp.getHeight(),
                        Bitmap.Config.ARGB_4444);
    
                mCanvas = new Canvas(DrawBitmap);
    
                mPath = new Path();
                DrawBitmapPaint = new Paint(Paint.DITHER_FLAG);
            }
    
            @Override
            protected void onSizeChanged(int w, int h, int oldw, int oldh) {
                super.onSizeChanged(w, h, oldw, oldh);
            }
    
            @Override
            protected void onDraw(Canvas canvas) {
                setDrawingCacheEnabled(true);
                canvas.drawBitmap(DrawBitmap, 0, 0, DrawBitmapPaint);
                canvas.drawPath(mPath, mPaint);
                canvas.drawRect(mY, 0, mY, 0, DrawBitmapPaint);
            }
    
            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;
                }
            }
    
            private void touch_up() {
                mPath.lineTo(mX, mY);
    
                mCanvas.drawPath(mPath, mPaint);
    
                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;
            }
    
        }
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            getMenuInflater().inflate(R.menu.main, menu);
            return true;
        }
    
        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            mPaint.setXfermode(null);
            switch (item.getItemId()) {
            case R.id.erase: 
                   mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
                   break;
            case R.id.DELETE: 
                 View =  new CustomView(this);
                   break;
            case R.id.draw: 
                   mPaint.setXfermode(null);
    
                   break;
            case R.id.Save:
                String pattern = "mm ss";
                SimpleDateFormat formatter = new SimpleDateFormat(pattern);
                String time = formatter.format(new Date());
                String path = ("/d-codepages" + time + ".png");
    
                File file = new File(Environment.getExternalStorageDirectory()
                        + path);
    
                try {
                    DrawBitmap.compress(Bitmap.CompressFormat.PNG, 100,
                            new FileOutputStream(file));
                    Toast.makeText(this, "File Saved ::" + path, Toast.LENGTH_SHORT)
                            .show();
                } catch (Exception e) {
                    Toast.makeText(this, "ERROR" + e.toString(), Toast.LENGTH_SHORT)
                            .show();
                }
    
            }
            return super.onOptionsItemSelected(item);
        }
    
    }
    

    【讨论】:

    • 可以确认这在 2020 年有效,尽管今年没有其他工作。干杯?
    【解决方案5】:

    还可以查看 Java Path 类。您可以使用它来绘制路径...当您在屏幕上移动手指时。每次更新(但是您实现了这一点 - 例如,上次更新中的每一个像素)您将 x,y 坐标添加到您的路径并通过循环重新渲染总路径。只是我现在正在玩的一个想法。

    【讨论】:

    • 我已经有一段时间没有玩过这个项目了,但是感谢您提供的信息!如果您不介意,请粘贴您的代码。再次感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多