超级简单的制作一个安卓游戏手柄轮盘控件

 效果就是这么个效果,话不多说直接开整。

首先是activity_main.xml布局文件

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipChildren="false"
    tools:context=".MainActivity">

    <LinearLayout
        android:id="@+id/background"
        android:background="@drawable/background"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:orientation="horizontal"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" >

        <ImageView
            android:id="@+id/center"
            android:layout_width="90dp"
            android:layout_height="90dp"
            android:background="@drawable/center"
            android:layout_marginTop="55dp"
            android:layout_marginLeft="55dp"/>

    </LinearLayout>

    <TextView
        android:id="@+id/info"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_marginTop="175dp"
        app:layout_constraintTop_toTopOf="parent"
        tools:ignore="MissingConstraints"
        tools:layout_editor_absoluteX="0dp"
        android:text="角度:0+距离:0"
        android:textSize="25sp"
        android:gravity="center"/>

</androidx.constraintlayout.widget.ConstraintLayout>

就有四点需要注意:

1.中间的轮盘要用ImageView,如果用ImageButton会干扰LinearLayout区域的触摸事件;

2.IamgeView要嵌套在LinearLayout子布局内,因为在子布局中不会读取父布局中的操作;

3.android:clipChildren="false"这个父布局属性设置为false可以让子布局的空间可以超出子布局显示,就是中间的黑色移动轮盘可以超出LinearLayout的空间显示;

4.把中间轮盘的位置调节到LinearLayout中间位置。

接下来是MainActivity.java的代码

全部代码:

package com.example.wheel;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    LinearLayout background=null;
    ImageView center=null;
    TextView info=null;
    private double centerPoint=300;//LinearLayout组件最中心坐标,X和Y都是300

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

        {//绑定组件id
            background=(LinearLayout) findViewById(R.id.background);
            center=(ImageView) findViewById(R.id.center);
            info=(TextView) findViewById(R.id.info);
        }

        {//LinearLayout子控件空间内的操作
            //LinearLayout的触屏事件:只需要:按下,抬起,移动三个事件
            background.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View view, MotionEvent motionEvent) {
                    //判断事件类型
                    switch (motionEvent.getAction()){
                        case MotionEvent.ACTION_DOWN://按下
                        case MotionEvent.ACTION_MOVE://移动
                            //数学问题,判断手指在一个圆形的区域内,范围半径是300,用圆形的特征公式
                            if((motionEvent.getX()-300)*(motionEvent.getX()-300)+(motionEvent.getY()-300)*(motionEvent.getY()-300)<=300*300){
                                //用ImageView的相对初始位置平移的方法,做ImageView这个中心轮盘的移动
                                center.setTranslationX(motionEvent.getX()-300);
                                center.setTranslationY(motionEvent.getY()-300);
                                //将角度和距离值赋值给TextView组件
                                info.setText("角度:"+String.valueOf((int)getAngle(motionEvent.getX(),motionEvent.getY()))
                                +"+"+"距离:"+String.valueOf((int)getDistance(motionEvent.getX(), motionEvent.getY())));
                            }
                            break;
                        case MotionEvent.ACTION_UP://抬起操作
                            //不要忘记,中心轮盘要归中
                            center.setTranslationX(0);
                            center.setTranslationY(0);
                            info.setText("角度:0+距离:0");
                            break;
                        default://其他操作,不做响应
                            break;
                    }
                    return true;//表示触摸事件已处理,则可以进行移动的响应
                }
            });
        }
    }
    //获得轮盘的角度
    private double getAngle(double X,double Y){
        double angle=0;
        //根据反三角函数来转化坐标成为角度,arctan()函数
        angle=Math.atan2(Y-centerPoint,X-centerPoint);//都是与中心坐标而言
        //上面是转化为弧度制,接下来转化为角度值
        angle=Math.toDegrees(angle);
        return angle;
    }
    //获得轮盘的移动距离
    private double getDistance(double X,double Y){
        double distance=0;
        //根据两点之间的坐标来得到距离值
        distance=Math.sqrt(Math.pow(X-centerPoint,2)+Math.pow(Y-centerPoint,2));
        return distance;
    }
}

我按照思路来解释:

1.控件的绑定,不多说,就三个控件:LinearLayout(子布局触摸事件用),ImageView(中间的移动轮盘图),TextView(显示轮盘角度和距离);

2.只需要设置LinearLayout的触摸事件就够了,获取点击的坐标,做中心轮盘的信息计算用的

background.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View view, MotionEvent motionEvent) {
                    switch (motionEvent.getAction()){
                        case MotionEvent.ACTION_DOWN://按下
                        case MotionEvent.ACTION_MOVE://移动
                            //这里做轮盘的计算操作

                            break;
                        case MotionEvent.ACTION_UP://抬起操作
                            //这里做轮盘的归中操作

                            break;
                        default:
                            break;
                     }
                 return true;//return true表示事件已处理并进入下一个操作,使得轮盘可以移动
             }
        });

那么怎么另中间的ImageView视图跟随手指移动呢?这就是轮盘视图的重点操作了,ImageView控件有两个奇妙的属性.setTeanslationX(float num)和.setTranslationY(float num),表示ImageView控件以初始位置在X或Y轴偏移num个坐标。

根据点击LinearLayout中的坐标做操作,当然直接将读取到的坐标直接赋值进去可不行,那样就不是在手指按下的位置显示ImageView,而是在手指按下位置加上初始坐标的位置显示了。那么知道是这样问题就解决了,先运行点击中心点看看坐标大概多少,可以用System.out.println(String.valueof(motionEvent.getX()+String.valueof(motionEvent.getY()))在logcat窗口查看,我这里是(300,300):

center.setTranslationX(motionEvent.getX()-300);
center.setTranslationY(motionEvent.getY()-300);

当然不要忘记做范围限制ImageView随手指移动的位置,这里用圆形的特征公式巧妙解决:

if((motionEvent.getX()-300)*(motionEvent.getX()-300)+(motionEvent.getY()-300)*(motionEvent.getY()-300)<=300*300){

}

好了现在就可以实现ImageView跟随手指移动了,代码是这样:

background.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View view, MotionEvent motionEvent) {
                    //判断事件类型
                    switch (motionEvent.getAction()){
                        case MotionEvent.ACTION_DOWN://按下
                        case MotionEvent.ACTION_MOVE://移动
                            //数学问题,判断手指在一个圆形的区域内,范围半径是300,用圆形的特征公式
                            if((motionEvent.getX()-300)*(motionEvent.getX()-300)+(motionEvent.getY()-300)*(motionEvent.getY()-300)<=300*300){
                                //用ImageView的相对初始位置平移的方法,做ImageView这个中心轮盘的移动
                                center.setTranslationX(motionEvent.getX()-300);
                                center.setTranslationY(motionEvent.getY()-300);
                            }
                            break;
                        case MotionEvent.ACTION_UP://抬起操作
                            //不要忘记,中心轮盘要归中
                            center.setTranslationX(0);
                            center.setTranslationY(0);
                            break;
                        default://其他操作,不做响应
                            break;
                    }
                    return true;//表示触摸事件已处理,则可以进行移动的响应
                }
            });

那么怎么获取轮盘的角度和距离这两个重要的信息呢?

这里我写了两个函数解决(注:centerPoint也就是中心点的坐标):

1.获得角度,根据两点坐标差值做反正切三角函数arctan(Y‘/X'):

//获得轮盘的角度
    private double getAngle(double X,double Y){
        double angle=0;
        //根据反三角函数来转化坐标成为角度,arctan()函数
        angle=Math.atan2(Y-centerPoint,X-centerPoint);//都是与中心坐标而言
        //上面是转化为弧度制,接下来转化为角度值
        angle=Math.toDegrees(angle);
        return angle;
    }

2.获得距离,根据两点之间的距离公式:开平方(Y'*Y'+X'*X'):

//获得轮盘的移动距离
    private double getDistance(double X,double Y){
        double distance=0;
        //根据两点之间的坐标来得到距离值
        distance=Math.sqrt(Math.pow(X-centerPoint,2)+Math.pow(Y-centerPoint,2));
        return distance;
    }

3.计算后在TextView中展示:

info.setText("角度:"+String.valueOf((int)getAngle(motionEvent.getX(),motionEvent.getY()))
                                +"+"+"距离:"+String.valueOf((int)getDistance(motionEvent.getX(), motionEvent.getY())));

完成了,最后LinearLayout中的触摸事件的全部代码就是:

background.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View view, MotionEvent motionEvent) {
                    //判断事件类型
                    switch (motionEvent.getAction()){
                        case MotionEvent.ACTION_DOWN://按下
                        case MotionEvent.ACTION_MOVE://移动
                            //数学问题,判断手指在一个圆形的区域内,范围半径是300,用圆形的特征公式
                            if((motionEvent.getX()-300)*(motionEvent.getX()-300)+(motionEvent.getY()-300)*(motionEvent.getY()-300)<=300*300){
                                //用ImageView的相对初始位置平移的方法,做ImageView这个中心轮盘的移动
                                center.setTranslationX(motionEvent.getX()-300);
                                center.setTranslationY(motionEvent.getY()-300);
                                //将角度和距离值赋值给TextView组件
                                info.setText("角度:"+String.valueOf((int)getAngle(motionEvent.getX(),motionEvent.getY()))
                                +"+"+"距离:"+String.valueOf((int)getDistance(motionEvent.getX(), motionEvent.getY())));
                            }
                            break;
                        case MotionEvent.ACTION_UP://抬起操作
                            //不要忘记,中心轮盘要归中
                            center.setTranslationX(0);
                            center.setTranslationY(0);
                            info.setText("角度:0+距离:0");
                            break;
                        default://其他操作,不做响应
                            break;
                    }
                    return true;//表示触摸事件已处理,则可以进行移动的响应
                }
            });

完成了,够简单吧。

如果您觉得不错,请多多为我点赞支持哦

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陶炆松

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值