package com.efrobot.client.remotecontrol.customer;
import android.content.Context;
import android.graphics.Point;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.efrobot.client.remotecontrol.R;
/**
* Created by guo on 2016/6/8.
* 自定义方向控制,控制机器人的运动方向
* 1.在onTouch事件的时候保存手指点下的位置,保存成两个point对象,一个是背景的backgroundPoint,一个是轨迹球的point。调用requestLayout重新调用onLayout进行摆放位置
* 2.在onMove事件中
*/
public class RudderView extends ViewGroup {
public final static int MODEL_ALL = 0;
public final static int MODEL_UP_DOWN = 1;
public final static int MODEL_LEFT_RIGHT = 2;
private int viewWidth;
private int viewHeight;
private int model = MODEL_ALL;
private boolean isProcessTouch;
/**
* 轨迹球滑动监听
*/
private RudderViewListener mRudderViewListener;
/**
* 是否子控件
*/
private boolean isOnLayout = false;
/**
* 背景View
*/
private Point backGroundPoint = new Point();
/**
* 轨迹圆点View
*/
private Point mPoint = new Point();
/**
* 轨迹圆点得活动范围
*/
private int pointDistance = 0;
/**
* 是否显示子View
*/
private boolean isShow = true;
/**
* xml中声明此View,生成View对象时会调用此构造函数
* @param context 上下文
* @param attrs view的属性
*/
public RudderView(Context context, AttributeSet attrs) {
super(context, attrs);
//初始化背景和轨迹球id
int[] ids ={R.id.tv_point, R.id.tv_bg};
//初始化控件和轨迹球的背景图片
int[] backGrounds ={R.mipmap.remote_control_point, R.mipmap.remote_control_background};
LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
//初始化控件和轨迹球
for(int i = 0; i < ids.length; i++) {
TextView textView = new TextView(context);
textView.setId(ids[i]);
textView.setLayoutParams(params);
textView.setBackgroundResource(backGrounds[i]);
addView(textView);
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
measureChildren(widthMeasureSpec, heightMeasureSpec);
viewWidth = getMeasuredWidth();
viewHeight = getMeasuredHeight();
}
public void enableProcessTouch(boolean isProcessTouch) {
this.isProcessTouch = isProcessTouch;
}
/**
* 分布view的位置
* @param view 需要分布的view
* @param mPoint 位置点
*/
private void layoutChildView(View view, Point mPoint) {
int x = 0;
int y = 0;
int measuredWidth = view.getMeasuredWidth();
int measuredHeight = view.getMeasuredHeight();
//计算出 绘制的
int left = mPoint.x - measuredWidth / 2;
int top = mPoint.y - measuredHeight / 2;
int right = mPoint.x + measuredWidth / 2;
int bottom = mPoint.y + measuredHeight / 2;
if(left < 0) {
left = 0;
right = left + measuredWidth;
x = right / 2;
}
if(top < 0) {
top = 0;
bottom = top + measuredHeight;
y = bottom /2;
}
if(right > viewWidth) {
right = viewWidth;
left = viewWidth - measuredWidth;
x = (right + left) /2;
}
if(bottom > viewHeight) {
bottom = viewHeight;
top = bottom - measuredHeight;
y = (bottom + top) /2;
}
view.layout(left, top, right, bottom);
// if(view.getId() == R.id.tv_point) {
//// if(x != 0 && y != 0) {
//// mPoint.set(x, y);
//// }
// }else {
// if(x != 0 && y != 0) {
// mPoint.set(x, y);
// }
// }
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int pointRadius = 0;
int backRadius = 0;
int childCount = getChildCount();
for(int i = 0; i < childCount ; i++) {
View view = getChildAt(i);
if(isOnLayout && isShow) {
if(view.getId() == R.id.tv_point) {
layoutChildView(view, mPoint);
if(pointRadius == 0) {
pointRadius = view.getWidth();
}
}else {
layoutChildView(view, backGroundPoint);
if(backRadius == 0) {
backRadius = view.getWidth();
}
}
}else {
//手离开屏幕或者第一次的时候,不显示其子View
view.layout(-100,-100,-1,-1);
}
}
if(pointDistance == 0) {
if(pointRadius != 0 && backRadius != 0) {
// pointDistance = (backRadius - pointRadius) /2;
pointDistance = backRadius /2;
}
}
}
public void setModel(int model) {
this.model = model;
}
/**
* 设置轨迹球的监听
* @param mRudderViewListener 轨迹球的监听
*/
public void setRudderViewListener(RudderViewListener mRudderViewListener) {
this.mRudderViewListener = mRudderViewListener;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK){
case MotionEvent.ACTION_DOWN:
if(!isOnLayout) isOnLayout = true;
backGroundPoint.set((int) event.getX(), (int) event.getY());
mPoint.set(backGroundPoint.x, backGroundPoint.y);
requestLayout();
break;
case MotionEvent.ACTION_MOVE:
if(!isOnLayout) isOnLayout = true;
calculateInDontMoveBackPoint((int) event.getX(), (int) event.getY());
requestLayout();
break;
case MotionEvent.ACTION_UP:
if(isOnLayout) isOnLayout = false;
requestLayout();
break;
}
notifyListener(event.getAction());
return true;
}
@Override
public void setVisibility(int visibility) {
isShow = visibility != View.GONE;
requestLayout();
}
/**
* 计算背景点和手指移动点的显示位置(底部背景不动)
*/
private void calculateInDontMoveBackPoint(int x, int y) {
int yDistance = y - backGroundPoint.y;
int xDistance = x - backGroundPoint.x;
int offsetX = Math.abs(xDistance);
int offsetY = Math.abs(yDistance);
if (offsetX * offsetX + offsetY * offsetY > pointDistance * pointDistance) {
if(offsetX == 0) {
mPoint.y = yDistance > 0 ? backGroundPoint.y + pointDistance : backGroundPoint.y - pointDistance;
} else
if(offsetY == 0) {
mPoint.x = xDistance > 0 ? backGroundPoint.x + pointDistance : backGroundPoint.x - pointDistance;
}
else {
float ver = (float)offsetY / (float)offsetX;
double calculateX = Math.sqrt(pointDistance * pointDistance / (ver * ver + 1));
double calculateY = calculateX * ver;
if(x > backGroundPoint.x ) mPoint.x = backGroundPoint.x + (int)calculateX;
else mPoint.x = backGroundPoint.x - (int)calculateX;
if(y > backGroundPoint.y ) mPoint.y = backGroundPoint.y + (int)calculateY;
else mPoint.y = backGroundPoint.y - (int)calculateY;
}
}else {
mPoint.set(x, y);
}
}
/**
* 计算背景点个轨迹球的位置
*/
private void calculateInMoveBackPoint(int x, int y) {
if(model == MODEL_LEFT_RIGHT) {
mPoint.set(x, mPoint.y);
}else if(model == MODEL_UP_DOWN) {
mPoint.set(mPoint.x, y);
}else {
mPoint.set(x, y);
}
int yDistance = mPoint.y - backGroundPoint.y;
int offsetX = Math.abs(mPoint.x - backGroundPoint.x);
int offsetY = Math.abs(yDistance);
if (offsetX * offsetX + offsetY * offsetY > pointDistance * pointDistance) {
if(offsetX == 0) {
backGroundPoint.y = yDistance > 0 ? mPoint.y - pointDistance : mPoint.y + pointDistance;
}else {
float ver = (float)offsetY / (float)offsetX;
double calculateX = Math.sqrt(pointDistance * pointDistance / (ver * ver + 1));
double calculateY = calculateX * ver;
if(calculateX > 1 ) {
if(mPoint.x > backGroundPoint.x ) backGroundPoint.x = mPoint.x - (int)calculateX;
else backGroundPoint.x = mPoint.x + (int)calculateX;
}
if(calculateY > 1) {
if(mPoint.y > backGroundPoint.y ) backGroundPoint.y = mPoint.y - (int)calculateY;
else backGroundPoint.y = mPoint.y + (int)calculateY;
}
}
}
}
/**
* 通知监听器时轨迹器位置发生了裱花
* @param mAction touch时间的动作(按下,移动,抬起)
*/
private void notifyListener(int mAction) {
if(mRudderViewListener == null) return;
int distanceX = mPoint.x - backGroundPoint.x;
int distanceY = mPoint.y - backGroundPoint.y;
int offsetX = Math.abs(distanceX);
int offsetY = Math.abs(distanceY);
if(pointDistance == 0) return;
int distance = (distanceX * distanceX + distanceY * distanceY) * 100 / (pointDistance * pointDistance);
if(offsetX > offsetY) {
//左右方向
if(distanceX > 0 ) {
//右
mRudderViewListener.onSteeringWheelChanged(this, RudderViewListener.DIRECTION_RIGHT,distance, mAction);
}else if(distanceX < 0) {
//左
mRudderViewListener.onSteeringWheelChanged(this, RudderViewListener.DIRECTION_LEFT,distance , mAction);
}
}else if(offsetX < offsetY) {
//上下方向
if(distanceY > 0 ) {
//下
mRudderViewListener.onSteeringWheelChanged(this, RudderViewListener.DIRECTION_DOWN,distance, mAction);
}else if(distanceY < 0) {
//上
mRudderViewListener.onSteeringWheelChanged(this, RudderViewListener.DIRECTION_UP,distance, mAction);
}
}else if(offsetX == offsetY) {
//斜对角方向
if(distanceX > 0 && distanceY < 0) {
//右上
mRudderViewListener.onSteeringWheelChanged(this, RudderViewListener.DIRECTION_UP_RIGHT,distance, mAction);
}
if(distanceX > 0 && distanceY > 0) {
//右下
mRudderViewListener.onSteeringWheelChanged(this, RudderViewListener.DIRECTION_DOWN_RIGHT,distance, mAction);
}
if(distanceX < 0 && distanceY < 0) {
//左上
mRudderViewListener.onSteeringWheelChanged(this, RudderViewListener.DIRECTION_LEFT_DOWN,distance, mAction);
}
if(distanceX < 0 && distanceY > 0) {
//左下
mRudderViewListener.onSteeringWheelChanged(this, RudderViewListener.DIRECTION_LEFT_UP,distance, mAction);
}
}
}
/**
* 游戏摇杆的位置监听
*/
public interface RudderViewListener {
int DIRECTION_UP = 0;
int DIRECTION_UP_RIGHT = 1;
int DIRECTION_RIGHT = 2;
int DIRECTION_DOWN_RIGHT = 3;
int DIRECTION_DOWN = 4;
int DIRECTION_LEFT_DOWN = 5;
int DIRECTION_LEFT = 6;
int DIRECTION_LEFT_UP = 7;
/**
* 方向监听
* @param direction 方向变化
* @param distance 距离变化 最大值为100
*/
void onSteeringWheelChanged(RudderView view, int direction, int distance, int action);
}
}
自定义遥感控件
最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
- 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
- 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
- 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
推荐阅读更多精彩内容
- 转载请注明出处:http://blog.csdn.net/linglongxin24/article/detail...
- 在上篇中,我与大家分享了关于如何进行*.lrc歌词文件的解析,以及将解析完成后的歌词展示在镶嵌在ScrollVie...
- 异常情况下Activity的生命周期 内存不足、系统参数改变(比如:屏幕旋转)、各种国产管家卫士(百度卫士、360...