效果就是这么个效果,话不多说直接开整。
首先是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;//表示触摸事件已处理,则可以进行移动的响应
}
});
完成了,够简单吧。
如果您觉得不错,请多多为我点赞支持哦