PTZView
效果图以及相关的两张图片资源:
实现步骤:
- 继承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 }
【注】可以通过自定义属性传入图片,增强控件的自定义能力。自定义属性不在本文的讨论范围。
谢谢阅读,如有谬误,多谢指正。
没有评论:
发表评论