android 遥杆控件 自定义控件
遥杆控件 android 自定义控件
、
package com.sun.demo1;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import androidx.core.content.ContextCompat;
/**
* Created by jaelyn on 16-06-29.
* 摇杆view
*/
public class RockerView extends View {
public static final int BACK_MODE_LINE_Y = 1;
public static final int BACK_MODE_CENTER = 0;
public static final int CONTROL_BY_TOUCH = 0;
public static final int CONTROL_BY_ORIENTATION = 1;
private static final int TOUCH_DOWN = 0;
private static final int TOUCH_MOVE = 1;
private static final int TOUCH_UP = 2;
private static final int TOUCH_CENTER = 3;
private static final float PagerMarginsScale = 0.0f;
private Drawable mDrawBg;
private Drawable mDrawRocker;
private int mPagerMargins = 0;
private int mBgWight;
private int mBgR;
private int mRockerWidth, mRockerR;
private int mRockerX, mRockerY;
private Rect mRockerRect = new Rect();
private int mRockerGravide = 0;
private int mRockeBackMode = BACK_MODE_LINE_Y;
private int mTouchMode = TOUCH_CENTER;
private Paint paint = new Paint();
private OnLocaListener onLocaListener;
private byte trimX = (byte) 128, trimY = (byte) 128;
private SensorUtil sensorUtil;
private int mControlMode = CONTROL_BY_TOUCH;
private float mRockerXPer, mRockerYPer;
private float angle;
public String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String avenue;
public String spareAvenue;
public String getAvenue() {
return avenue;
}
public void setAvenue(String avenue) {
this.avenue = avenue;
}
public String getSpareAvenue() {
return spareAvenue;
}
public void setSpareAvenue(String spareAvenue) {
this.spareAvenue = spareAvenue;
}
public OnMyMoveListener myMoveListener;
public void setOnMyMoveListener(OnMyMoveListener listener){
this.myMoveListener=listener;
}
RotationListener rotationListener;
public interface RotationListener {
// 角度
void AngleChange(float angleNum);
// 是否显示方向标
void isShow(boolean isShow);
// 方向值
void PositionChange(int type, int x,int y);
// 按下时的坐标
void onDown(float x,float y);
}
public void setRotationListener(RotationListener rotationListener){
this.rotationListener = rotationListener;
}
private Runnable moveBackRunnable = new Runnable() {
@Override
public void run() {
moveBack();
}
};
public RockerView(Context context) {
super(context);
init(null, 0);
}
public RockerView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs, 0);
}
public RockerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs, defStyleAttr);
}
public void init(AttributeSet attrs, int defStyleAttr) {
paint.setColor(0xaaff0000);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
parentHeight = parentWidth = Math.min(parentWidth, parentHeight);
mBgWight = parentWidth;
mPagerMargins = (int) (parentWidth * PagerMarginsScale);
mBgR = parentWidth / 2 - mPagerMargins - mRockerR;
mRockerWidth = mDrawRocker.getIntrinsicWidth();
mRockerWidth =(( mBgWight / 2) / 2) +10;
mRockerR = mRockerWidth / 2;
setMeasuredDimension(parentWidth, parentHeight);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//绘制背景
mDrawBg.setBounds(0, 0, mBgWight, mBgWight);
mDrawBg.draw(canvas);
//计算小球的位置
mDrawRocker.setBounds(getRockerRect());
//绘制小球
mDrawRocker.draw(canvas);
}
/**
* 以摇杆当前的坐标为中心点,计算Rocker绘画的范围
* @return
*/
private Rect getRockerRect() {
int rockerX = (int) (mBgR * mRockerXPer + mBgWight / 2);
int rockerY = (int) (-mBgR * mRockerYPer + mBgWight / 2);
mRockerRect.set(rockerX - mRockerR, rockerY - mRockerR, rockerX + mRockerR,
rockerY + mRockerR);
return mRockerRect;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (mControlMode == CONTROL_BY_ORIENTATION) {
return super.onTouchEvent(event);
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (isTouchRocker((int) event.getX(), (int) event.getY())) {
mTouchMode = TOUCH_DOWN;
if(rotationListener != null){
rotationListener.isShow(true);
}
return true;
}
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
if (mTouchMode == TOUCH_MOVE) {
moveBack();
mTouchMode = TOUCH_UP;
}
if(rotationListener != null){
rotationListener.isShow(false);
}
break;
}
return super.onTouchEvent(event);
}
public boolean isTouchRocker(int x, int y) {
// return mRockerRect.contains(x, y);
return true;
}
private void moveRocker(float x, float y) {
if (!isRange(x, y)) {
setCircleXY(x, y);
} else {
mRockerX = (int) x;
mRockerY = (int) y;
}
setLinstenerData();
postInvalidate();
}
private boolean isRange(float x, float y) {
float dx = mBgWight / 2 - x;
float dy = mBgWight / 2 - y;
return mBgR >= Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
}
private void setLinstenerData() {
if (mBgR == 0) {
return;
}
mRockerXPer = (mRockerX - mBgWight / 2f) / (float) mBgR;
mRockerYPer = (mBgWight / 2f - mRockerY) / (float) mBgR;
if(this.myMoveListener!=null){
this.myMoveListener.onSignal(avenue, name, transformFB(mBgR, mRockerX - mBgWight / 2), 1);
this.myMoveListener.onSignal(spareAvenue, name, transformFB(mBgR, mRockerY - mBgWight / 2), 2);
}
}
public int transformFB(int radius, float num){
int direction = 0;
if(num > 0){
direction = (int) ((Math.abs(num) / radius) * 90);
direction = 90 + direction;
}else if(num < 0){
direction = (int) ((Math.abs(num) / radius) * 90);
direction = 90 - direction;
}else{
direction = 90;
}
//超值锁
if(direction > 180){
direction = 180;
}
if(direction < 0){
direction = 0;
}
return direction;
}
public interface OnLocaListener {
void getLocation(int x, int y);
}
public void setOnLocaListener(OnLocaListener onLocaListener) {
this.onLocaListener = onLocaListener;
}
private class AnimToBack implements Runnable {
private long startTime;
private float duration;
private int startX, startY;
private int dx, dy;
public void start(int startX, int startY, int endX, int endY, int duration) {
this.duration = duration;
dx = endX - startX;
dy = endY - startY;
this.startX = startX;
this.startY = startY;
startTime = SystemClock.uptimeMillis();
post(this);
}
@Override
public void run() {
float progress = (SystemClock.uptimeMillis() - startTime) / duration;
if (progress >= 1) {
progress = 1;
} else {
post(this);
}
moveRocker(dx * progress + startX, dy * progress + startY);
}
}
private void setBackMode(int baceMode, boolean moveToBack) {
this.mRockeBackMode = baceMode;
if (moveToBack) {
moveBack();
}
}
public void moveBack() {
int backX = mBgWight / 2;
int backY = mBgWight / 2;
if (mRockeBackMode == BACK_MODE_CENTER) {
backY = backX = mBgWight / 2;
} else if (mRockeBackMode == BACK_MODE_LINE_Y) {
backX = mBgWight / 2;
backY = mBgWight;
}
new AnimToBack().start(mRockerX, mRockerY, backX, backY, 150);
}
public void moveToPoint(float percentX, float percentY) {
float x = percentX * mBgR + mBgWight / 2;
float y = percentY * mBgR + mBgWight / 2;
new AnimToBack().start((int) mRockerX, (int) mRockerY, (int) x, (int) y, 10);
}
public void moveToPointDura(float percentX, float percentY, int duration) {
float x = percentX * mBgR + mBgWight / 2;
float y = percentY * mBgR + mBgWight / 2;
new AnimToBack().start((int) mRockerX, (int) mRockerY, (int) x, (int) y, 10);
Handler handler = new Handler();
handler.removeCallbacks(moveBackRunnable);
handler.postDelayed(moveBackRunnable, duration);
}
public void setControlMode(int type) {
final double stickyCenter = 0.09;
if (type == CONTROL_BY_TOUCH) {
mControlMode = CONTROL_BY_TOUCH;
if (sensorUtil != null) {
sensorUtil.unRegisterListener();
sensorUtil = null;
}
} else if (type == CONTROL_BY_ORIENTATION) {
mControlMode = CONTROL_BY_ORIENTATION;
sensorUtil = new SensorUtil(getContext(), new SensorUtil.OnChangeListener() {
@Override
public void setXY(float dx, float dy) {
Log.d("sensor", dx + "--" + dy);
float x = dx * mBgR + (float) mBgWight / 2;
float y = dy * mBgR + (float) mBgWight / 2;
moveRocker(x, y);
}
});
sensorUtil.registerListener();
}
}
public float getAngle(float xx,float yy){
double angle,k;
if (mBgWight / 2==yy)//斜率不存在时
if (mBgWight / 2 > xx)//判断x1指向x2的方向
angle= -Math.PI/2;
else
angle= Math.PI/2;
else{
k=(mBgWight / 2-xx)/(mBgWight / 2-yy); //两点的坐标求斜率,至于为什么是(x1-x2)/(y1-y2)不是(y1-y2)/(x1-x2)待会我们再做解释
if (mBgWight / 2 > yy) {//判断x1y1指向x2y2的方向
// 用反tan求角度 这个高中好像没学过 既然Math类已经帮我们封装好了就直接拿来用吧
angle = Math.atan(k) + Math.PI;
} else {
angle = Math.atan(k);
}
}
return (float) angle;
}
/**
* 角度值换算
* @param num
* @return
*/
public float transformAngle(float num){
float roundLength = (float) (Math.abs(num + 1.5) );
num = (float) (roundLength / 0.0172);
if(num > 360){
num = 360;
}else{
num = 360 - num;
}
return num;
}
public void registerListener() {
if (sensorUtil != null) {
sensorUtil.registerListener();
}
}
public void unregisterListener() {
if (sensorUtil != null) {
sensorUtil.unRegisterListener();
}
}
public float getmRockerXPer() {
return mRockerXPer;
}
public float getmRockerYPer() {
return mRockerYPer;
}
public byte getTrimX() {
return trimX;
}
public void setTrimX(byte trimX) {
this.trimX = trimX;
}
public byte getTrimY() {
return trimY;
}
public void setTrimY(byte trimY) {
this.trimY = trimY;
}
}
附 DEMO地址 https://download.csdn.net/download/qq_37630270/87971815