package com.lechange.demo.view;
|
|
import android.annotation.SuppressLint;
|
import android.content.Context;
|
import android.content.res.TypedArray;
|
import android.graphics.Bitmap;
|
import android.graphics.BitmapFactory;
|
import android.graphics.Canvas;
|
import android.graphics.Color;
|
import android.graphics.Paint;
|
import android.graphics.PaintFlagsDrawFilter;
|
import android.graphics.Point;
|
import android.graphics.Rect;
|
import android.graphics.RectF;
|
import android.util.AttributeSet;
|
import android.view.MotionEvent;
|
import android.view.View;
|
|
import com.lechange.demo.R;
|
|
|
/**
|
* 云台控制面板
|
*/
|
@SuppressLint("DrawAllocation")
|
public class LcCloudRudderView extends View {
|
private Point mRockerPosition;
|
private final Point mCtrlPoint = new Point(100, 100);
|
private float mSolidRudderRadius = 60;
|
private float mChangeRudderRadius = 60;
|
private int mWheelRadius = 100;
|
private RudderListener listener = null;
|
private int mDownState;
|
private int firstX, firstY;
|
private int dCtrlPointx, dCtrlPointy;
|
private static Bitmap mBigCircleBg;
|
private static Bitmap mBigCircleBg_h;
|
private static Bitmap mSmallCircleBg;
|
private static Bitmap mBigCircleLandScapeBg;
|
private static Bitmap mBigCircleLandScapeBg_h;
|
private static Bitmap mSmallCircleLandScapeBg;
|
private float mAngle;
|
private boolean mShowDirectPic;
|
private boolean mCanTouch = true;
|
private boolean mLandScapeOnly = false;
|
//支持四方向
|
private boolean mSupportFourDirection=true;
|
|
|
public LcCloudRudderView(Context context) {
|
super(context);
|
init();
|
}
|
|
public LcCloudRudderView(Context context, AttributeSet attrs) {
|
super(context, attrs);
|
setAttribute(context, attrs);
|
init();
|
}
|
|
private void setAttribute(Context context, AttributeSet attrs) {
|
if (attrs != null) {
|
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.LcCloudRudderView);
|
mLandScapeOnly = array.getBoolean(R.styleable.LcCloudRudderView_landscape_only, false);
|
array.recycle();
|
}
|
}
|
|
private void init() {
|
setBackgroundColor(Color.TRANSPARENT);
|
this.setKeepScreenOn(true);
|
mCanTouch = true;
|
Paint mPaint = new Paint();
|
mPaint.setColor(Color.GREEN);
|
mPaint.setAntiAlias(true);
|
mRockerPosition = new Point(mCtrlPoint);
|
setFocusable(true);
|
setFocusableInTouchMode(true);
|
|
if (mBigCircleBg == null) {
|
mBigCircleBg = BitmapFactory.decodeResource(getResources(), R.mipmap.play_module_cloudstage_direction_default);
|
}
|
|
if (mBigCircleBg_h == null) {
|
mBigCircleBg_h = BitmapFactory.decodeResource(getResources(), R.mipmap.play_module_cloudstage_direction_up);
|
}
|
|
if (mSmallCircleBg == null) {
|
mSmallCircleBg = BitmapFactory.decodeResource(getResources(), R.mipmap.play_module_cloudstage_direction_button);
|
}
|
if (mBigCircleLandScapeBg == null) {
|
mBigCircleLandScapeBg = BitmapFactory.decodeResource(getResources(), R.mipmap.play_module_video_cloudstage_direction_default);
|
}
|
|
if (mBigCircleLandScapeBg_h == null) {
|
mBigCircleLandScapeBg_h = BitmapFactory.decodeResource(getResources(), R.mipmap.play_module_video_cloudstage_direction_up);
|
}
|
|
if (mSmallCircleLandScapeBg == null) {
|
mSmallCircleLandScapeBg = BitmapFactory.decodeResource(getResources(), R.mipmap.play_module_video_cloudstage_direction_button);
|
}
|
mSolidRudderRadius = (float) (mSmallCircleBg.getHeight() / 2.0);
|
}
|
|
/**
|
* 重置云台背景图,为了区分4方向和8方向
|
*/
|
public void resetCircleBg() {
|
if (mSupportFourDirection) {
|
if (mBigCircleBg != null) {
|
mBigCircleBg.recycle();
|
mBigCircleBg = BitmapFactory.decodeResource(getResources(), R.mipmap.play_module_cloudstage_direction_default_four);
|
}
|
if (mBigCircleLandScapeBg != null) {
|
mBigCircleLandScapeBg.recycle();
|
mBigCircleLandScapeBg = BitmapFactory.decodeResource(getResources(), R.mipmap.play_module_video_cloudstage_direction_default_four);
|
}
|
} else {
|
if (mBigCircleBg != null) {
|
mBigCircleBg.recycle();
|
mBigCircleBg = BitmapFactory.decodeResource(getResources(), R.mipmap.play_module_cloudstage_direction_default);
|
}
|
if (mBigCircleLandScapeBg != null) {
|
mBigCircleLandScapeBg.recycle();
|
mBigCircleLandScapeBg = BitmapFactory.decodeResource(getResources(), R.mipmap.play_module_video_cloudstage_direction_default);
|
}
|
}
|
invalidate();
|
}
|
|
|
@Override
|
protected void onDraw(Canvas canvas) {
|
super.onDraw(canvas);
|
Bitmap bigCirclebg = mLandScapeOnly ? mBigCircleLandScapeBg : mBigCircleBg;
|
if (bigCirclebg == null || bigCirclebg.isRecycled()) {
|
return;
|
}
|
|
try {
|
canvas.save();
|
canvas.translate(mCtrlPoint.x, mCtrlPoint.y);
|
canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG));
|
|
Paint paint = new Paint();
|
paint.setAntiAlias(true);
|
Rect srcRect = new Rect(0, 0, bigCirclebg.getWidth(), bigCirclebg.getHeight());
|
RectF dstRcctF = new RectF(-mWheelRadius, -mWheelRadius, mWheelRadius, mWheelRadius);
|
canvas.drawBitmap(bigCirclebg, srcRect, dstRcctF, paint);
|
canvas.restore();
|
|
if (mShowDirectPic) {
|
|
Bitmap bigCircleBg_h = mLandScapeOnly ? mBigCircleLandScapeBg_h : mBigCircleBg_h;
|
canvas.save();
|
canvas.translate(mCtrlPoint.x, mCtrlPoint.y);
|
canvas.rotate(mAngle);
|
Rect srcRect2 = new Rect(0, 0, bigCircleBg_h.getWidth(), bigCircleBg_h.getHeight());
|
RectF dstRcctF2 = new RectF(-mWheelRadius, -mWheelRadius, mWheelRadius, mWheelRadius);
|
canvas.drawBitmap(bigCircleBg_h, srcRect2, dstRcctF2, paint);
|
canvas.restore();
|
}
|
|
Bitmap smallCircleBg = mLandScapeOnly ? mSmallCircleLandScapeBg : mSmallCircleBg;
|
Rect srcRect3 = new Rect(0, 0, smallCircleBg.getWidth(), smallCircleBg.getHeight());
|
RectF dstRcctF3 = new RectF(mRockerPosition.x - mChangeRudderRadius, mRockerPosition.y - mChangeRudderRadius, mRockerPosition.x + mChangeRudderRadius, mRockerPosition.y + mChangeRudderRadius);
|
canvas.drawBitmap(smallCircleBg, srcRect3, dstRcctF3, paint);
|
|
} catch (Exception e) {
|
e.printStackTrace();
|
} finally {
|
|
}
|
}
|
|
|
public void setRudderListener(RudderListener rockerListener) {
|
listener = rockerListener;
|
}
|
|
public boolean isSupportFourDirection() {
|
return mSupportFourDirection;
|
}
|
|
/**
|
* 设置是否支持四方向云台
|
*
|
* @param supportFourDirection
|
*/
|
public void setSupportFourDirection(boolean supportFourDirection) {
|
this.mSupportFourDirection = supportFourDirection;
|
resetCircleBg();
|
}
|
|
@Override
|
public boolean onTouchEvent(MotionEvent event) {
|
if (!mCanTouch) {
|
return true;
|
}
|
int len = (int) Math.sqrt(Math.pow(mCtrlPoint.x - event.getX(), 2) + Math.pow(mCtrlPoint.y - event.getY(), 2));
|
switch (event.getAction() & MotionEvent.ACTION_MASK) {
|
case MotionEvent.ACTION_DOWN:
|
if (len < mWheelRadius / 2) {
|
if (listener != null) {
|
listener.onSteeringWheelChangedBegin();
|
}
|
mDownState = 1;
|
firstX = (int) event.getX();
|
firstY = (int) event.getY();
|
dCtrlPointx = firstX - mCtrlPoint.x;
|
dCtrlPointy = firstY - mCtrlPoint.y;
|
} else if (len >= (mWheelRadius / 2) && len <= mWheelRadius) {
|
if (listener != null) {
|
listener.onSteeringWheelChangedBegin();
|
}
|
mDownState = 2;
|
mShowDirectPic = true;
|
firstX = (int) event.getX();
|
firstY = (int) event.getY();
|
dCtrlPointx = firstX - mCtrlPoint.x;
|
dCtrlPointy = firstY - mCtrlPoint.y;
|
float radian = getRadian(mCtrlPoint, new Point((int) event.getX(), (int) event.getY()));
|
int angle = LcCloudRudderView.this.getAngleConvert(radian);
|
Direction direction = directConvert(angle);
|
if (listener != null) {
|
listener.onSteeringWheelChangedSingle(direction);
|
}
|
}
|
invalidate();
|
break;
|
case MotionEvent.ACTION_MOVE:
|
if (mDownState == 1) {
|
int dragLen = (int) Math.sqrt(Math.pow(firstX - event.getX(), 2) + Math.pow(firstY - event.getY(), 2));
|
if (dragLen <= mWheelRadius - mChangeRudderRadius / 2) {
|
mRockerPosition.set((int) event.getX() - dCtrlPointx, (int) event.getY() - dCtrlPointy);
|
} else {
|
int cutRadius = (int) (mWheelRadius - mChangeRudderRadius / 2);
|
float radian = getRadian(mCtrlPoint, new Point((int) event.getX() - (firstX - mCtrlPoint.x), (int) event.getY() - (firstY - mCtrlPoint.y)));
|
mRockerPosition = new Point(mCtrlPoint.x + (int) (cutRadius * Math.cos(radian)), mCtrlPoint.y + (int) (cutRadius * Math.sin(radian)));
|
|
}
|
float radian = getRadian(mCtrlPoint, new Point((int) event.getX(), (int) event.getY()));
|
int angle = LcCloudRudderView.this.getAngleConvert(radian);
|
Direction direction = directConvert(angle);
|
if (dragLen >= (mWheelRadius / 2)) {//超过 边界再发送命令
|
mShowDirectPic = true;
|
if (listener != null) {
|
listener.onSteeringWheelChangedContinue(direction);
|
}
|
} else {//未超过边界,发送停止命令,图标不显示按下
|
mShowDirectPic = false;
|
if (listener != null) {
|
listener.onSteeringWheelChangedContinue(null);
|
}
|
}
|
} else if (mDownState == 2) {
|
if (listener != null) {
|
if (len >= (mWheelRadius / 2) && len <= mWheelRadius) {
|
mShowDirectPic = true;
|
float radian = getRadian(mCtrlPoint, new Point((int) event.getX(), (int) event.getY()));
|
int angle = LcCloudRudderView.this.getAngleConvert(radian);
|
directConvert(angle);
|
} else {
|
mShowDirectPic = false;
|
}
|
}
|
|
}
|
invalidate();
|
break;
|
case MotionEvent.ACTION_CANCEL:
|
case MotionEvent.ACTION_UP:
|
if (mDownState == 1) {
|
mShowDirectPic = false;
|
mRockerPosition = new Point(mCtrlPoint);
|
if (listener != null) {
|
listener.onSteeringWheelChangedContinue(null);
|
listener.onSteeringWheelChangedEnd();
|
}
|
|
} else if (mDownState == 2) {
|
mShowDirectPic = false;
|
float radian = getRadian(mCtrlPoint, new Point((int) event.getX(), (int) event.getY()));
|
int angle = LcCloudRudderView.this.getAngleConvert(radian);
|
Direction direction = directConvert(angle);
|
mRockerPosition = new Point(mCtrlPoint);
|
if (listener != null) {
|
//listener.onSteeringWheelChangedSingle(direction);
|
listener.onSteeringWheelChangedEnd();
|
}
|
}
|
firstX = 0;
|
firstY = 0;
|
mDownState = 0;
|
invalidate();
|
break;
|
default:
|
break;
|
}
|
return true;
|
}
|
|
private static float getRadian(Point a, Point b) {
|
float lenA = b.x - a.x;
|
float lenB = b.y - a.y;
|
float lenC = (float) Math.sqrt(lenA * lenA + lenB * lenB);
|
float ang = (float) Math.acos(lenA / lenC);
|
ang = ang * (b.y < a.y ? -1 : 1);
|
return ang;
|
}
|
|
private Direction directConvert(int angle) {
|
Direction direction = Direction.Left;
|
if (mSupportFourDirection) {
|
if (angle <= 45 || angle > 315) {
|
direction = Direction.Right;
|
mAngle = 90;
|
} else if (angle > 45 && angle <= 135) {
|
direction = Direction.Up;
|
mAngle = 0;
|
} else if (angle > 135 && angle <= 225) {
|
direction = Direction.Left;
|
mAngle = 270;
|
} else if (angle > 225 && angle <= 315) {
|
direction = Direction.Down;
|
mAngle = 180;
|
}
|
|
} else {
|
|
if (angle <= 22.5 || angle > 337.5) {
|
direction = Direction.Right;
|
mAngle = 90;
|
} else if (angle > 22.5 && angle <= 67.5) {
|
direction = Direction.Right_up;
|
mAngle = 45;
|
} else if (angle > 67.5 && angle <= 112.5) {
|
direction = Direction.Up;
|
mAngle = 0;
|
} else if (angle > 112.5 && angle <= 157.5) {
|
direction = Direction.Left_up;
|
mAngle = 315;
|
} else if (angle > 157.5 && angle <= 202.5) {
|
direction = Direction.Left;
|
mAngle = 270;
|
} else if (angle > 202.5 && angle <= 247.5) {
|
direction = Direction.Left_down;
|
mAngle = 225;
|
} else if (angle > 247.5 && angle <= 292.5) {
|
direction = Direction.Down;
|
mAngle = 180;
|
} else if (angle > 292.5 && angle <= 337.5) {
|
direction = Direction.Right_down;
|
mAngle = 135;
|
}
|
}
|
|
return direction;
|
}
|
|
private int getAngleConvert(float radian) {
|
int tmp = (int) Math.round(radian / Math.PI * 180);
|
if (tmp < 0) {
|
return -tmp;
|
} else {
|
return 180 + (180 - tmp);
|
}
|
}
|
|
public interface RudderListener {
|
void onSteeringWheelChangedBegin();
|
|
void onSteeringWheelChangedContinue(Direction direction);
|
|
void onSteeringWheelChangedSingle(Direction direction);
|
|
void onSteeringWheelChangedEnd();
|
}
|
|
@Override
|
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
super.onSizeChanged(w, h, oldw, oldh);
|
int len = Math.min(w, h) / 2;
|
mWheelRadius = (int) (len - mSolidRudderRadius / 2);
|
mChangeRudderRadius = mWheelRadius * 17 / 40;
|
|
mCtrlPoint.set(w / 2, h / 2);
|
mRockerPosition.set(w / 2, h / 2);
|
postInvalidate();
|
}
|
|
public void enable(boolean enabled) {
|
if (mCanTouch && !enabled) {
|
mShowDirectPic = false;
|
mRockerPosition = new Point(mCtrlPoint);
|
invalidate();
|
if (listener != null) {
|
listener.onSteeringWheelChangedContinue(null);
|
listener.onSteeringWheelChangedEnd();
|
}
|
}
|
setEnabled(enabled);
|
setAlpha(enabled ? 1f : 0.5f);
|
mCanTouch = enabled;
|
}
|
|
public void unit() {
|
Bitmap bigCirclebg = mLandScapeOnly ? mBigCircleLandScapeBg : mBigCircleBg;
|
Bitmap bigCircleBg_h = mLandScapeOnly ? mBigCircleLandScapeBg_h : mBigCircleBg_h;
|
Bitmap smallCircleBg = mLandScapeOnly ? mSmallCircleLandScapeBg : mSmallCircleBg;
|
if (bigCirclebg != null) {
|
bigCirclebg.recycle();
|
if (mLandScapeOnly) {
|
mBigCircleLandScapeBg = null;
|
} else {
|
mBigCircleBg = null;
|
}
|
}
|
if (bigCircleBg_h != null) {
|
bigCircleBg_h.recycle();
|
if (mLandScapeOnly) {
|
mBigCircleLandScapeBg_h = null;
|
} else {
|
mBigCircleBg_h = null;
|
}
|
}
|
if (smallCircleBg != null) {
|
smallCircleBg.recycle();
|
if (mLandScapeOnly) {
|
mSmallCircleLandScapeBg = null;
|
} else {
|
mSmallCircleBg = null;
|
}
|
}
|
listener = null;
|
}
|
}
|