Android实现自定义方向盘-4解决触摸时指针跳跃的问题

1、拖拽判断

为了解决点击指针时,指针跳转至反方向的问题,我们可以采取拖拽判断的方式,即只有当用户执行明显的拖拽动作时才更新方向盘的角度。这样可以避免单击或短距离移动时,指针突然跳转到反方向的问题。

实现思路

  1. 记录初始点击位置:当用户按下屏幕时,记录初始点击的坐标位置和当前指针角度。

  2. 判断拖拽距离:在用户拖动时,判断当前触摸点与初始触摸点的距离。如果距离超过一定阈值(表示用户确实在拖动而非点击),才开始更新指针的角度。

  3. 更新角度:在满足拖拽条件的情况下,更新指针的角度,使其指向当前触摸点的方向。

2、开始拖拽时,起始点设置为上一次指针所在位置

为了确保在开始拖拽时,指针能从当前位置开始而不是跳到触摸起始点,我们需要将当前指针的位置设置为拖拽的起始参考点。具体来说,我们在检测到用户开始拖拽时,计算相对于当前指针角度的偏移量,这样拖拽过程会以当前指针的位置为基准。

调整后的实现思路

  1. 记录初始角度偏移:在拖拽开始时(ACTION_DOWN),计算触摸点与当前指针的角度偏移量,并在后续拖拽中使用这个偏移量来计算新的角度。

  2. 在拖拽过程中应用偏移:在ACTION_MOVE中计算新角度时,将初始的偏移量加到计算结果中,确保指针从当前位置开始旋转。

3、调整后的完整代码

package com.example.gamecontrol;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

public class SteeringWheelView extends View {
    private Paint paint;
    private float centerX, centerY, radius;
    private float currentAngle = 0;
    private OnSteeringWheelChangeListener listener;
    
    private static final float MIN_DRAG_DISTANCE = 20f; // 最小拖拽距离阈值

    private float startX, startY;
    private boolean isDragging = false;
    private float initialAngleOffset = 0f;

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

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

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

    private void init() {
        paint = new Paint();
        paint.setColor(Color.GRAY);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(10);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        centerX = getWidth() / 2;
        centerY = getHeight() / 2;
        radius = Math.min(centerX, centerY) - 20;
        canvas.drawCircle(centerX, centerY, radius, paint);

        // 画一个指示方向的线
        float indicatorX = (float) (centerX + radius * Math.cos(Math.toRadians(currentAngle)));
        float indicatorY = (float) (centerY + radius * Math.sin(Math.toRadians(currentAngle)));
        paint.setColor(Color.RED);
        canvas.drawLine(centerX, centerY, indicatorX, indicatorY, paint);
        paint.setColor(Color.GRAY); // 恢复颜色
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                // 记录初始点击位置和状态
                startX = x;
                startY = y;
                isDragging = false;

                // 计算触摸点与当前指针的角度偏移量
                initialAngleOffset = calculateAngle(x, y) - currentAngle;
                break;

            case MotionEvent.ACTION_MOVE:
                // 计算拖拽距离
                float deltaX = x - startX;
                float deltaY = y - startY;
                float distance = (float) Math.sqrt(deltaX * deltaX + deltaY * deltaY);

                if (distance > MIN_DRAG_DISTANCE) {
                    isDragging = true;

                    // 计算当前触摸点的角度,并应用初始偏移量
                    float angle = calculateAngle(x, y) - initialAngleOffset;

                    // 更新方向盘角度
                    updateSteeringWheelAngle(angle);
                }
                break;

            case MotionEvent.ACTION_UP:
                // 在拖拽状态下结束触摸
                if (isDragging) {
                    // 可以在这里执行松手后的操作,例如回弹效果等
                }
                isDragging = false;
                break;
        }
        return true;
    }

    private float calculateAngle(float x, float y) {
        float angle = (float) Math.toDegrees(Math.atan2(centerY - y, centerX - x));
        if (angle < 0) angle += 360;
        return angle;
    }

    public void updateSteeringWheelAngle(float angle) {
        currentAngle = angle % 360;
        if (currentAngle < 0) currentAngle += 360;

        if (listener != null) {
            listener.onSteeringWheelChanged(currentAngle);
        }
        invalidate();
    }

    public float getCurrentAngle() {
        return currentAngle;
    }

    public void setOnSteeringWheelChangeListener(OnSteeringWheelChangeListener listener) {
        this.listener = listener;
    }

    public interface OnSteeringWheelChangeListener {
        void onSteeringWheelChanged(float angle);
    }
}

4、触摸时指针跳跃问题

代码解读

  1. MIN_DRAG_DISTANCE:定义了最小的拖拽距离(MIN_DRAG_DISTANCE),只有当用户的拖动距离超过该阈值时,才认为是有效的拖动,并更新指针角度。

  2. isDragging:这是一个标志变量,用来判断用户是否正在拖动方向盘。在ACTION_MOVE中,如果检测到拖动距离超过了阈值,则将isDragging设置为true,并更新指针角度。

  3. ACTION_UP:在用户松开手指时,检查是否是有效的拖动操作,并根据需要执行后续操作(如指针回弹到某个位置等)。

优势与效果

  • 防止跳跃:这种方法有效防止了轻触或者短距离移动时指针突然跳跃至反方向的情况。
  • 用户体验提升:通过判断拖拽距离,仅在用户进行明显拖动操作时才更新指针的角度,使得用户体验更加流畅和自然。

通过以上实现,指针的移动将会更加平滑,且能避免误触导致的反方向跳转问题。

5、 起始点问题

  1. initialAngleOffset:在用户按下(ACTION_DOWN)时,计算触摸点的角度与当前指针角度之间的偏移量。这个偏移量在后续的拖拽过程中保持不变,确保拖拽时指针从当前位置开始旋转。

  2. calculateAngle:一个辅助方法,用于计算某个点相对于中心的角度。这个方法在拖拽过程中多次调用,用于实时计算新的指针角度。

  3. onTouchEvent 调整:在ACTION_DOWN时,计算初始的角度偏移量。在ACTION_MOVE时,通过初始偏移量调整指针的角度,避免直接跳转到触摸点的方向。

效果

通过这种方式,指针在用户拖动时将始终从当前位置开始旋转,而不会突然跳到触摸起始点对应的方向。这样用户在拖动指针时,操作会更加自然,指针的运动轨迹也会更加平滑。
相关文章:
链接: Android实现自定义方向盘
链接: Android实现自定义方向盘-2添加陀螺仪
链接: Android实现自定义方向盘-3添加平滑处理
链接: Android实现自定义方向盘-4解决触摸时指针跳跃的问题
链接: Android实现自定义方向盘-5livedata实现
链接: Android实现自定义方向盘-6mvvm传递数据
链接: Android实现自定义方向盘-7livedata,viewmodel相关问题
链接: Android实现自定义方向盘-8自定义view的相关问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值