这篇文章我们就来探讨另一种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(); } |
综上所诉,就已经实现了一个摇晃刷新功能。