做遊戲的時候,一般都要使用到多種多樣的傳感器,以實現比較豐富的UI 互動,比如檢測手機的晃動。
如何檢測手機的搖晃和搖晃程度呢?
找了些資料,並加以改進,將此功能封裝成類(ShakeDetector),方便今後使用。
http://blog.csdn.net/ZhengZhiRen/archive/2010/10/09/5930451.aspx
搖晃檢測基於加速傳感器(Sensor.TYPE_ACCELEROMETER)。
由於重力的存在,當手機靜止放於桌面時,加速傳感器也是有加速度的。
所以,僅通過是否有加速度來判斷搖晃是不行的。
那麼,判斷加速度的變化吧。。。
在一個較短的時間間隔求出加速度的差值,跟一個指定的閾值比較,如果差值大於閾值,則認爲是搖晃發生了。
ClingMarks的方法將x、y、z方向的加速度差值簡單的加起來,我認爲不是很準確。
加速度是向量,求差應該是各方向的差值平方後相加,再開方。(數學忘光了,沒記錯吧。。。)
代碼
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 = 3000;
- 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();
- }
// mListenters.add(XXXOnShakeListener); 如果有多個listenter則使用 - }
- /**
- * 停止搖晃檢測
- */
- 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(); //如果前面沒有加入OnShakeListener則需使直接調用自定義的方法或語句 eg: XXXXActivity.this.onShake();
- }
- }
- /**
- * 當搖晃事件發生時,通知所有的listener
- */
- private void notifyListeners() {
- for (OnShakeListener listener : mListeners) {
- listener.onShake();
- }
- }
- }