自定义遥感控件

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);
    }
}

你可能感兴趣的:(自定义遥感控件)