答案 0 :(得分:2)
我建议你可以使用Wheel Menu
<com.anupcowkur.wheelmenu.WheelMenu
android:id="@+id/wheelMenu"
android:layout_width="300dp"
android:layout_height="300dp" />
https://github.com/anupcowkur/Android-Wheel-Menu
https://github.com/LukeDeighton/WheelView
答案 1 :(得分:1)
我需要由用户旋转此拨号器,这是它的代码。该代码受link的启发,在阅读我的代码之前,您可以阅读那里的说明。
currentAngle 是用于监视已旋转的总角度拨号器的变量。因此,每旋转360度,它将旋转360度,因此角度始终在0-360度之间。您可以在 rotateDialer 功能中进行检查。在 onSingleTapConfirmed 函数中,我们发送点击坐标(即x和y),然后将其更改为保存在 clickedAngle 中的角度。拨号程序有8个部分,以45度角分开。拨号器的每个部分都有定义的角度范围。因此它将从每个角度范围(即0-45,0-90..etc)中减去currentAngle,从而实时更改每个截面范围。 例如,让拨号程序的当前角度在+方向上为20度,因此第一部分的角度范围现在更改为(0-20)至(45-20),即-20至25度
import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.support.constraint.ConstraintLayout;
import android.support.constraint.Guideline;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
public class MainActivityNew extends AppCompatActivity {
private static Bitmap imageOriginal, imageScaled;
private static Matrix matrix;
private ImageView dialer;
private int dialerHeight, dialerWidth;
private GestureDetector detector;
// needed for detecting the inversed rotations
private boolean[] quadrantTouched;
private boolean allowRotating;
ImageView menu_circle;
Guideline menuWheelGuidline;
float currentAngle; //The current angle of the dialer
double clickedAngle; //The angle which user has clicked
@SuppressLint("ClickableViewAccessibility")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_new);
setUpMenuWheel();
// load the image only once
if (imageOriginal == null) {
imageOriginal = BitmapFactory.decodeResource(getResources(), R.drawable.menu_wheel);
}
// initialize the matrix only once
if (matrix == null) {
matrix = new Matrix();
} else {
// not needed, you can also post the matrix immediately to restore the old state
matrix.reset();
}
detector = new GestureDetector(this, new MyGestureDetector());
// there is no 0th quadrant, to keep it simple the first value gets ignored
quadrantTouched = new boolean[] { false, false, false, false, false };
allowRotating = true;
dialer = findViewById(R.id.menu_wheel);
dialer.setOnTouchListener(new MyOnTouchListener());
dialer.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
// method called more than once, but the values only need to be initialized one time
if (dialerHeight == 0 || dialerWidth == 0) {
dialerHeight = dialer.getHeight();
dialerWidth = dialer.getWidth();
// resize
Matrix resize = new Matrix();
resize.postScale((float)Math.min(dialerWidth, dialerHeight) / (float)imageOriginal.getWidth(), (float)Math.min(dialerWidth, dialerHeight) / (float)imageOriginal.getHeight());
imageScaled = Bitmap.createBitmap(imageOriginal, 0, 0, imageOriginal.getWidth(), imageOriginal.getHeight(), resize, false);
// translate to the image view's center
float translateX = dialerWidth / 2 - imageScaled.getWidth() / 2;
float translateY = dialerHeight / 2 - imageScaled.getHeight() / 2;
matrix.postTranslate(translateX, translateY);
dialer.setImageBitmap(imageScaled);
dialer.setImageMatrix(matrix);
}
}
});
}
/**
* Rotate the dialer.
*
* @param degrees The degrees, the dialer should get rotated.
*/
private void rotateDialer(float degrees) {
if(Math.abs(currentAngle)/360>1){
if(currentAngle>0){
currentAngle =currentAngle-360+degrees;
}else{
currentAngle +=360+degrees;
}
}else{
currentAngle=currentAngle+degrees;
}
matrix.postRotate(degrees, dialerWidth / 2, dialerHeight / 2);
dialer.setImageMatrix(matrix);
Log.d("Angle Sum",""+currentAngle);
}
/**
* @return The angle of the unit circle with the image view's center
*/
private double getAngle(double xTouch, double yTouch) {
double x = xTouch - (dialerWidth / 2d);
double y = dialerHeight - yTouch - (dialerHeight / 2d);
switch (getQuadrant(x, y)) {
case 1:
return Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI;
case 2:
case 3:
return 180 - (Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI);
case 4:
return 360 + Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI;
default:
return 0;// ignore, does not happen
}
}
/**
* @return The selected quadrant.
*/
private static int getQuadrant(double x, double y) {
if (x >= 0) {
return y >= 0 ? 1 : 4;
} else {
return y >= 0 ? 2 : 3;
}
}
/**
* Simple implementation of an {@link View.OnTouchListener} for registering the dialer's touch events.
*/
private class MyOnTouchListener implements View.OnTouchListener {
private double startAngle;
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// reset the touched quadrants
for (int i = 0; i < quadrantTouched.length; i++) {
quadrantTouched[i] = false;
}
allowRotating = false;
startAngle = getAngle(event.getX(), event.getY());
break;
case MotionEvent.ACTION_MOVE:
double currentAngle = getAngle(event.getX(), event.getY());
rotateDialer((float) (startAngle - currentAngle));
startAngle = currentAngle;
break;
case MotionEvent.ACTION_UP:
allowRotating = true;
break;
}
// set the touched quadrant to true
quadrantTouched[getQuadrant(event.getX() - (dialerWidth / 2), dialerHeight - event.getY() - (dialerHeight / 2))] = true;
detector.onTouchEvent(event);
return true;
}
}
/**
* Simple implementation of a {@link GestureDetector.SimpleOnGestureListener} for detecting a fling event.
*/
private class MyGestureDetector extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
iconClicked(e.getX(),e.getY());
return super.onSingleTapConfirmed(e);
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
// get the quadrant of the start and the end of the fling
int q1 = getQuadrant(e1.getX() - (dialerWidth / 2), dialerHeight - e1.getY() - (dialerHeight / 2));
int q2 = getQuadrant(e2.getX() - (dialerWidth / 2), dialerHeight - e2.getY() - (dialerHeight / 2));
// the inversed rotations
if ((q1 == 2 && q2 == 2 && Math.abs(velocityX) < Math.abs(velocityY))
|| (q1 == 3 && q2 == 3)
|| (q1 == 1 && q2 == 3)
|| (q1 == 4 && q2 == 4 && Math.abs(velocityX) > Math.abs(velocityY))
|| ((q1 == 2 && q2 == 3) || (q1 == 3 && q2 == 2))
|| ((q1 == 3 && q2 == 4) || (q1 == 4 && q2 == 3))
|| (q1 == 2 && q2 == 4 && quadrantTouched[3])
|| (q1 == 4 && q2 == 2 && quadrantTouched[3])) {
dialer.post(new FlingRunnable(-1 * (velocityX + velocityY)));
} else {
// the normal rotation
dialer.post(new FlingRunnable(velocityX + velocityY));
}
return true;
}
}
/**
* A {@link Runnable} for animating the the dialer's fling.
*/
private class FlingRunnable implements Runnable {
private float velocity;
float totalAngle;
public FlingRunnable(float velocity) {
this.velocity = velocity;
}
@Override
public void run() {
if (Math.abs(velocity) > 5 && allowRotating) {
rotateDialer(velocity / 75);
totalAngle=totalAngle+velocity/75;
velocity /= 1.0666F;
// post this instance again
dialer.post(this);
}
}
}
//To position the menu wheel
public void setUpMenuWheel(){
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int width = displayMetrics.widthPixels;
int height = displayMetrics.heightPixels;
menu_circle = findViewById(R.id.menu_wheel);
menu_circle.getLayoutParams().height=width;
menuWheelGuidline = findViewById(R.id.menuWheelGuidline);
ConstraintLayout.LayoutParams lp = (ConstraintLayout.LayoutParams) menuWheelGuidline.getLayoutParams();
lp.guideBegin = height-(width/2);
menuWheelGuidline.setLayoutParams(lp);
}
public void iconClicked(double x,double y){
clickedAngle=getAngle(x,y);
Log.d("Clicked angle",""+(getAngle(x,y)));
if(clickedAngle>0-currentAngle && clickedAngle<45-currentAngle){
Log.e("Icon 1","Clicked");
}if(clickedAngle>45-currentAngle && clickedAngle<90-currentAngle){
Log.e("Icon 2","Clicked");
}if(clickedAngle>90-currentAngle && clickedAngle<135-currentAngle){
Log.e("Icon 3","Clicked");
}if(clickedAngle>135-currentAngle && clickedAngle<180-currentAngle){
Log.e("Icon 4","Clicked");
}if(clickedAngle>180-currentAngle && clickedAngle<225-currentAngle){
Log.e("Icon 5","Clicked");
}if(clickedAngle>225-currentAngle && clickedAngle<270-currentAngle){
Log.e("Icon 6","Clicked");
}if(clickedAngle>270-currentAngle && clickedAngle<315-currentAngle){
Log.e("Icon 7","Clicked");
}if(clickedAngle>315-currentAngle && clickedAngle<359-currentAngle){
Log.e("Icon 8","Clicked");
}
}
}