這篇文章我們就來探討另一種App重新整理的方式,就叫“搖晃重新整理”吧。眾所周知,下拉重新整理方式已經有很多App在用了,只要手指在螢幕上滑動,就可以重新整理介面了。
儘管下拉重新整理方式很實用,不過我們還可以使用別的方式來重新整理介面,也就是基於智慧手機感測器的搖晃重新整理。這樣就不用滑動手指,只要搖晃手機就可以重新整理介面:
實現方法
為了實現搖晃重新整理功能,這裡需要使用重力加速器(Accelerometer
),若需要了解更多關於怎麼使用重力加速器的方式請看這裡
首先,需要保證在搖晃重新整理或者移動手機的時候不會發生誤操作,這裡需要實現對感測器的控制,保證捕抓到的是使用者想要的搖動操作。另外,我們在實現這個邏輯操作的時候需要和UI的程式碼分離,建議不要把介面邏輯程式碼和其它的程式碼混雜在一起,把它獨立出來方便重用。所以首先新建一個ShakeEventManager
類,這個類需要對感測器事件進行監聽:
1 2 3 4 |
; html-script: false ] public class ShakeEventManager implements SensorEventListener { .. } |
為了監聽感測器,這裡實現了SensorEventListener
介面,然後就要操作重力加速度感測器,把我們寫的這個類註冊成事件監聽器:
1 2 3 4 5 6 |
; html-script: false ] public void init(Context ctx) { sManager = (SensorManager) ctx.getSystemService(Context.SENSOR_SERVICE); s = sManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); register(); } |
接著實現register()
方法:
1 2 3 4 |
; html-script: false ] public void register() { sManager.registerListener(this, s, SensorManager.SENSOR_DELAY_NORMAL); } |
在觸發重新整理事件的時候,需要對一些條件進行檢測,以保證使用者是有意在搖動手機:
- 加速度必須大於某個臨界值;
- 必須出發一些固定的加速感測器事件;
- 這些事件發生的時間必須在一定的範圍內。
這裡把這個實現邏輯程式碼寫在onSensorChanged
方法裡,這個方法在加速器的值有效的時候都會被呼叫。第一步要計算這個加速度的值。這裡還需要知道三個座標的最大加速度值,然後減去重力的值在三個方向上的分量。像Android官方教程文件中說明的那樣,首先進行一層過濾,把重力的分量減掉,然後在進行另外的座標分量處理:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
; html-script: false ] private float calcMaxAcceleration(SensorEvent event) { gravity[0] = calcGravityForce(event.values[0], 0); gravity[1] = calcGravityForce(event.values[1], 1); gravity[2] = calcGravityForce(event.values[2], 2); float accX = event.values[0] - gravity[0]; float accY = event.values[1] - gravity[1]; float accZ = event.values[2] - gravity[2]; float max1 = Math.max(accX, accY); return Math.max(max1, accZ); } |
看看calcGravityForce
這個方法:
1 2 3 4 5 |
; html-script: false ] // Low pass filter private float calcGravityForce(float currentVal, int index) { return ALPHA * gravity[index] + (1 - ALPHA) * currentVal; } |
在知道最大的加速度值後,這裡實現了之前的判斷邏輯:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
; html-script: false ] @Override public void onSensorChanged(SensorEvent sensorEvent) { float maxAcc = calcMaxAcceleration(sensorEvent); Log.d("SwA", "Max Acc ["+maxAcc+"]"); if (maxAcc >= MOV_THRESHOLD) { if (counter == 0) { counter++; firstMovTime = System.currentTimeMillis(); Log.d("SwA", "First mov.."); } else { long now = System.currentTimeMillis(); if ((now - firstMovTime) = MOV_COUNTS) if (listener != null) listener.onShake(); } } } |
從程式碼看,第三行計算了加速度的值然後與一個臨界值作對比(第五行)。如果是第一次搖動,就儲存當前時間,看看在一定的時間內其它的事件有沒有觸發。如果所有條件都滿足了,就會呼叫介面中的回撥方法:
1 2 3 4 |
; html-script: false ] public static interface ShakeListener { public void onShake(); } |
測試App
以上已經實現了搖動事件管理,然後我們需要新建一個簡單的App來使用它。只需新建一個帶有一個ListView
的簡單Activity
,然後讓它搖動的時候可以重新整理ListView
:
1 2 3 4 5 6 7 8 9 |
; html-script: false ] public class MainActivity extends ActionBarActivity implements ShakeEventManager.ShakeListener { .... @Override public void onShake() { // We update the ListView } } |
可以看到,在第五行的時候介面重新整理了,因為在使用者搖動手機的時候,這個方法已經被呼叫。
最後需要考慮一些問題:在App停止的時候,我們需要登出這個監聽器,因為一直監聽事件會很費電。另外在App恢復執行的時候,需要再重新註冊這個監聽器:
1 2 3 4 5 6 7 8 9 10 11 12 |
; html-script: false ] Override protected void onResume() { super.onResume(); sd.register(); } @Override protected void onPause() { super.onPause(); sd.deregister(); } |
綜上所訴,就已經實現了一個搖晃重新整理功能。