zoukankan      html  css  js  c++  java
  • 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/

  • 相关阅读:
    bootstrap-select 下拉多选组件
    Spring Boot学习笔记----POI(Excel导入导出)
    Spring boot 导出Excel
    drf 关键配置
    VCL界面开发工具—DevExpress VCL控件全新发布v19.2.6
    Web界面开发工具!Kendo UI for jQuery数据管理之网格列宽
    WPF应用界面开发技巧放送!DevExpress Breadcrumb控件
    Winforms平台界面开发技巧,如何快速掌握Filter Editor(二)
    ASP.NET Core界面开发,DevExpress v19.2增强富文本编辑器功能
    VCL界面开发工具!DevExpress VCL v19.2.5全新出发
  • 原文地址:https://www.cnblogs.com/huanyi0723/p/4826237.html
Copyright © 2011-2022 走看看