android虚拟摇杆
虚拟摇杆一
资源下载
效果如下:
第一步:attr 中定义自定义参数,如下:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--
areaBackground 设置区域背景
rockerBackground 设置摇杆的样式
rockerScale 设置摇杆的相对于背景的比例
rockerSpeedLevel 设置当前位置相对于中心点的距离的比例 如:10 则中心点到边缘的距离分为 10 分越靠外数值越大 0-10
rockerCallBackMode 有变化就回调,或者是方向改变才会回调-->
<declare-styleable name="RockerView">
<attr name="areaBackground"format="color|reference" />
<attr name="rockerBackground"format="color|reference" />
<attr name="rockerScale"format="float"/>
<attr name="rockerSpeedLevel"format="integer" />
<attr name="rockerCallBackMode">
<flag name="CALL_BACK_MODE_MOVE" value="0" />
<flag name="CALL_BACK_MODE_STATE_CHANGE" value="1" />
</attr>
</declare-styleable>
</resources>
第二步:新建java类,继承View,代码较多,附带注释,不一一讲解了,不多700行吧:
public class MyRockerView extends View { private static final String TAG = "RockerView"; private static final int DEFAULT_SIZE = 400; private static final float DEFAULT_ROCKER_SCALE = 0.5f;//默认半径为背景的1/2 private Paint mAreaBackgroundPaint; private Paint mRockerPaint; private Point mRockerPosition; private Point mCenterPoint; private int mAreaRadius; private float mRockerScale; private int mRockerRadius; private CallBackMode mCallBackMode = CallBackMode.CALL_BACK_MODE_MOVE; private OnAngleChangeListener mOnAngleChangeListener; private OnShakeListener mOnShakeListener; private OnDistanceLevelListener mOnDistanceLevelListener; private DirectionMode mDirectionMode; private Direction tempDirection = Direction.DIRECTION_CENTER; private float lastDistance = 0; private boolean hasCall = false; private float baseDistance = 0; private int mDistanceLevel = 10;//分成10分 // 角度 private static final double ANGLE_0 = 0; private static final double ANGLE_360 = 360; // 360°水平方向平分2份的边缘角度 private static final double ANGLE_HORIZONTAL_2D_OF_0P = 90; private static final double ANGLE_HORIZONTAL_2D_OF_1P = 270; // 360°垂直方向平分2份的边缘角度 private static final double ANGLE_VERTICAL_2D_OF_0P = 0; private static final double ANGLE_VERTICAL_2D_OF_1P = 180; // 360°平分4份的边缘角度 private static final double ANGLE_4D_OF_0P = 0; private static final double ANGLE_4D_OF_1P = 90; private static final double ANGLE_4D_OF_2P = 180; private static final double ANGLE_4D_OF_3P = 270; // 360°平分4份的边缘角度(旋转45度) private static final double ANGLE_ROTATE45_4D_OF_0P = 45; private static final double ANGLE_ROTATE45_4D_OF_1P = 135; private static final double ANGLE_ROTATE45_4D_OF_2P = 225; private static final double ANGLE_ROTATE45_4D_OF_3P = 315; // 360°平分8份的边缘角度 private static final double ANGLE_8D_OF_0P = 22.5; private static final double ANGLE_8D_OF_1P = 67.5; private static final double ANGLE_8D_OF_2P = 112.5; private static final double ANGLE_8D_OF_3P = 157.5; private static final double ANGLE_8D_OF_4P = 202.5; private static final double ANGLE_8D_OF_5P = 247.5; private static final double ANGLE_8D_OF_6P = 292.5; private static final double ANGLE_8D_OF_7P = 337.5; // 摇杆可移动区域背景 private static final int AREA_BACKGROUND_MODE_PIC = 0; private static final int AREA_BACKGROUND_MODE_COLOR = 1; private static final int AREA_BACKGROUND_MODE_XML = 2; private static final int AREA_BACKGROUND_MODE_DEFAULT = 3; private int mAreaBackgroundMode = AREA_BACKGROUND_MODE_DEFAULT; private Bitmap mAreaBitmap; private int mAreaColor; // 摇杆背景 private static final int ROCKER_BACKGROUND_MODE_PIC = 4; private static final int ROCKER_BACKGROUND_MODE_COLOR = 5; private static final int ROCKER_BACKGROUND_MODE_XML = 6; private static final int ROCKER_BACKGROUND_MODE_DEFAULT = 7; private int mRockerBackgroundMode = ROCKER_BACKGROUND_MODE_DEFAULT; private Bitmap mRockerBitmap; private int mRockerColor; public MyRockerView(Context context, AttributeSet attrs) { super(context, attrs); // 获取自定义属性 initAttribute(context, attrs); if (isInEditMode()) { } // 移动区域画笔 mAreaBackgroundPaint = new Paint(); mAreaBackgroundPaint.setAntiAlias(true); // 摇杆画笔 mRockerPaint = new Paint(); mRockerPaint.setAntiAlias(true); // 中心点 mCenterPoint = new Point(); // 摇杆位置 mRockerPosition = new Point(); } /** * 获取属性 * * @param context context * @param attrs attrs */ private void initAttribute(Context context, AttributeSet attrs) { TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RockerView); // 可移动区域背景 Drawable areaBackground = typedArray.getDrawable(R.styleable.RockerView_areaBackground); if (null != areaBackground) { // 设置了背景 if (areaBackground instanceof BitmapDrawable) { // 设置了一张图片 mAreaBitmap = ((BitmapDrawable) areaBackground).getBitmap(); mAreaBackgroundMode = AREA_BACKGROUND_MODE_PIC; } else if (areaBackground instanceof GradientDrawable) { // XML mAreaBitmap = drawable2Bitmap(areaBackground); mAreaBackgroundMode = AREA_BACKGROUND_MODE_XML; } else if (areaBackground instanceof ColorDrawable) { // 色值 mAreaColor = ((ColorDrawable) areaBackground).getColor(); mAreaBackgroundMode = AREA_BACKGROUND_MODE_COLOR; } else { // 其他形式 mAreaBackgroundMode = AREA_BACKGROUND_MODE_DEFAULT; } } else { // 没有设置背景 mAreaBackgroundMode = AREA_BACKGROUND_MODE_DEFAULT; } // 摇杆背景 Drawable rockerBackground = typedArray.getDrawable(R.styleable.RockerView_rockerBackground); if (null != rockerBackground) { // 设置了摇杆背景 if (rockerBackground instanceof BitmapDrawable) { // 图片 mRockerBitmap = ((BitmapDrawable) rockerBackground).getBitmap(); mRockerBackgroundMode = ROCKER_BACKGROUND_MODE_PIC; } else if (rockerBackground instanceof GradientDrawable) { // XML mRockerBitmap = drawable2Bitmap(rockerBackground); mRockerBackgroundMode = ROCKER_BACKGROUND_MODE_XML; } else if (rockerBackground instanceof ColorDrawable) { // 色值 mRockerColor = ((ColorDrawable) rockerBackground).getColor(); mRockerBackgroundMode = ROCKER_BACKGROUND_MODE_COLOR; } else { // 其他形式 mRockerBackgroundMode = ROCKER_BACKGROUND_MODE_DEFAULT; } } else { // 没有设置摇杆背景 mRockerBackgroundMode = ROCKER_BACKGROUND_MODE_DEFAULT; } // 摇杆半径 mRockerScale = typedArray.getFloat(R.styleable.RockerView_rockerScale, DEFAULT_ROCKER_SCALE); //距离级别 mDistanceLevel = typedArray.getInt(R.styleable.RockerView_rockerSpeedLevel, 10); //回调模式 mCallBackMode = getCallBackMode(typedArray.getInt(R.styleable.RockerView_rockerCallBackMode, 0)); typedArray.recycle(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int measureWidth, measureHeight; int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); if (widthMode == MeasureSpec.EXACTLY) { // 具体的值和match_parent measureWidth = widthSize; } else { // wrap_content measureWidth = DEFAULT_SIZE; } if (heightMode == MeasureSpec.EXACTLY) { measureHeight = heightSize; } else { measureHeight = DEFAULT_SIZE; } setMeasuredDimension(measureWidth, measureHeight); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); int measuredWidth = getMeasuredWidth(); int measuredHeight = getMeasuredHeight(); int cx = measuredWidth / 2; int cy = measuredHeight / 2; // 中心点 mCenterPoint.set(cx, cy); // 可移动区域的半径 mAreaRadius = (measuredWidth <= measuredHeight) ? (int) (cx / (mRockerScale + 1)) : (int) (cy / (mRockerScale + 1)); mRockerRadius = (int) (mAreaRadius * mRockerScale); // 摇杆位置 if (0 == mRockerPosition.x || 0 == mRockerPosition.y) { mRockerPosition.set(mCenterPoint.x, mCenterPoint.y); } // 画可移动区域 if (AREA_BACKGROUND_MODE_PIC == mAreaBackgroundMode || AREA_BACKGROUND_MODE_XML == mAreaBackgroundMode) { // 图片 Rect src = new Rect(0, 0, mAreaBitmap.getWidth(), mAreaBitmap.getHeight()); Rect dst = new Rect(mCenterPoint.x - mAreaRadius, mCenterPoint.y - mAreaRadius, mCenterPoint.x + mAreaRadius, mCenterPoint.y + mAreaRadius); canvas.drawBitmap(mAreaBitmap, src, dst, mAreaBackgroundPaint); } else if (AREA_BACKGROUND_MODE_COLOR == mAreaBackgroundMode) { // 色值 mAreaBackgroundPaint.setColor(mAreaColor); canvas.drawCircle(mCenterPoint.x, mCenterPoint.y, mAreaRadius, mAreaBackgroundPaint); } else { // 其他或者未设置 mAreaBackgroundPaint.setColor(Color.GRAY); canvas.drawCircle(mCenterPoint.x, mCenterPoint.y, mAreaRadius, mAreaBackgroundPaint); } // 画摇杆 if (ROCKER_BACKGROUND_MODE_PIC == mRockerBackgroundMode || ROCKER_BACKGROUND_MODE_XML == mRockerBackgroundMode) { // 图片 Rect src = new Rect(0, 0, mRockerBitmap.getWidth(), mRockerBitmap.getHeight()); Rect dst = new Rect(mRockerPosition.x - mRockerRadius, mRockerPosition.y - mRockerRadius, mRockerPosition.x + mRockerRadius, mRockerPosition.y + mRockerRadius); canvas.drawBitmap(mRockerBitmap, src, dst, mRockerPaint); } else if (ROCKER_BACKGROUND_MODE_COLOR == mRockerBackgroundMode) { // 色值 mRockerPaint.setColor(mRockerColor); canvas.drawCircle(mRockerPosition.x, mRockerPosition.y, mRockerRadius, mRockerPaint); } else { // 其他或者未设置 mRockerPaint.setColor(Color.RED); canvas.drawCircle(mRockerPosition.x, mRockerPosition.y, mRockerRadius, mRockerPaint); } } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN:// 按下 // 回调 开始 callBackStart(); case MotionEvent.ACTION_MOVE:// 移动 float moveX = event.getX(); float moveY = event.getY(); baseDistance = mAreaRadius+2; Log.e("baseDistance",baseDistance+""); mRockerPosition = getRockerPositionPoint(mCenterPoint, new Point((int) moveX, (int) moveY), mAreaRadius + mRockerRadius, mRockerRadius); moveRocker(mRockerPosition.x, mRockerPosition.y); break; case MotionEvent.ACTION_UP:// 抬起 case MotionEvent.ACTION_CANCEL:// 移出区域 // 回调 结束 callBackFinish(); if (mOnShakeListener != null) { mOnShakeListener.direction(Direction.DIRECTION_CENTER); } float upX = event.getX(); float upY = event.getY(); moveRocker(mCenterPoint.x, mCenterPoint.y); break; } return true; } /** * 获取摇杆实际要显示的位置(点) * * @param centerPoint 中心点 * @param touchPoint 触摸点 * @param regionRadius 摇杆可活动区域半径 * @param rockerRadius 摇杆半径 * @return 摇杆实际显示的位置(点) */ private Point getRockerPositionPoint(Point centerPoint, Point touchPoint, float regionRadius, float rockerRadius) { // 两点在X轴的距离 float lenX = (float) (touchPoint.x - centerPoint.x); // 两点在Y轴距离 float lenY = (float) (touchPoint.y - centerPoint.y); // 两点距离 float lenXY = (float) Math.sqrt((double) (lenX * lenX + lenY * lenY)); // 计算弧度 double radian = Math.acos(lenX / lenXY) * (touchPoint.y < centerPoint.y ? -1 : 1); // 计算角度 double angle = radian2Angle(radian); if (lenXY + rockerRadius <= regionRadius) { // 触摸位置在可活动范围内 // 回调 返回参数 callBack(angle, (int) lenXY); return touchPoint; } else { // 触摸位置在可活动范围以外 // 计算要显示的位置 int showPointX = (int) (centerPoint.x + (regionRadius - rockerRadius) * Math.cos(radian)); int showPointY = (int) (centerPoint.y + (regionRadius - rockerRadius) * Math.sin(radian)); callBack(angle, (int) Math.sqrt((showPointX - centerPoint.x) * (showPointX - centerPoint.x) + (showPointY - centerPoint.y) * (showPointY - centerPoint.y))); return new Point(showPointX, showPointY); } } /** * 移动摇杆到指定位置 * * @param x x坐标 * @param y y坐标 */ private void moveRocker(float x, float y) { mRockerPosition.set((int) x, (int) y); invalidate(); } /** * 弧度转角度 * * @param radian 弧度 * @return 角度[0, 360) */ private double radian2Angle(double radian) { double tmp = Math.round(radian / Math.PI * 180); return tmp >= 0 ? tmp : 360 + tmp; } /** * Drawable 转 Bitmap * * @param drawable Drawable * @return Bitmap */ private Bitmap drawable2Bitmap(Drawable drawable) { // 取 drawable 的长宽 int width = drawable.getIntrinsicWidth(); int height = drawable.getIntrinsicHeight(); // 取 drawable 的颜色格式 Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; // 建立对应 bitmap Bitmap bitmap = Bitmap.createBitmap(width, height, config); Canvas canvas = new Canvas(bitmap); drawable.setBounds(0, 0, width, height); drawable.draw(canvas); return bitmap; } /** * 回调 * 开始 */ private void callBackStart() { tempDirection = Direction.DIRECTION_CENTER; if (null != mOnAngleChangeListener) { mOnAngleChangeListener.onStart(); } if (null != mOnShakeListener) { mOnShakeListener.onStart(); } } /** * 回调 * 返回参数 * * @param angle 摇动角度 */ private void callBack(double angle, float distance) { Log.e("distance",distance+""); if (Math.abs(distance - lastDistance) >= (baseDistance / mDistanceLevel)) { lastDistance = distance; if (null != mOnDistanceLevelListener) { int level = (int) (distance/(baseDistance/mDistanceLevel)); mOnDistanceLevelListener.onDistanceLevel(level); } } if (null != mOnAngleChangeListener) { mOnAngleChangeListener.angle(angle); } if (null != mOnShakeListener) { if (CallBackMode.CALL_BACK_MODE_MOVE == mCallBackMode) { switch (mDirectionMode) { case DIRECTION_2_HORIZONTAL:// 左右方向 if (ANGLE_0 <= angle && ANGLE_HORIZONTAL_2D_OF_0P > angle || ANGLE_HORIZONTAL_2D_OF_1P <= angle && ANGLE_360 > angle) { // 右 mOnShakeListener.direction(Direction.DIRECTION_RIGHT); } else if (ANGLE_HORIZONTAL_2D_OF_0P <= angle && ANGLE_HORIZONTAL_2D_OF_1P > angle) { // 左 mOnShakeListener.direction(Direction.DIRECTION_LEFT); } break; case DIRECTION_2_VERTICAL:// 上下方向 if (ANGLE_VERTICAL_2D_OF_0P <= angle && ANGLE_VERTICAL_2D_OF_1P > angle) { // 下 mOnShakeListener.direction(Direction.DIRECTION_DOWN); } else if (ANGLE_VERTICAL_2D_OF_1P <= angle && ANGLE_360 > angle) { // 上 mOnShakeListener.direction(Direction.DIRECTION_UP); } break; case DIRECTION_4_ROTATE_0:// 四个方向 if (ANGLE_4D_OF_0P <= angle && ANGLE_4D_OF_1P > angle) { // 右下 mOnShakeListener.direction(Direction.DIRECTION_DOWN_RIGHT); } else if (ANGLE_4D_OF_1P <= angle && ANGLE_4D_OF_2P > angle) { // 左下 mOnShakeListener.direction(Direction.DIRECTION_DOWN_LEFT); } else if (ANGLE_4D_OF_2P <= angle && ANGLE_4D_OF_3P > angle) { // 左上 mOnShakeListener.direction(Direction.DIRECTION_UP_LEFT); } else if (ANGLE_4D_OF_3P <= angle && ANGLE_360 > angle) { // 右上 mOnShakeListener.direction(Direction.DIRECTION_UP_RIGHT); } break; case DIRECTION_4_ROTATE_45:// 四个方向 旋转45度 if (ANGLE_0 <= angle && ANGLE_ROTATE45_4D_OF_0P > angle || ANGLE_ROTATE45_4D_OF_3P <= angle && ANGLE_360 > angle) { // 右 mOnShakeListener.direction(Direction.DIRECTION_RIGHT); } else if (ANGLE_ROTATE45_4D_OF_0P <= angle && ANGLE_ROTATE45_4D_OF_1P > angle) { // 下 mOnShakeListener.direction(Direction.DIRECTION_DOWN); } else if (ANGLE_ROTATE45_4D_OF_1P <= angle && ANGLE_ROTATE45_4D_OF_2P > angle) { // 左 mOnShakeListener.direction(Direction.DIRECTION_LEFT); } else if (ANGLE_ROTATE45_4D_OF_2P <= angle && ANGLE_ROTATE45_4D_OF_3P > angle) { // 上 mOnShakeListener.direction(Direction.DIRECTION_UP); } break; case DIRECTION_8:// 八个方向 if (ANGLE_0 <= angle && ANGLE_8D_OF_0P > angle || ANGLE_8D_OF_7P <= angle && ANGLE_360 > angle) { // 右 mOnShakeListener.direction(Direction.DIRECTION_RIGHT); } else if (ANGLE_8D_OF_0P <= angle && ANGLE_8D_OF_1P > angle) { // 右下 mOnShakeListener.direction(Direction.DIRECTION_DOWN_RIGHT); } else if (ANGLE_8D_OF_1P <= angle && ANGLE_8D_OF_2P > angle) { // 下 mOnShakeListener.direction(Direction.DIRECTION_DOWN); } else if (ANGLE_8D_OF_2P <= angle && ANGLE_8D_OF_3P > angle) { // 左下 mOnShakeListener.direction(Direction.DIRECTION_DOWN_LEFT); } else if (ANGLE_8D_OF_3P <= angle && ANGLE_8D_OF_4P > angle) { // 左 mOnShakeListener.direction(Direction.DIRECTION_LEFT); } else if (ANGLE_8D_OF_4P <= angle && ANGLE_8D_OF_5P > angle) { // 左上 mOnShakeListener.direction(Direction.DIRECTION_UP_LEFT); } else if (ANGLE_8D_OF_5P <= angle && ANGLE_8D_OF_6P > angle) { // 上 mOnShakeListener.direction(Direction.DIRECTION_UP); } else if (ANGLE_8D_OF_6P <= angle && ANGLE_8D_OF_7P > angle) { // 右上 mOnShakeListener.direction(Direction.DIRECTION_UP_RIGHT); } break; default: break; } } else if (CallBackMode.CALL_BACK_MODE_STATE_CHANGE == mCallBackMode) { switch (mDirectionMode) { case DIRECTION_2_HORIZONTAL:// 左右方向 if ((ANGLE_0 <= angle && ANGLE_HORIZONTAL_2D_OF_0P > angle || ANGLE_HORIZONTAL_2D_OF_1P <= angle && ANGLE_360 > angle) && tempDirection != Direction.DIRECTION_RIGHT) { // 右 tempDirection = Direction.DIRECTION_RIGHT; mOnShakeListener.direction(Direction.DIRECTION_RIGHT); } else if (ANGLE_HORIZONTAL_2D_OF_0P <= angle && ANGLE_HORIZONTAL_2D_OF_1P > angle && tempDirection != Direction.DIRECTION_LEFT) { // 左 tempDirection = Direction.DIRECTION_LEFT; mOnShakeListener.direction(Direction.DIRECTION_LEFT); } break; case DIRECTION_2_VERTICAL:// 上下方向 if (ANGLE_VERTICAL_2D_OF_0P <= angle && ANGLE_VERTICAL_2D_OF_1P > angle && tempDirection != Direction.DIRECTION_DOWN) { // 下 tempDirection = Direction.DIRECTION_DOWN; mOnShakeListener.direction(Direction.DIRECTION_DOWN); } else if (ANGLE_VERTICAL_2D_OF_1P <= angle && ANGLE_360 > angle && tempDirection != Direction.DIRECTION_UP) { // 上 tempDirection = Direction.DIRECTION_UP; mOnShakeListener.direction(Direction.DIRECTION_UP); } break; case DIRECTION_4_ROTATE_0:// 四个方向 if (ANGLE_4D_OF_0P <= angle && ANGLE_4D_OF_1P > angle && tempDirection != Direction.DIRECTION_DOWN_RIGHT) { // 右下 tempDirection = Direction.DIRECTION_DOWN_RIGHT; mOnShakeListener.direction(Direction.DIRECTION_DOWN_RIGHT); } else if (ANGLE_4D_OF_1P <= angle && ANGLE_4D_OF_2P > angle && tempDirection != Direction.DIRECTION_DOWN_LEFT) { // 左下 tempDirection = Direction.DIRECTION_DOWN_LEFT; mOnShakeListener.direction(Direction.DIRECTION_DOWN_LEFT); } else if (ANGLE_4D_OF_2P <= angle && ANGLE_4D_OF_3P > angle && tempDirection != Direction.DIRECTION_UP_LEFT) { // 左上 tempDirection = Direction.DIRECTION_UP_LEFT; mOnShakeListener.direction(Direction.DIRECTION_UP_LEFT); } else if (ANGLE_4D_OF_3P <= angle && ANGLE_360 > angle && tempDirection != Direction.DIRECTION_UP_RIGHT) { // 右上 tempDirection = Direction.DIRECTION_UP_RIGHT; mOnShakeListener.direction(Direction.DIRECTION_UP_RIGHT); } break; case DIRECTION_4_ROTATE_45:// 四个方向 旋转45度 if ((ANGLE_0 <= angle && ANGLE_ROTATE45_4D_OF_0P > angle || ANGLE_ROTATE45_4D_OF_3P <= angle && ANGLE_360 > angle) && tempDirection != Direction.DIRECTION_RIGHT) { // 右 tempDirection = Direction.DIRECTION_RIGHT; mOnShakeListener.direction(Direction.DIRECTION_RIGHT); } else if (ANGLE_ROTATE45_4D_OF_0P <= angle && ANGLE_ROTATE45_4D_OF_1P > angle && tempDirection != Direction.DIRECTION_DOWN) { // 下 tempDirection = Direction.DIRECTION_DOWN; mOnShakeListener.direction(Direction.DIRECTION_DOWN); } else if (ANGLE_ROTATE45_4D_OF_1P <= angle && ANGLE_ROTATE45_4D_OF_2P > angle && tempDirection != Direction.DIRECTION_LEFT) { // 左 tempDirection = Direction.DIRECTION_LEFT; mOnShakeListener.direction(Direction.DIRECTION_LEFT); } else if (ANGLE_ROTATE45_4D_OF_2P <= angle && ANGLE_ROTATE45_4D_OF_3P > angle && tempDirection != Direction.DIRECTION_UP) { // 上 tempDirection = Direction.DIRECTION_UP; mOnShakeListener.direction(Direction.DIRECTION_UP); } break; case DIRECTION_8:// 八个方向 if ((ANGLE_0 <= angle && ANGLE_8D_OF_0P > angle || ANGLE_8D_OF_7P <= angle && ANGLE_360 > angle) && tempDirection != Direction.DIRECTION_RIGHT) { // 右 tempDirection = Direction.DIRECTION_RIGHT; mOnShakeListener.direction(Direction.DIRECTION_RIGHT); } else if (ANGLE_8D_OF_0P <= angle && ANGLE_8D_OF_1P > angle && tempDirection != Direction.DIRECTION_DOWN_RIGHT) { // 右下 tempDirection = Direction.DIRECTION_DOWN_RIGHT; mOnShakeListener.direction(Direction.DIRECTION_DOWN_RIGHT); } else if (ANGLE_8D_OF_1P <= angle && ANGLE_8D_OF_2P > angle && tempDirection != Direction.DIRECTION_DOWN) { // 下 tempDirection = Direction.DIRECTION_DOWN; mOnShakeListener.direction(Direction.DIRECTION_DOWN); } else if (ANGLE_8D_OF_2P <= angle && ANGLE_8D_OF_3P > angle && tempDirection != Direction.DIRECTION_DOWN_LEFT) { // 左下 tempDirection = Direction.DIRECTION_DOWN_LEFT; mOnShakeListener.direction(Direction.DIRECTION_DOWN_LEFT); } else if (ANGLE_8D_OF_3P <= angle && ANGLE_8D_OF_4P > angle && tempDirection != Direction.DIRECTION_LEFT) { // 左 tempDirection = Direction.DIRECTION_LEFT; mOnShakeListener.direction(Direction.DIRECTION_LEFT); } else if (ANGLE_8D_OF_4P <= angle && ANGLE_8D_OF_5P > angle && tempDirection != Direction.DIRECTION_UP_LEFT) { // 左上 tempDirection = Direction.DIRECTION_UP_LEFT; mOnShakeListener.direction(Direction.DIRECTION_UP_LEFT); } else if (ANGLE_8D_OF_5P <= angle && ANGLE_8D_OF_6P > angle && tempDirection != Direction.DIRECTION_UP) { // 上 tempDirection = Direction.DIRECTION_UP; mOnShakeListener.direction(Direction.DIRECTION_UP); } else if (ANGLE_8D_OF_6P <= angle && ANGLE_8D_OF_7P > angle && tempDirection != Direction.DIRECTION_UP_RIGHT) { // 右上 tempDirection = Direction.DIRECTION_UP_RIGHT; mOnShakeListener.direction(Direction.DIRECTION_UP_RIGHT); } break; default: break; } } } } /** * 回调 * 结束 */ private void callBackFinish() { tempDirection = Direction.DIRECTION_CENTER; if (null != mOnAngleChangeListener) { mOnAngleChangeListener.onFinish(); } if (null != mOnShakeListener) { mOnShakeListener.onFinish(); } } /** * 回调模式 */ public enum CallBackMode { // 有移动就立刻回调 CALL_BACK_MODE_MOVE, // 只有状态变化的时候才回调 CALL_BACK_MODE_STATE_CHANGE, //只有状态变化或者距离变化的时候才回调 CALL_BACK_MODE_STATE_DISTANCE_CHANGE } /** * 设置回调模式 * * @param mode 回调模式 */ public void setCallBackMode(CallBackMode mode) { mCallBackMode = mode; } /** * 摇杆支持几个方向 */ public enum DirectionMode { DIRECTION_2_HORIZONTAL,// 横向 左右两个方向 DIRECTION_2_VERTICAL, // 纵向 上下两个方向 DIRECTION_4_ROTATE_0, // 四个方向 DIRECTION_4_ROTATE_45, // 四个方向 旋转45度 DIRECTION_8 // 八个方向 } /** * 方向 */ public enum Direction { DIRECTION_LEFT, // 左 DIRECTION_RIGHT, // 右 DIRECTION_UP, // 上 DIRECTION_DOWN, // 下 DIRECTION_UP_LEFT, // 左上 DIRECTION_UP_RIGHT, // 右上 DIRECTION_DOWN_LEFT, // 左下 DIRECTION_DOWN_RIGHT, // 右下 DIRECTION_CENTER // 中间 } /** * 添加摇杆摇动角度的监听 * * @param listener 回调接口 */ public void setOnAngleChangeListener(OnAngleChangeListener listener) { mOnAngleChangeListener = listener; } /** * 添加摇动的监听 * * @param directionMode 监听的方向 * @param listener 回调 */ public void setOnShakeListener(DirectionMode directionMode, OnShakeListener listener) { mDirectionMode = directionMode; mOnShakeListener = listener; } /** * 添加摇动的距离变化 */ public void setOnDistanceLevelListener(OnDistanceLevelListener listenr) { mOnDistanceLevelListener = listenr; } /** * 摇动方向监听接口 */ public interface OnShakeListener { // 开始 void onStart(); /** * 摇动方向 * * @param direction 方向 */ void direction(Direction direction); // 结束 void onFinish(); } /** * 摇动角度的监听接口 */ public interface OnAngleChangeListener { // 开始 void onStart(); /** * 摇杆角度变化 * * @param angle 角度[0,360) */ void angle(double angle); // 结束 void onFinish(); } /** * 摇动距离 */ public interface OnDistanceLevelListener { void onDistanceLevel(int level); } private CallBackMode getCallBackMode(int mode) { switch (mode) { case 0: return CallBackMode.CALL_BACK_MODE_MOVE; case 1: return CallBackMode.CALL_BACK_MODE_STATE_CHANGE; } return mCallBackMode; } }
第三步:添加到布局:
特别注意,需要先导入自定义的属性:xmlns:rocker="http://schemas.android.com/apk/res-auto"
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:rocker="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.liang.myrockerview_view.MainActivity"> <!--数据显示--> <LinearLayout android:layout_width="130dp" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:orientation="vertical"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="XY轴数据" android:textAlignment="center" /> <TextView android:id="@+id/directionXY_Text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="当前方向:"/> <TextView android:id="@+id/angleXY_Text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="当前角度:"/> <TextView android:id="@+id/levelXY_Text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="当前偏移级别:"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Z轴数据" android:textAlignment="center"/> <TextView android:id="@+id/directionZ_Text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="当前方向:"/> <TextView android:id="@+id/angleZ_Text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="当前角度:"/> <TextView android:id="@+id/levelZ_Text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="当前偏移级别:"/> </LinearLayout> <!--摇杆--> <com.liang.myrockerview_view.MyRockerView android:id="@+id/rockerXY_View" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="25dp" android:layout_alignParentBottom="true" rocker:areaBackground="@mipmap/rocker_base" rocker:rockerBackground="@mipmap/rocker" rocker:rockerSpeedLevel="10" rocker:rockerCallBackMode="CALL_BACK_MODE_STATE_CHANGE" rocker:rockerScale="0.5"/> <com.liang.myrockerview_view.MyRockerView android:id="@+id/rockerZ_View" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="25dp" android:layout_alignParentRight="true" android:layout_alignParentBottom="true" rocker:areaBackground="@mipmap/rocker_base" rocker:rockerBackground="@mipmap/rocker" rocker:rockerSpeedLevel="10" rocker:rockerCallBackMode="CALL_BACK_MODE_STATE_CHANGE" rocker:rockerScale="0.5"/> </RelativeLayout>
第四部:实例化并添加点击事件
//方向有改变时回调 mRockerViewXY = (MyRockerView) findViewById(R.id.rockerXY_View);//8方向 mRockerViewZ = (MyRockerView) findViewById(R.id.rockerZ_View);//2方向
//xy轴 //方向 mRockerViewXY.setOnShakeListener(MyRockerView.DirectionMode.DIRECTION_8, new MyRockerView.OnShakeListener() { @Override public void onStart() { } @Override public void direction(MyRockerView.Direction direction) { if (direction == MyRockerView.Direction.DIRECTION_CENTER){ directionXY = ("当前方向:中心"); }else if (direction == MyRockerView.Direction.DIRECTION_DOWN){ directionXY = ("当前方向:下"); }else if (direction == MyRockerView.Direction.DIRECTION_LEFT){ directionXY = ("当前方向:左"); }else if (direction == MyRockerView.Direction.DIRECTION_UP){ directionXY = ("当前方向:上"); }else if (direction == MyRockerView.Direction.DIRECTION_RIGHT){ directionXY = ("当前方向:右"); }else if (direction == MyRockerView.Direction.DIRECTION_DOWN_LEFT){ directionXY = ("当前方向:左下"); }else if (direction == MyRockerView.Direction.DIRECTION_DOWN_RIGHT){ directionXY = ("当前方向:右下"); }else if (direction == MyRockerView.Direction.DIRECTION_UP_LEFT){ directionXY = ("当前方向:左上"); }else if (direction == MyRockerView.Direction.DIRECTION_UP_RIGHT){ directionXY = ("当前方向:右上"); } Log.e(TAG, "XY轴"+directionXY); Log.e(TAG, "-----------------------------------------------" ); directionXY_Text.setText(directionXY); } @Override public void onFinish() { } }); //角度 mRockerViewXY.setOnAngleChangeListener(new MyRockerView.OnAngleChangeListener() { @Override public void onStart() { } @Override public void angle(double angle) { angleXY = ("当前角度:"+angle); Log.e(TAG, "XY轴"+angleXY); angleXY_Text.setText(angleXY); } @Override public void onFinish() { } }); //级别 mRockerViewXY.setOnDistanceLevelListener(new MyRockerView.OnDistanceLevelListener() { @Override public void onDistanceLevel(int level) { levelXY = ("当前距离级别:"+level); Log.e(TAG, "XY轴"+levelXY); levelXY_Text.setText(levelXY); } });
- 上一篇: android 虚拟摇杆绘制
- 下一篇: Android自定义摇杆实现蓝牙控制小车