效果圖以及相關的兩張圖片資源: 實現步驟: 繼承View 重寫onTouchEvent,根據觸摸坐標計算角度 重寫onDraw,根據角度旋轉並繪製圖片 代碼如下: 1 import android.annotation.SuppressLint; 2 import android.content.C ...
效果圖以及相關的兩張圖片資源:
實現步驟:
- 繼承View
- 重寫onTouchEvent,根據觸摸坐標計算角度
- 重寫onDraw,根據角度旋轉並繪製圖片
代碼如下:
1 import android.annotation.SuppressLint; 2 import android.content.Context; 3 import android.content.res.Resources; 4 import android.graphics.Bitmap; 5 import android.graphics.BitmapFactory; 6 import android.graphics.Canvas; 7 import android.graphics.Matrix; 8 import android.graphics.Paint; 9 import android.util.AttributeSet; 10 import android.view.MotionEvent; 11 import android.view.View; 12 13 import androidx.annotation.IntDef; 14 15 /** 16 * 自定義雲台控制項 17 * <p>2020-06-02: create by zenghm 18 */ 19 public class PTZView extends View { 20 21 public static final int NONE = 0; 22 public static final int TOP = 1; 23 public static final int BOTTOM = 2; 24 public static final int LEFT = 3; 25 public static final int RIGHT = 4; 26 27 @IntDef({NONE, LEFT, TOP, RIGHT, BOTTOM}) 28 public @interface Direction { 29 } 30 31 public interface DirectionChangedListener { 32 /** 33 * 方向變化回調 34 * 35 * @param oldDirection 之前的方向 36 * @param curDirection 當前的方向 37 */ 38 void onDirectionChanged(PTZView view, @Direction int oldDirection, @Direction int curDirection); 39 } 40 41 private DirectionChangedListener mListener; 42 @Direction 43 private int mDirection = NONE; 44 private float mCenterX, mCenterY; 45 private float mAngel = 0; 46 47 private Bitmap mDefaultBitmap; 48 private Bitmap mPressBitmap; 49 private Matrix mMatrix = new Matrix(); 50 private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 51 52 public PTZView(Context context) { 53 this(context, null, 0); 54 } 55 56 public PTZView(Context context, AttributeSet attrs) { 57 this(context, attrs, 0); 58 } 59 60 public PTZView(Context context, AttributeSet attrs, int defStyle) { 61 super(context, attrs, defStyle); 62 // 載入資源 63 Resources res = context.getResources(); 64 mDefaultBitmap = BitmapFactory.decodeResource(res, R.drawable.ptz_default); 65 mPressBitmap = BitmapFactory.decodeResource(res, R.drawable.ptz_press); 66 } 67 68 public void setOnDirectionChangedListener(DirectionChangedListener listener) { 69 mListener = listener; 70 } 71 72 @Override 73 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 74 super.onSizeChanged(w, h, oldw, oldh); 75 mCenterX = (float) w / 2; 76 mCenterY = (float) h / 2; 77 } 78 79 @Override 80 protected void onDraw(Canvas canvas) { 81 super.onDraw(canvas); 82 Bitmap bitmap = isPressed() ? mPressBitmap : mDefaultBitmap; 83 // 計算圖片縮放 84 float sx = (float) getWidth() / bitmap.getWidth(); 85 float sy = (float) getHeight() / bitmap.getHeight(); 86 // 設置變換矩陣(縮放、旋轉) 87 mMatrix.reset(); 88 mMatrix.postScale(sx, sy); 89 mMatrix.postRotate(-mAngel, mCenterX, mCenterY); 90 // 繪製圖片 91 canvas.drawBitmap(bitmap, mMatrix, mPaint); 92 } 93 94 @SuppressLint("ClickableViewAccessibility") 95 @Override 96 public boolean onTouchEvent(MotionEvent event) { 97 //super.onTouchEvent(event); 98 if (!isEnabled()) 99 return false; 100 101 switch (event.getAction()) { 102 case MotionEvent.ACTION_DOWN: 103 setPressed(true); 104 postInvalidate(); 105 break; 106 107 case MotionEvent.ACTION_UP: 108 case MotionEvent.ACTION_CANCEL: 109 if (mListener != null) { 110 mListener.onDirectionChanged(this, mDirection, NONE); 111 } 112 mDirection = NONE; 113 mAngel = 0; 114 setPressed(false); 115 postInvalidate(); 116 break; 117 118 case MotionEvent.ACTION_MOVE: 119 // 計算角度 120 float x = event.getX() - mCenterX; 121 float y = mCenterY - event.getY(); 122 mAngel = (float) (Math.atan2(y, x) / Math.PI * 180); 123 // 重新繪製 124 postInvalidate(); 125 // 根據角度判斷方向 126 int direction; 127 if (mAngel > -45 && mAngel <= 45) { 128 direction = LEFT; 129 } else if (mAngel > 45 && mAngel <= 135) { 130 direction = TOP; 131 } else if (mAngel <= -45 && mAngel > -135) { 132 direction = BOTTOM; 133 } else { 134 direction = RIGHT; 135 } 136 // 回調方向變化 137 if (mListener != null && mDirection != direction) { 138 mListener.onDirectionChanged(this, mDirection, direction); 139 } 140 mDirection = direction; 141 break; 142 143 default: 144 break; 145 } 146 return true; 147 } 148 }
【註】可以通過自定義屬性傳入圖片,增強控制項的自定義能力。自定義屬性不在本文的討論範圍。
謝謝閱讀,如有謬誤,多謝指正。