android - 识别自定义 View 上的三次点击

标签 android canvas android-widget touch-event

我想在用户点击自定义 View 时绘制圆圈,并根据点击次数改变圆圈颜色。

Single Tap : YELLOW CIRCLE
Double Tap : GREEN CIRCLE
Triple Tap : RED COLOR

问题是,我制作了一个自定义 View ,该 View 将根据时间计算点击事件,但有时它会错过第一次点击。这导致了 View 中的问题。

以下代码显示了我为实现上述自定义 View 所做的所有努力。

TripleTapView

package com.slk.car_rating_app;

import java.util.ArrayList;
import java.util.Date;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.RectF;
import android.os.CountDownTimer;
import android.view.MotionEvent;
import android.view.View;

public class TripleTapView extends View {
    // Set the tap delay in milliseconds
    protected static final long TAP_MAX_DELAY = 500L;
    // Radius to capture tap within bound
    final static int RADIUS = 30;
    // Store all points with tap count
    public ArrayList<CustomPoint> point = new ArrayList<CustomPoint>();
    // Context to access view
    Context context;
    Paint paint;
    private long thisTime = 0, prevTime = 0;
    private boolean firstTap = true, doubleTap = false;;
    float stopX, stopY, startX, startY;
    RectF area_rect;
    TapCounter tapCounter = new TapCounter(TAP_MAX_DELAY, TAP_MAX_DELAY);

    public TripleTapView(Context context) {
        super(context);
        this.context = context;
        paint = new Paint();
        paint.setColor(Color.GREEN);
        paint.setAntiAlias(true);
        paint.setDither(true);
        paint.setStyle(Paint.Style.FILL);
        paint.setStrokeJoin(Paint.Join.ROUND);
        paint.setStrokeCap(Paint.Cap.ROUND);
        paint.setStrokeWidth(2);
    }

    @SuppressLint("DrawAllocation")
    @Override
    protected void onDraw(final Canvas canvas) {
        super.onDraw(canvas);
        for (CustomPoint point_temp : point) {
            // For changing tap circle color based on tap count
            switch (point_temp.count) {
            case 1:
                paint.setColor(Color.YELLOW);
                break;
            case 2:
                paint.setColor(Color.GREEN);
                break;
            case 3:
                paint.setColor(Color.RED);
                break;
            }
            canvas.drawCircle(point_temp.point.x, point_temp.point.y, 10, paint);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            stopX = event.getX();
            stopY = event.getY();
            if (firstTap) {
                addFirstTap();
            } else if (doubleTap) {
                prevTime = thisTime;
                thisTime = new Date().getTime();
                if (thisTime > prevTime) {
                    if ((thisTime - prevTime) <= TAP_MAX_DELAY) {
                        if (area_rect.contains(stopX, stopY))
                            doubleTap = false;
                        else {
                            addPoint(1);
                            addFirstTap();
                        }
                    } else {
                        addPoint(1);
                        firstTap = true;
                    }
                } else {
                    firstTap = true;
                }
            } else {
                prevTime = thisTime;
                thisTime = new Date().getTime();
                if (thisTime > prevTime) {
                    if ((thisTime - prevTime) <= TAP_MAX_DELAY) {
                        if (area_rect.contains(stopX, stopY)) {
                            addPoint(3);
                            firstTap = true;
                        } else {
                            addPoint(2);
                            addFirstTap();
                        }
                    } else {
                        addPoint(2);
                        firstTap = true;
                    }
                } else {
                    firstTap = true;
                }
            }
        }
        return true;
    }

    void addPoint(int tapCount) {
        point.add(new CustomPoint(new PointF(startX, startY), tapCount));
        invalidate();
    }

    void addFirstTap() {
        thisTime = new Date().getTime();
        firstTap = false;
        doubleTap = true;
        startX = stopX;
        startY = stopY;
        area_rect = new RectF(stopX - RADIUS, stopY - RADIUS, stopX + RADIUS,
                stopY + RADIUS);
        tapCounter.resetCounter();
    }

    class TapCounter extends CountDownTimer {
        public TapCounter(long millisInFuture, long countDownInterval) {
            super(millisInFuture, countDownInterval);
        }

        @Override
        public void onFinish() {
            if (doubleTap) {
                prevTime = thisTime;
                thisTime = new Date().getTime();
                if (thisTime > prevTime) {
                    if ((thisTime - prevTime) <= TAP_MAX_DELAY) {
                        doubleTap = false;
                    } else {
                        addPoint(1);
                        firstTap = true;
                    }
                } else {
                    firstTap = true;
                }
            } else if (!firstTap && !doubleTap) {
                prevTime = thisTime;
                thisTime =  new Date().getTime();
                if (thisTime > prevTime) {
                    if ((thisTime - prevTime) <= TAP_MAX_DELAY) {
                        addPoint(2);
                        firstTap = true;
                    }
                } else {
                    firstTap = true;
                }
            }
        }

        @Override
        public void onTick(long millisUntilFinished) {
        }

        public void resetCounter() {
            start();
        }
    }
}

请帮我解决这个问题。

最佳答案

此代码将满足您的需要。我简化了你的类(class)。

import java.util.ArrayList;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.RectF;
import android.os.CountDownTimer;
import android.view.MotionEvent;
import android.view.View;

public class TripleTapView extends View {

    // Set the tap delay in milliseconds
    protected static final long TAP_MAX_DELAY = 500L;
    // Radius to capture tap within bound
    private final static int RADIUS = 30;
    // Store all points with tap count
    public ArrayList<CustomPoint> _points = new ArrayList<CustomPoint>();

    Context _context;
    Paint _paint;

    TapCounter _tapCounter = new TapCounter(TAP_MAX_DELAY, TAP_MAX_DELAY);

    public TripleTapView(Context context) {
        super(context);
        _context = context;

        _paint = new Paint();
        _paint.setAntiAlias(true);
        _paint.setDither(true);
        _paint.setStyle(Paint.Style.FILL);
        _paint.setStrokeJoin(Paint.Join.ROUND);
        _paint.setStrokeCap(Paint.Cap.ROUND);
        _paint.setStrokeWidth(2);
    }

    @Override
    protected void onDraw(final Canvas canvas) {
        super.onDraw(canvas);
        for (CustomPoint point_temp : _points) {
            // For changing tap circle color based on tap count
            switch (point_temp.count) {
            case 1:
                _paint.setColor(Color.YELLOW);
                break;
            case 2:
                _paint.setColor(Color.GREEN);
                break;
            case 3:
                _paint.setColor(Color.RED);
                break;
            }
            canvas.drawCircle(point_temp.point.x, point_temp.point.y, 10,
                    _paint);
        }
    }

    private RectF _lastTapArea;
    private int _lastTapCount = 0;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            _tapCounter.resetCounter();
            float x = event.getX();
            float y = event.getY();

            if (_lastTapArea != null) {
                if (_lastTapArea.contains(x, y)) {
                    if (_lastTapCount < 3) {
                        _lastTapCount++;
                    } else {
                        addPoint(_lastTapArea.centerX(),
                                _lastTapArea.centerY(), _lastTapCount);
                        _lastTapCount = 1;
                    }
                } else {
                    addPoint(_lastTapArea.centerX(), _lastTapArea.centerY(),
                            _lastTapCount);
                    _lastTapCount = 1;
                    _lastTapArea = new RectF(x - RADIUS, y - RADIUS,
                            x + RADIUS, y + RADIUS);
                }
            } else {
                _lastTapCount = 1;
                _lastTapArea = new RectF(x - RADIUS, y - RADIUS, x + RADIUS, y
                        + RADIUS);
            }

            return true;
        }

        return false;
    }

    void addPoint(float x, float y, int tapCount) {
        _points.add(new CustomPoint(new PointF(x, y), tapCount));
        invalidate();
    }

    class TapCounter extends CountDownTimer {

        public TapCounter(long millisInFuture, long countDownInterval) {
            super(millisInFuture, countDownInterval);
        }

        @Override
        public void onFinish() {
            if (_lastTapArea != null) {
                if (_lastTapCount > 0)
                    addPoint(_lastTapArea.centerX(), _lastTapArea.centerY(),
                            _lastTapCount);

                _lastTapCount = 0;
                _lastTapArea = null;
            }
        }

        @Override
        public void onTick(long millisUntilFinished) {
        }

        public void resetCounter() {
            start();
        }
    }
}

关于android - 识别自定义 View 上的三次点击,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15861638/

相关文章:

javascript - 如何使用 HTML5 Canvas 和 Javascript 将 putImageData 与动画 gif 一起使用?

android - 完成后如何关闭 IME 数字小键盘?

android - 如果服务停止,后台线程会发生什么?

android - 如何使用 fastscroll 和 albhabet 索引器实现 ListView

android - 卡尔曼滤波器 - 指南针和陀螺仪

android - 如何在 View 中嵌入时间选择器

javascript - 添加另一个形状时,动力学 JS 形状阴影变得更加明显

java - 如何在 ImageView 中使用触摸获取实际图像坐标?

android - LinearLayout 中的 ConstraintLayout 不起作用

HTML5 Canvas 绘制图像问题