自定义控件----方向盘的基本实现

在很多开发中,为了界面更加的友好,在自定义View的基础上,开发者会开发出各种各样的自定义控件来满足实际开发需要,其中有一种”方向盘”的控件在实际开发中非常常见,便于用户进行一些实际性的方向控制。

在复习参考了许多自定义控件的基础上,我实现了一个最最基本的方向盘空间,并且可以根据方向做出相应的反应。话不多说,先看看效果。


做的有点丑,大家可以看看实际原理,后期再优化具体“方向盘”.

自定义控件----方向盘的基本实现_第1张图片

空间下面的几行字是我为了确定方向所写的一些参数,基本思想就是在方向盘的中心确定一个坐标轴,根据中间这个小圆的和中心点的距离与方向确定所处的方向。在手离开屏幕以后,小圆回到原点。


一言不合就放代码~~~~

具体是怎么实现的呢??
来我们一起看看代码,看完一目了然。


package com.sshhsun.socketudp.utils;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

public class MyWheel extends View implements Runnable,View.OnTouchListener {

    public MyWheel(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
    }

    //先定义一些绘图要用的基本参数
    public static final int BOTTOM = 7;
    public static final int BOTTOM_LEFT = 8;
    public static final long DEFAULT_LOOP_INTERVAL = 100L;
    public static final int FRONT = 3;
    public static final int FRONT_RIGHT = 4;
    public static final int LEFT = 1;
    public static final int LEFT_FRONT = 2;
    public static final int RIGHT = 5;
    public static final int RIGHT_BOTTOM = 6;
    private final double RAD = 57.295779500000002D;
    private Paint button;
    private int buttonRadius;
    public double centerX = 0.0D;
    public double centerY = 0.0D;
    private Paint horizontalLine;
    private int joystickRadius;
    private int lastAngle = 0;
    private int lastPower = 0;
    private long loopInterval = 100L;
    private Paint mainCircle;   //整个控件的大圆,及小红点的活动范围


    //自定义的接口用于监听处理控件的触摸事件
    private OnMyWheelMoveListener onmywheelMoveListener;
    private Paint secondaryCircle;//第二个内圆,小红圆超过后开始处理角度
    private Thread thread = new Thread(this);
    private Paint verticalLine;
    private int xPosition = 0;
    private int yPosition = 0;
    private static final String tag="MyWheel"; 

    public MyWheel(Context paramContext, AttributeSet paramAttributeSet) {
        super(paramContext, paramAttributeSet);
        initMyWheel();   //好吧,我知道MyWheel这个名字有点太随便了........
    }

    public MyWheel(Context paramContext, AttributeSet paramAttributeSet,
            int paramInt) {
        super(paramContext, paramAttributeSet, paramInt);
        initMyWheel();
    }

    //根据所处的位置得到角度
    private int getAngle() {
        if (this.xPosition > this.centerX) {
            if (this.yPosition < this.centerY) {
                int m = (int) (90.0D + 57.295779500000002D * Math
                        .atan((this.yPosition - this.centerY)
                                / (this.xPosition - this.centerX)));
                this.lastAngle = m;
                return m;
            }
            if (this.yPosition > this.centerY) {
                int k = 90 + (int) (57.295779500000002D * Math
                        .atan((this.yPosition - this.centerY)
                                / (this.xPosition - this.centerX)));
                this.lastAngle = k;
                return k;
            }
            this.lastAngle = 90;
            return 90;
        }
        if (this.xPosition < this.centerX) {
            if (this.yPosition < this.centerY) {
                int j = (int) (57.295779500000002D * Math
                        .atan((this.yPosition - this.centerY)
                                / (this.xPosition - this.centerX)) - 90.0D);
                this.lastAngle = j;
                return j;
            }
            if (this.yPosition > this.centerY) {
                int i = -90
                        + (int) (57.295779500000002D * Math
                                .atan((this.yPosition - this.centerY)
                                        / (this.xPosition - this.centerX)));
                this.lastAngle = i;
                return i;
            }
            this.lastAngle = -90;
            return -90;
        }
        if (this.yPosition <= this.centerY) {
            this.lastAngle = 0;
            return 0;
        }
        if (this.lastAngle < 0) {
            this.lastAngle = -180;
            return -180;
        }
        this.lastAngle = 180;
        return 180;
    }

    //根据红色圆的距离和角度得到方向
    private int getDirection() {
        int k;
        int j = 0;
        int i;
        if ((this.lastPower == 0) && (this.lastAngle == 0)) {
            k = 0;
            return k;
        }

        if (this.lastAngle <= 0)
            j = 90 + -1 * this.lastAngle;
        while (true) {
            k = 1 + (j + 22) / 45;
            if (k <= 8) {
                break;
            }

            if (this.lastAngle <= 90) {
                j = 90 - this.lastAngle;
                continue;
            }
            j = 360 - (-90 + this.lastAngle);
        }
        return k;
    }

    //得到红色圆与中心的距离
    private int getPower() {
        return (this.lastPower=(int) (100.0D * Math.sqrt((this.xPosition - this.centerX)
                * (this.xPosition - this.centerX)
                + (this.yPosition - this.centerY)
                * (this.yPosition - this.centerY)) / this.joystickRadius));
    }

    private int measure(int paramInt) {
        int i = View.MeasureSpec.getMode(paramInt);
        int j = View.MeasureSpec.getSize(paramInt);
        if (i == 0)
            return 200;
        return j;
    }


    //初始化一些基本参数
    protected void initMyWheel() {
        this.mainCircle = new Paint(1);
        this.mainCircle.setColor(Color.BLUE);
        this.mainCircle.setStrokeWidth(3.0f);
        this.mainCircle.setStyle(Paint.Style.STROKE);
        this.secondaryCircle = new Paint();
        this.secondaryCircle.setColor(-16711936);
        this.secondaryCircle.setStrokeWidth(3.0f);
        this.secondaryCircle.setStyle(Paint.Style.STROKE);
        this.verticalLine = new Paint();
        this.verticalLine.setStrokeWidth(5.0F);
        this.verticalLine.setColor(-65536);
        this.horizontalLine = new Paint();
        this.horizontalLine.setStrokeWidth(2.0F);
        this.horizontalLine.setColor(-16777216);
        this.button = new Paint(1);
        this.button.setColor(Color.RED);
        this.button.setStyle(Paint.Style.FILL);
    }

    //初始化以后绘制方向盘。
    protected void onDraw(Canvas paramCanvas) {
        this.centerX = (getWidth() / 2);
        this.centerY = (getHeight() / 2);
        paramCanvas.drawCircle((int) this.centerX, (int) this.centerY,
                this.joystickRadius, this.mainCircle);
        paramCanvas.drawCircle((int) this.centerX, (int) this.centerY,
                this.joystickRadius / 2, this.secondaryCircle);
        paramCanvas
                .drawLine((float) this.centerX, (float) this.centerY,
                        (float) this.centerX,
                        (float) (this.centerY - this.joystickRadius),
                        this.verticalLine);
        paramCanvas.drawLine((float) (this.centerX - this.joystickRadius),
                (float) this.centerY,
                (float) (this.centerX + this.joystickRadius),
                (float) this.centerY, this.horizontalLine);
        paramCanvas
                .drawLine((float) this.centerX,
                        (float) (this.centerY + this.joystickRadius),
                        (float) this.centerX, (float) this.centerY,
                        this.horizontalLine);
        paramCanvas.drawCircle(this.xPosition, this.yPosition,
                this.buttonRadius, this.button);
    }

    protected void onFinishInflate() {
    }

    protected void onMeasure(int paramInt1, int paramInt2) {
        int i = Math.min(measure(paramInt1), measure(paramInt2));
        setMeasuredDimension(i, i);
    }

    protected void onSizeChanged(int paramInt1, int paramInt2, int paramInt3,
            int paramInt4) {
        super.onSizeChanged(paramInt1, paramInt2, paramInt3, paramInt4);
        this.xPosition = (getWidth() / 2);
        this.yPosition = (getWidth() / 2);
        int i = Math.min(paramInt1, paramInt2);
        this.buttonRadius = (int) (0.20D * (i / 2));
        this.joystickRadius = (int) (0.75D * (i / 2));
    }

    @Override
    public boolean onTouchEvent(MotionEvent paramMotionEvent) {
        //根据手触碰的坐标决定红色小圆的位置
        this.xPosition = (int) paramMotionEvent.getX();
        this.yPosition = (int) paramMotionEvent.getY();
        double d = Math.sqrt((this.xPosition - this.centerX)
                * (this.xPosition - this.centerX)
                + (this.yPosition - this.centerY)
                * (this.yPosition - this.centerY));
        if (d > this.joystickRadius) {
            this.xPosition = (int) ((this.xPosition - this.centerX)
                    * this.joystickRadius / d + this.centerX);
            this.yPosition = (int) ((this.yPosition - this.centerY)
                    * this.joystickRadius / d + this.centerY);
        }
        invalidate();//再重新绘制
        if (paramMotionEvent.getAction() == 1) {
            this.xPosition = (int) this.centerX;
            this.yPosition = (int) this.centerY;
            this.thread.interrupt();
            if (this.onmywheelMoveListener != null)
                this.onmywheelMoveListener.onValueChanged(getAngle(),
                        getPower());
        }
        if ((this.onmywheelMoveListener != null)
                && (paramMotionEvent.getAction() == 0)) {
            if ((this.thread != null) && (this.thread.isAlive()))
                this.thread.interrupt();
            this.thread = new Thread(this);
            this.thread.start();
            if (this.onmywheelMoveListener != null)
                //自定义接口处理触摸事件
                this.onmywheelMoveListener.onValueChanged(getAngle(),
                        getPower());
        }
        return true;
    }

    @Override
    public void run() {
        while (true) {
            if (Thread.interrupted())
                return;
            post(new Runnable() {
                public void run() {
//                  Log.e(tag, "运行在"+Thread.currentThread().getName()+"线程中");
                    if (MyWheel.this.onmywheelMoveListener != null)
                        MyWheel.this.onmywheelMoveListener.onValueChanged(
                                MyWheel.this.getAngle(),
                                MyWheel.this.getPower());
                }
            });
            try {
                Thread.sleep(this.loopInterval);
            } catch (InterruptedException localInterruptedException) {
            }
        }
    }
    public void setOnMyWheelMoveListener(
            OnMyWheelMoveListener paramOnJoystickMoveListener, long paramLong) {
        this.onmywheelMoveListener = paramOnJoystickMoveListener;
        this.loopInterval = paramLong;
    }

    public static abstract interface OnMyWheelMoveListener {
        public abstract void onValueChanged(int paramInt1, int paramInt2);
    }

    @SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        /*处理这个控件的触摸事件*/
        return true;
    }
}

怎么用?下面我给出我的调用实例进行讲解

首先在XML文件中应用。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >

        <Button
            android:id="@+id/simple_rest"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="蹲下" />

        <Button
            android:id="@+id/simple_stand"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="站立" />

        <Button
            android:id="@+id/simple_standinit"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="准备" />

        <Button
            android:id="@+id/simple_sit"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="坐下" />

        <Button
            android:id="@+id/simple_standzero "
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="零态" />
    LinearLayout>

    <com.sshhsun.socketudp.utils.MyWheel
        android:id="@+id/mywheel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/notice"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="这是简单控制界面" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

        <SeekBar
            android:id="@+id/turns"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:minHeight="3dp"
            android:minWidth="260dp"
            android:progress="100" />
    LinearLayout>

LinearLayout>

在一个Fragment中引用实例并处理相应监听事件。

package com.sshhsun.socketudp.fragment;

import android.content.Context;
import android.os.Bundle;
import android.os.Vibrator;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebView.FindListener;
import android.widget.Button;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import android.widget.Toast;

import com.sshhsun.socketudp.R;
import com.sshhsun.socketudp.activity.constant.Constant;
import com.sshhsun.socketudp.utils.MyWheel;
import com.sshhsun.socketudp.utils.MyWheel.OnMyWheelMoveListener;
import com.sshhsun.socketudp.utils.UDPUtil;

public class SimpleFragment extends Fragment implements View.OnClickListener {

    private MyWheel mtwheel;
    private TextView notice;
    private TextView show;
    private String direction = "none";
    private SeekBar seekbar;
    private static final String tag = "SimpleFragment";
    Vibrator vibator;
    private Context context = getActivity();
    private boolean isturn = false;
    private Button stand;
    private Button sit;
    private Button standinit;
    private Button rest;
    private Button standzero;
    private UDPUtil udpUtil;
    private boolean issend = false;
    private boolean isstop = true;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        return initView(inflater, container, savedInstanceState);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        initData();
        initListener();
    }

    public View initView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.frag_simple, null);

        //我的方向盘控件mtwheel
        mtwheel = (MyWheel) view.findViewById(R.id.mywheel);

        //控件下面的提示信息notice,其他控件大家可以忽略.
        notice = (TextView) view.findViewById(R.id.notice);
        seekbar = (SeekBar) view.findViewById(R.id.turns);
        seekbar.setProgress(50);
        stand = (Button) view.findViewById(R.id.simple_stand);
        sit = (Button) view.findViewById(R.id.simple_sit);
        standinit = (Button) view.findViewById(R.id.simple_standinit);
        rest = (Button) view.findViewById(R.id.simple_rest);
        standzero = (Button) view.findViewById(R.id.simple_standzero);
        return view;
    }

    public void initListener() {
        sit.setOnClickListener(this);
        standinit.setOnClickListener(this);
        rest.setOnClickListener(this);
        standzero.setOnClickListener(this);
        stand.setOnClickListener(this);


        //下面的监听器代码最为重要!!!!!!!!
        mtwheel.setOnMyWheelMoveListener(new OnMyWheelMoveListener() {

            @Override
            // paramInt1:角度
            // paramInt2:距离 根据这两个参数可以算出方向盘的方位
            public void onValueChanged(int paramInt1, int paramInt2) {
                boolean isdistance = false;
                if (paramInt2 >= 50) {
                    isdistance = true;
                    int temp = Math.abs(paramInt1);
                    if (paramInt1 >= 0) {
                        if (temp > 50 && temp < 120) {
                            direction = "right";
                            if (!issend) {
                                udpUtil.UdpSend(direction, Constant.port);
                                issend = true;
                                isstop = false;
                            }
                        } else if (temp < 40) {
                            direction = "forward";
                            if (!issend) {
                                udpUtil.UdpSend(direction, Constant.port);
                                issend = true;
                                isstop = false;
                            }
                        } else if (temp > 140) {
                            direction = "back";
                            if (!issend) {
                                udpUtil.UdpSend(direction, Constant.port);
                                issend = true;
                                isstop = false;
                            }
                        } else {
                            direction = "指向不明确";
                            issend = false;
                        }
                    } else {
                        if (temp > 50 && temp < 120) {
                            direction = "left";
                            if (!issend) {
                                udpUtil.UdpSend(direction, Constant.port);
                                issend = true;
                                isstop = false;
                            }
                        } else if (temp < 40) {
                            direction = "forward";
                            if (!issend) {
                                udpUtil.UdpSend(direction, Constant.port);
                                issend = true;
                                isstop = false;
                            }
                        } else if (temp > 140) {
                            direction = "back";
                            if (!issend) {
                                udpUtil.UdpSend(direction, Constant.port);
                                issend = true;
                                isstop = false;
                            }
                        } else {
                            direction = "指向不明确";
                            issend = false;
                        }
                    }
                } else {
                    isdistance = false;
                    direction = "stop";
                    issend = false;
                }
                notice.setText("  getAngle:" + paramInt1 + "\n" + "  getPower:"
                        + paramInt2 + "\n" + "direction:" + direction);

                if (direction.equals("stop") && (!isstop)) {
                    udpUtil.UdpSend(direction, Constant.port);
                    isstop = true;
                }
            }
        }, 100L);
        seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                seekbar.setProgress(50);
                isturn = false;
                String command = "stop";
                udpUtil.UdpSend(command, Constant.port);
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onProgressChanged(SeekBar seekBar, int progress,
                    boolean fromUser) {
                int cucrrent = seekbar.getProgress();
                String command = "hello";
                if (cucrrent < 20) {
                    Toast.makeText(getActivity(), "onProgressChanged" + "左转", 0)
                            .show();
                    if (!isturn) {
                        Log.e(tag, "onProgressChanged" + "左转");
                        command = "turnleft";
                        udpUtil.UdpSend(command, Constant.port);
                        vibator.vibrate(100);
                        isturn = true;
                    }
                } else if (cucrrent > 80) {
                    Toast.makeText(getActivity(), "onProgressChanged" + "右转", 0)
                            .show();
                    if (!isturn) {
                        Log.e(tag, "onProgressChanged" + "右转");
                        command = "turnright";
                        udpUtil.UdpSend(command, Constant.port);
                        vibator.vibrate(100);
                        isturn = true;
                    }
                }
            }
        });

    }

    public void initData() {
        udpUtil = new UDPUtil(Constant.Address);
        vibator = (Vibrator) getActivity().getSystemService(
                Context.VIBRATOR_SERVICE);
        Thread.currentThread().setName(tag);
    }

    public void processClick(View v) {
        String command = "hello";
        switch (v.getId()) {
        case R.id.simple_rest:
            command = "rest";
            break;
        case R.id.simple_sit:
            command = "sit";

            break;
        case R.id.simple_stand:
            command = "stand";

            break;
        case R.id.simple_standinit:
            command = "standinit";

            break;
        case R.id.simple_standzero:
            command = "standzero";

            break;
        default:
            break;
        }
        udpUtil.UdpSend(command, Constant.port);
    }

    @Override
    public void onClick(View v) {
        processClick(v);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        vibator.cancel();
    }
    // @Override
    // public boolean onTouch(View v, MotionEvent event) {
    // if (v.getId() == R.id.turns) {
    // String notice = "";
    // switch (event.getAction()) {
    // case MotionEvent.ACTION_DOWN:
    // notice = "ACTION_DOWN"+event.getX();
    // int process=(int) Math.floor(event.getX()+0.5);
    // seekbar.setProgress(process);
    // break;
    // case MotionEvent.ACTION_UP:
    // notice = "ACTION_UP";
    // break;
    // case MotionEvent.ACTION_CANCEL:
    // notice = "ACTION_CANCEL";
    // break;
    // default:
    // break;
    // }
    // if (!TextUtils.isEmpty(notice)) {
    // Toast.makeText(getActivity(), notice, 0).show();
    // }
    // }
    // return true;
    // }

}





声明一下:

1.上面的控件代码(第一部分代码)可以实际使用
2.第二部分代码演示了控件的使用与处理
3.关于控件的实现原理和思想在代码与注释中已经详细标记

你可能感兴趣的:(andorid学习笔记,技术分享,解决问题。)