Android 摇一摇之双甩功能

Android 摇一摇之双甩功能

最近做一个摇一摇的功能 网上相关代码很多 但是这次的需求有点奇葩 要求是摇两次才生效

看起来好像很简单 但真正要做遇到的问题还是很多 时间限制 机型灵敏性 摇动的方式 弄了一周多 做出的效果算一般吧

原理介绍

其实就是加速度传感器的使用 开发传感器应用的步骤如下

1 调用Context的getSystemService(Context.SENSOR_SERVICE)方法获取 SensorManager对象

SensorManager代表系统的传感器管理服务2 调用SensorManager的getDefaultSensor(int type)获取指定类型的传感器

3 在Activity的onResume()方法中调用SensorManager的registerListener()为指定传感器注册监听

程序通过实现监听器可获取传感器传回来的数据

registerListener(SensorEventListener listener, Sensor sensor, int rateUs)

listener 监听传感器事件的监听器 该监听需要实现SensorEventListener接口

sensor 传感器对象

rateUs 获取传感器数据的频率 支持4个频率值

SENSOR_DELAY_FASTEST 最快 延迟小 耗电

SENSOR_DELAY_GAME 适合游戏

SENSOR_DELAY_UI 正常频率

SENSOR_DELAY_NORMAL 省电 延迟大

上代码

public class AccelerometerTest extends Activity
    implements SensorEventListener
{
    // 定义系统的Sensor管理器
    SensorManager sensorManager;
    EditText etTxt1;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        // 获取程序界面上的文本框组件
        etTxt1 = (EditText) findViewById(R.id.txt1);
        // 获取系统的传感器管理服务
        sensorManager = (SensorManager) getSystemService(
            Context.SENSOR_SERVICE);  //
    }

    @Override
    protected void onResume()
    {
        super.onResume();
        // 为系统的加速度传感器注册监听器
        sensorManager.registerListener(this,
            sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
            SensorManager.SENSOR_DELAY_GAME);  //
    }

    @Override
    protected void onStop()
    {
        // 取消注册
        sensorManager.unregisterListener(this);
        super.onStop();
    }

    // 以下是实现SensorEventListener接口必须实现的方法
    // 当传感器的值发生改变时回调该方法
    @Override
    public void onSensorChanged(SensorEvent event)
    {
        float[] values = event.values;
        StringBuilder sb = new StringBuilder();
        sb.append("X方向上的加速度:");
        sb.append(values[0]);
        sb.append("
Y方向上的加速度:");
        sb.append(values[1]);
        sb.append("
Z方向上的加速度:");
        sb.append(values[2]);
        etTxt1.setText(sb.toString());
    }

    // 当传感器精度改变时回调该方法。
    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy)
    {
    }
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
<TextView
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="@string/tip" />
<EditText
    android:id="@+id/txt1"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:editable="false"
    android:cursorVisible="false" />
</LinearLayout>

返回的三个值分别代表在X Y Z三个方向上的加速度

X轴沿屏幕向左

Y轴沿屏幕向上

Z轴垂直于屏幕向里

下面给出双甩功能的代码 主要原理是判断速度阀值 并加入时间限制

MainActivity

public class MainActivity extends Activity{

  EditText etTxt1;
  private ShakeListener mShakeListener;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    etTxt1 = (EditText) findViewById(R.id.txt1);
  }

  @Override
  protected void onResume() {
    super.onResume();
    //注册
    mShakeListener = new ShakeListener(this);
    mShakeListener.setOnShakeListener(new ShakeListener.OnShakeListener() {
      
      @Override
      public void onShake() {
        Log.i("TAG", "震动震动震动震动震动震动震动震动震动震动震动震动震动震动震动震动震动震动震动震动");
        Vibrator vVi = (Vibrator)getSystemService(Service.VIBRATOR_SERVICE);
        vVi.vibrate(400);
        
        StringBuilder sb = new StringBuilder();
        sb.append(mShakeListener.getSpeed());
        etTxt1.setText(sb.toString());
      }
    });

  }

  @Override
  protected void onStop() {
    super.onStop();
    // 取消注册
    mShakeListener.stop();
  }


}

ShakeListener

public class ShakeListener implements SensorEventListener {
  
  private Context mContext;
  private Sensor sensor; // 传感器
  private SensorManager sensorManager; // 传感器管理器
  private OnShakeListener onShakeListener;

  // 手机上一个位置时重力感应坐标
  private float lastX;
  private float lastY;
  private float lastZ;
  private double speed;

  private long lastUpdateTime;
  int UPTATE_INTERVAL_TIME = 70;// 两次检测的时间间隔
  int SPEED_SHRESHOLD = 3000;// 速度阈值

  // 双甩
  int count = 0;
  int timeSlice = 0; // 时间片
  
  final int GET_SUCC = 0;
  Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
      super.handleMessage(msg);
      switch (msg.what) {
        case GET_SUCC:
          count = 0;
          timeSlice = 0;
          break;
      }
    }
  };

  public ShakeListener(Context mContext) {
    super();
    this.mContext = mContext;
    start();
  }
  
  //开始
  public void start() {
    // 获得传感器管理器
    sensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
    if (sensorManager != null) {
      // 获得重力传感器
      sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
    }
    // 注册
    if (sensor != null) {
      sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_FASTEST);
    }

  }
  //停止
  public void stop() {
    sensorManager.unregisterListener(this);
  }

  // 设置重力感应监听器
  public void setOnShakeListener(OnShakeListener listener) {
    onShakeListener = listener;
  }

  @Override
  public void onSensorChanged(SensorEvent event) {
    
    long currentUpdateTime = System.currentTimeMillis(); // 现在检测时间
    long timeInterval = currentUpdateTime - lastUpdateTime; // 两次检测的时间间隔
    if (timeInterval < UPTATE_INTERVAL_TIME) // 判断是否达到了检测时间间隔
      return;
    lastUpdateTime = currentUpdateTime; // 现在的时间变成last时间

    float[] values = event.values;
    // 获得x,y,z坐标
    float x = event.values[0];
    float y = event.values[1];
    float z = event.values[2];

    // 获得x,y,z的变化值
    float deltaX = x - lastX;
    float deltaY = y - lastY;
    float deltaZ = z - lastZ;

    // 将现在的坐标变成last坐标
    lastX = x;
    lastY = y;
    lastZ = z;

    speed = Math.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ) * 10000 / timeInterval;
    Log.i("TAG", "speed" + speed);
    Log.i("TAG", "count---" + count);
    Log.i("TAG", "timeSlice---" + timeSlice);

    //限制两次摇动在1S的时间内
    if (count == 1) {
      timeSlice++;
      if (timeSlice * UPTATE_INTERVAL_TIME > 1000) {
        count = 0;
        timeSlice = 0;
      }
    }

    if (speed > SPEED_SHRESHOLD) {
      Log.i("TAG",  " 摇一摇---------------------------------------------------------------------------------------------------摇一摇");
      
      count++;

      if (count == 2) {
        
        count = 0;
        //如果两次触发在300毫秒之内 只能算一次
        if (timeSlice * UPTATE_INTERVAL_TIME < 300) {
          count = 1;
        } else {
          onShakeListener.onShake();
          
          handler.removeMessages(GET_SUCC);
          handler.sendEmptyMessageDelayed(GET_SUCC, 300);
        }
        
        timeSlice = 0;
      }
    }

  }

  @Override
  public void onAccuracyChanged(Sensor sensor, int accuracy) {
    
  }
  
  public interface OnShakeListener {
    public void onShake();
  }


  public double getSpeed() {
    return speed;
  }
  
}

activity_main

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.accelerometertest.MainActivity" >
    
    <EditText 
        android:id="@+id/txt1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />

</RelativeLayout>

加速度传感器Demo https://github.com/huanyi0723/Accelerometer/

双甩功能Demo https://github.com/huanyi0723/AccelerometerTest/

原文地址:https://www.cnblogs.com/huanyi0723/p/4826237.html