2020年6月10日星期三

PTZView

PTZView


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

实现步骤:

  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  * <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 }

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

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


没有评论:

发表评论