PTZView - 自定义云台控件

效果图以及相关的两张图片资源:

PTZView - 自定义云台控件_第1张图片PTZView - 自定义云台控件_第2张图片PTZView - 自定义云台控件_第3张图片

实现步骤:

  1. 继承View
  2. 重写onTouchEvent,根据触摸坐标计算角度
  3. 重写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  * 

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 }

 【注】可以通过自定义属性传入图片,增强控件的自定义能力。自定义属性不在本文的讨论范围。

谢谢阅读,如有谬误,多谢指正。

你可能感兴趣的:(PTZView - 自定义云台控件)