在View中进行重绘,主要是通过计算角度及距离来实现。实现类代码如下:
package com.example.roatedemo; import java.util.Calendar; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.util.Log; import android.view.MotionEvent; import android.view.View; public class RotateView extends View { private Paint mPaint = new Paint(); private Bitmap bitmaplittele;//中间不动的图片 private Bitmap bitmapBig;//随手指转动的图片 private Bitmap bitmapOut;//外围不动的图片 // 圆心坐标 private float mPointX = 0, mPointY = 0; private int flag = 0; // 半径 private int mRadius = 0; // 旋转角度 private int mAngle = 0; private int beginAngle = 0, currentAngle = 0; private String TAG = "NewView"; int bitMap[] = { R.drawable.circle0, R.drawable.circle1, R.drawable.circle2 }; int imageIndex = 0; boolean isUp = false,isTouch=false; Context mContext; RotateViewListener listener; long beginTime,endTime; Calendar now; public RotateView(Context context, int px, int py, int radius,RotateViewListener listener) { super(context); mContext = context; this.listener = listener; mPointX = px; mPointY = py; mRadius = radius; bitmaplittele = BitmapFactory.decodeResource(getResources(), R.drawable.a1_pointer).copy(Bitmap.Config.ARGB_8888, true); bitmapBig = BitmapFactory.decodeResource(getResources(), bitMap[0]) .copy(Bitmap.Config.ARGB_8888, true); bitmapOut = BitmapFactory.decodeResource(getResources(), R.drawable.bigcir).copy(Bitmap.Config.ARGB_8888, true); setBackgroundResource(R.drawable.back); Log.e(TAG, "RotateViewBegin"); } @Override public boolean dispatchTouchEvent(MotionEvent e) { switch (e.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: now = Calendar.getInstance(); beginTime = now.getTimeInMillis(); beginAngle = computeCurrentAngle(e.getX(), e.getY()); isUp = false; //如果点击触摸范围在圈外,则不处理 if (getDistance(e.getX(), e.getY())>bitmapOut.getWidth()/2) { isTouch=false; }else { isTouch=true; } return true; case MotionEvent.ACTION_MOVE: if (!isTouch) { return true; } currentAngle = computeCurrentAngle(e.getX(), e.getY()); invalidate(); return true; case MotionEvent.ACTION_UP: isUp = true; if (!isTouch) { return true; } now = Calendar.getInstance(); endTime = now.getTimeInMillis(); if (SetClick(e.getX(), e.getY())) { return true; } if (mAngle > 0) { int count = mAngle / 120 + (mAngle % 120 > 60 ? 1 : 0); imageIndex = (imageIndex + count) % 3; } else if (mAngle < 0) { mAngle = -mAngle; int count = mAngle / 120 + (mAngle % 120 > 60 ? 1 : 0); imageIndex = (imageIndex + 3 - count) % 3; } bitmapBig = BitmapFactory.decodeResource(getResources(), bitMap[imageIndex]).copy(Bitmap.Config.ARGB_8888, true); bitmapBig = adjustPhotoRotation(bitmapBig, imageIndex * 120); invalidate(); if (mAngle >= 60) { listener.onModChange(imageIndex); } return true; } return false; } @Override public void onDraw(Canvas canvas) { // Log.i(TAG, "onDraw"); // 大圆 drawInCenter(canvas, bitmapOut, mPointX, mPointY, TAG); // 外圈 if (isUp) { mAngle = 0; } else { mAngle = currentAngle - beginAngle; } Bitmap tempBig = adjustPhotoRotation(bitmapBig, mAngle); // Log.i(TAG, "mAngle:"+mAngle); drawInCenter(canvas, tempBig, mPointX, mPointY + 10, TAG); // 小圆(中间的圆心) drawInCenter(canvas, bitmaplittele, mPointX, mPointY - 10, TAG); } Bitmap adjustPhotoRotation(Bitmap bm, final int orientationDegree) { if (orientationDegree == 0) { return bm; } Matrix m = new Matrix(); m.setRotate(orientationDegree, (float) bm.getWidth() / 2, (float) bm.getHeight() / 2); try { Bitmap bm1 = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), m, true); return bm1; } catch (OutOfMemoryError ex) { } return null; } private void drawInCenter(Canvas canvas, Bitmap bitmap, float left, float top, String text) { canvas.drawBitmap(bitmap, left - bitmap.getWidth() / 2, top - bitmap.getHeight() / 2, null); } // 子控件位置改变重新计算角度 private int computeCurrentAngle(float x, float y) { // 根据圆心坐标计算角度 float distance = (float) Math .sqrt(((x - mPointX) * (x - mPointX) + (y - mPointY) * (y - mPointY))); int degree = (int) (Math.acos((x - mPointX) / distance) * 180 / Math.PI); if (y < mPointY) { degree = -degree; } if (degree < 0) { degree += 360; } // Log.i("RoundSpinView", "x:" + x + ",y:" + y + ",degree:" + degree); return degree; } // 获取距离圆心的距离 private float getDistance(float x, float y) { // 根据圆心坐标计算角度 float distance = (float) Math .sqrt(((x - mPointX) * (x - mPointX) + (y - mPointY) * (y - mPointY))); return distance; } //点击 private boolean SetClick(float x, float y) { float distance = getDistance(x, y); if (mAngle>10||mAngle<-10) { return false; }else if(endTime-beginTime>1000){ return false; } if (distance < bitmapBig.getWidth() / 2) { int mod = 0; if (beginAngle < 90 || 330 < beginAngle) { mod = (imageIndex+3-1)%3; } else if (90 < beginAngle && 210 > beginAngle) { mod = (imageIndex+3-2)%3; } else{ mod = imageIndex; } //回调到主界面进行处理。 listener.onModClick(mod); } return true; } public interface RotateViewListener { void onModClick(int mode); void onModChange(int mode); } }
package com.example.roatedemo; import com.example.roatedemo.RotateView.RotateViewListener; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.util.DisplayMetrics; import android.util.Log; import android.widget.Toast; public class MainActivity extends Activity implements RotateViewListener{ RotateView rotateView; String TAG="MainActivity"; Context mContext; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mContext = this; int height,width; DisplayMetrics displayMetrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); height = displayMetrics.heightPixels; width = displayMetrics.widthPixels; Log.i(TAG, "height:"+height); Log.i(TAG, "width:"+width); rotateView = new RotateView(getApplicationContext(), width/2, height/3, 150,this); setContentView(rotateView); } @Override public void onModClick(int mode) { String[] clickStrings = new String[] { "1被点击", "2被点击","3被点击" }; Toast.makeText(mContext, clickStrings[mode], 0).show(); } @Override public void onModChange(int mode) { String[] clickStrings = new String[] { "切换到1", "切换到2","切换到3" }; Toast.makeText(mContext, clickStrings[mode], 0).show(); } }
除了实现图片旋转,还实现将图片切成3部分,每部分120度,每转动120度切换一个模式,点击每个部分均有响应事件回调到主界面。涉及保密,图片不给在此给出。