android 实现甩屏

最近要实现一个手机摇晃的功能。

想到这个功能可能应用广泛,比如摇晃手机换图片、截图、洗牌、结束当前程序等,所以找了些资料,并加以改进,将此功能封装成类(ShakeDetector),方便今后使用。

摇晃检测基于加速传感器(Sensor.TYPE_ACCELEROMETER)。

由于重力的存在,当手机静止放于桌面时,加速传感器也是有加速度的。所以,仅通过是否有加速度来判断摇晃是不行的。

那么,判断加速度的变化吧。在一个较短的时间间隔求出加速度的差值,跟一个指定的阈值比较,如果差值大于阈值,则认为是摇晃发生了。ClingMarks的方法将x、y、z方向的加速度差值简单的加起来,我认为不是很准确。

加速度是向量,求差应该是各方向的差值平方后相加,再开方。(数学忘光了,应该没记错吧。)

所以就有了这行代码:

?
1
float delta = FloatMath.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ) / diffTime * 10000 ;

功能封装成类ShakeDetector,实现了SensorEventListener接口,用于向系统注册传感器事件的Listener。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package zhengzhiren.android.hardware;
  
import java.util.ArrayList;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.util.FloatMath;
  
/**
  * 用于检测手机晃动
 
  * @author 郑智仁
  */
public class ShakeDetector implements SensorEventListener {
     /**
      * 检测的时间间隔
      */
     static final int UPDATE_INTERVAL = 100 ;
     /**
      * 上一次检测的时间
      */
     long mLastUpdateTime;
     /**
      * 上一次检测时,加速度在x、y、z方向上的分量,用于和当前加速度比较求差。
      */
     float mLastX, mLastY, mLastZ;
     Context mContext;
     SensorManager mSensorManager;
     ArrayList<OnShakeListener> mListeners;
     /**
      * 摇晃检测阈值,决定了对摇晃的敏感程度,越小越敏感。
      */
     public int shakeThreshold = 5000 ;
  
     public ShakeDetector(Context context) {
         mContext = context;
         mSensorManager = (SensorManager) context
                 .getSystemService(Context.SENSOR_SERVICE);
         mListeners = new ArrayList<OnShakeListener>();
     }
  
     /**
      * 当摇晃事件发生时,接收通知
      */
     public interface OnShakeListener {
         /**
          * 当手机晃动时被调用
          */
         void onShake();
     }
  
     /**
      * 注册OnShakeListener,当摇晃时接收通知
     
      * @param listener
      */
     public void registerOnShakeListener(OnShakeListener listener) {
         if (mListeners.contains(listener))
             return ;
         mListeners.add(listener);
     }
  
     /**
      * 移除已经注册的OnShakeListener
     
      * @param listener
      */
     public void unregisterOnShakeListener(OnShakeListener listener) {
         mListeners.remove(listener);
     }
  
     /**
      * 启动摇晃检测
      */
     public void start() {
         if (mSensorManager == null ) {
             throw new UnsupportedOperationException();
         }
         Sensor sensor = mSensorManager
                 .getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
         if (sensor == null ) {
             throw new UnsupportedOperationException();
         }
         boolean success = mSensorManager.registerListener( this , sensor,
                 SensorManager.SENSOR_DELAY_GAME);
         if (!success) {
             throw new UnsupportedOperationException();
         }
     }
  
     /**
      * 停止摇晃检测
      */
     public void stop() {
         if (mSensorManager != null )
             mSensorManager.unregisterListener( this );
     }
  
     @Override
     public void onAccuracyChanged(Sensor sensor, int accuracy) {
         // TODO Auto-generated method stub
     }
  
     @Override
     public void onSensorChanged(SensorEvent event) {
         long currentTime = System.currentTimeMillis();
         long diffTime = currentTime - mLastUpdateTime;
         if (diffTime < UPDATE_INTERVAL)
             return ;
         mLastUpdateTime = currentTime;
         float x = event.values[ 0 ];
         float y = event.values[ 1 ];
         float z = event.values[ 2 ];
         float deltaX = x - mLastX;
         float deltaY = y - mLastY;
         float deltaZ = z - mLastZ;
         mLastX = x;
         mLastY = y;
         mLastZ = z;
         float delta = FloatMath.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ
                 * deltaZ)
                 / diffTime * 10000 ;
         if (delta > shakeThreshold) { // 当加速度的差值大于指定的阈值,认为这是一个摇晃
             this .notifyListeners();
         }
     }
  
     /**
      * 当摇晃事件发生时,通知所有的listener
      */
     private void notifyListeners() {
         for (OnShakeListener listener : mListeners) {
             listener.onShake();
         }
     }
}

如何使用ShakeDetector

1、new一个ShakeDetector
2、调用mShakeDetector.registerOnShakeListener()注册一个OnShakeListener
3、在OnShakeListener的onShake函数中,处理摇晃事件
4、调用mShakeDetector.start()启动摇晃检测
5、mShakeDetector.stop()用于停止摇晃检测

参考资料:
http://www.clingmarks.com/?p=25
http://android.hlidskialf.com/blog/code/android-shake-detection-listener

 

注:此文转载

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值