溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Android自定義控件如何實現方向盤效果

發(fā)布時間:2020-08-03 09:26:13 來源:億速云 閱讀:175 作者:小豬 欄目:移動開發(fā)

小編這次要給大家分享的是Android自定義控件如何實現方向盤效果,文章內容豐富,感興趣的小伙伴可以來了解一下,希望大家閱讀完這篇文章之后能夠有所收獲。

在很多開發(fā)中,為了界面更加的友好,在自定義View的基礎上,開發(fā)者會開發(fā)出各種各樣的自定義控件來滿足實際開發(fā)需要,其中有一種”方向盤”的控件在實際開發(fā)中非常常見,便于用戶進行一些實際性的方向控制。

在復習參考了許多自定義控件的基礎上,我實現了一個最最基本的方向盤空間,并且可以根據方向做出相應的反應。話不多說,先看看效果。

做的有點丑,大家可以看看實際原理,后期再優(yōu)化具體“方向盤”.

Android自定義控件如何實現方向盤效果

空間下面的幾行字是我為了確定方向所寫的一些參數,基本思想就是在方向盤的中心確定一個坐標軸,根據中間這個小圓的和中心點的距離與方向確定所處的方向。在手離開屏幕以后,小圓回到原點。

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

具體是怎么實現的呢??

來我們一起看看代碼,看完一目了然。

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;  //整個控件的大圓,及小紅點的活動范圍


  //自定義的接口用于監(jiān)聽處理控件的觸摸事件
  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="零態(tài)" />
  </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中引用實例并處理相應監(jiān)聽事件。

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


    //下面的監(jiān)聽器代碼最為重要?。。。。。。?!
    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.關于控件的實現原理和思想在代碼與注釋中已經詳細標記

看完這篇關于Android自定義控件如何實現方向盤效果的文章,如果覺得文章內容寫得不錯的話,可以把它分享出去給更多人看到。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI