Android实现摇杆操作,获取到摇杆方向

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent">



    <ImageView
        android:id="@+id/joystick"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_gravity="center_horizontal|bottom"
        android:layout_marginBottom="50dp"
        android:background="@drawable/click_item"/>

</FrameLayout>
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="oval">
            <solid android:color="#66000000" />
        </shape>
    </item>
    <item>
        <shape android:shape="oval">
            <solid android:color="@android:color/transparent" />
            <stroke
                android:width="2dp"
                android:color="@android:color/black" />
        </shape>
    </item>

</layer-list>

首先是布局文件和控件的item(外圈黑色,内圈透明的灰色)

package com.example.moveclick;

public interface OnJoystickMoveListener {
    void onJoystickMove(String direction);

}

一个接口,负责监听控件的移动方向

package com.example.moveclick;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
import android.widget.ImageView;

public class MainActivity extends AppCompatActivity implements GestureDetector.OnGestureListener {

    private FrameLayout container;
    private ImageView joystick;
    private GestureDetector gestureDetector;
    private float centerX, centerY;
    private float lastX, lastY;
    private static final int RADIUS = 30;

    private OnJoystickMoveListener joystickMoveListener;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        container = findViewById(R.id.container);
        joystick = findViewById(R.id.joystick);
        gestureDetector = new GestureDetector(this, this);

        ViewTreeObserver viewTreeObserver = container.getViewTreeObserver();
        viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                container.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                centerX = container.getWidth() / 2f;
                centerY = container.getHeight() * 5/6f;
            }
        });

        joystickMoveListener = new OnJoystickMoveListener() {
            @Override
            public void onJoystickMove(String direction) {
                // 在这里实现接口方法,可以根据方向来做一些操作
                // 比如移动控件、播放动画、发送网络请求等
                // 这里只是简单地打印一下方向信息
                System.out.println("Joystick direction: " + direction);
            }
        };
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return gestureDetector.onTouchEvent(event);
    }

    @Override
    public boolean onDown(MotionEvent e) {
        lastX = e.getX();
        lastY = e.getY();
        return true;
    }

    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        float deltaX = e2.getX() - centerX;
        float deltaY = e2.getY() - centerY;
        float distance = (float) Math.sqrt(deltaX * deltaX + deltaY * deltaY);
        float angle = (float) Math.atan2(deltaY, deltaX);
        if (distance > RADIUS) {
            distance = RADIUS;
            deltaX = (float) (RADIUS * Math.cos(angle));
            deltaY = (float) (RADIUS * Math.sin(angle));
        }
        joystick.setX(centerX + deltaX - joystick.getWidth() / 2);
        joystick.setY(centerY + deltaY - joystick.getHeight() / 2);

        String direction = "";
        if (deltaY < -RADIUS/2) {
            direction = "up";
        } else if (deltaY > RADIUS/2) {
            direction = "down";
        } else if (deltaX < -RADIUS/2) {
            direction = "left";
        } else if (deltaX > RADIUS/2) {
            direction = "right";
        }

        joystickMoveListener.onJoystickMove(direction);
        return true;
    }

    @Override
    public void onLongPress(MotionEvent e) {
        // Do nothing
    }

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        // Do nothing
        return true;
    }

    @Override
    public void onShowPress(MotionEvent e) {
        // Do nothing
    }

    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        return true;
    }

}
//addOnGlobalLayoutListener()是ViewTreeObserver的一个方法,用于添加一个OnGlobalLayoutListener监听器来监听View的状态变化。
//
//当View的布局发生变化时,addOnGlobalLayoutListener()方法会在ViewTreeObserver的消息队列中添加一个消息,告知系统需要执行一个任务。这个任务就是在View的布局完成后回调OnGlobalLayoutListener的onGlobalLayout()方法,让开发者可以在其中获取View的尺寸、位置等信息,并进行相应的操作。
//
//添加OnGlobalLayoutListener后,当View的布局发生变化时,onGlobalLayout()方法会被调用。因此,我们可以在onGlobalLayout()方法中获取View的尺寸、位置等信息,以便在正确的时机对View进行操作。
//
//需要注意的是,当View的布局发生变化时,OnGlobalLayoutListener会被调用多次,因此在使用addOnGlobalLayoutListener()方法时,应该注意避免重复计算或重复操作。可以使用removeOnGlobalLayoutListener()方法来移除OnGlobalLayoutListener,避免重复回调。


//GestureDetector.OnGestureListener是Android中的一个接口,用于监听手势事件,如单击、双击、滑动、长按、快速滑动等。
//
//GestureDetector是一个用于监听手势事件的工具类,它可以通过GestureDetector.OnGestureListener接口来监听各种手势事件。当用户触发手势事件时,GestureDetector会回调对应的方法,以便开发者可以对事件做出响应。
//
//GestureDetector.OnGestureListener接口中定义了一些方法,包括:
//
//onDown(MotionEvent e):手指按下时触发的事件;
//onShowPress(MotionEvent e):手指按下后一段时间后触发的事件,例如长按;
//onSingleTapUp(MotionEvent e):手指轻轻点击屏幕后立刻抬起时触发的事件;
//onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY):手指在屏幕上滑动时触发的事件;
//onLongPress(MotionEvent e):手指长按屏幕时触发的事件;
//onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY):手指在屏幕上快速滑动时触发的事件。
//开发者可以实现GestureDetector.OnGestureListener接口,重写对应的方法,以便监听手势事件并进行相应的处理。使用GestureDetector可以使我们的应用程序更加易用和直观,提升用户体验。

简单的说一下,

1,获取中心点与控件xy的初始位置,中心点的位置通过分割帧布局计算出来

2,实现GestureDetector.OnGestureListener的所有方法,并且在onScroll方法中获取到移动方向并且传递到接口,由于明确的划定了移动范围无论手势如何延长,控件始终在规定的布局中

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值