這次通過設備的 Sensor 判斷使用者是否有搖晃手機(類似微信的搖一搖功能)
偵測手機搖動狀況
搖晃後更換圖片、震動手機
設定 2秒內只發動一次事件(搖晃過程會一直拿到 Sensor 數據,但不希望因此在短時間內連續震動或換圖)
通過 SensorManager 來獲取 Sensor,Vibrator 來震動手機。
要使用 Sensor 的步驟很簡短,和 system 要到 SensorManager,在要到對應的 sensor.
然後 register Listener 用來接收 sensor 拿到的數據
val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
sensorManager.registerListener(sensorListener, sensor, SensorManager.SENSOR_DELAY_NORMAL)
這裡以 Accelerometer 為例,當使用者搖動手機的時候,我們就執行 shakeHandler()
private val sensorListener = object:SensorEventListener {
override fun onAccuracyChanged(p0: Sensor?, p1: Int) {}
override fun onSensorChanged(event: SensorEvent?) {
if(event != null){
val xValue = Math.abs(event.values[0]) // 加速度 - X 軸方向
val yValue = Math.abs(event.values[1]) // 加速度 - Y 軸方向
val zValue = Math.abs(event.values[2]) // 加速度 - Z 軸方向
if (xValue > 20 || yValue > 20 || zValue > 20) {
shakeHandler()
}
}
}
}
通過 isChangingPhoto 這個自己定屬性,來防止因為搖動過程中多次觸發事件。
當我們接收到搖動事件的時候,
就先將 isChangingPhoto 改為 true,並開始更換圖片和震動手機( changImage() / doVibrate())
然後執行一個 Handler 相隔一秒以後在將 isChangingPhoto 改為 false.
private fun shakeHandler() {
if(isChangingPhoto){
return
}
isChangingPhoto = true
changeImage()
doVibrate()
Handler().postDelayed({
isChangingPhoto = false
}, 1000)
}
private fun doVibrate() {
if(Build.VERSION.SDK_INT >= 26){
vibrator.vibrate(VibrationEffect.createOneShot(100, 10))
} else {
vibrator.vibrate(100)
}
}
private fun changeImage() {
when(currentImageNumber){
0 -> layout_landImageView.setImageResource(images[1])
1 -> layout_landImageView.setImageResource(images[2])
2 -> layout_landImageView.setImageResource(images[3])
3 -> layout_landImageView.setImageResource(images[4])
4 -> layout_landImageView.setImageResource(images[0])
}
if(currentImageNumber != 4){
currentImageNumber += 1
} else {
currentImageNumber = 0
}
}
和 iOS 開發環境很不一樣的是,Android 的硬件設備都來自各種不同的廠商,但在 Android 中有定義 20幾種傳感器。
其中常用的應該是陀螺儀、加速計、方向傳感器、重力傳感器等。
public static final int TYPE_ACCELEROMETER = 1;
public static final int TYPE_ACCELEROMETER_UNCALIBRATED = 35;
public static final int TYPE_AMBIENT_TEMPERATURE = 13;
public static final int TYPE_GAME_ROTATION_VECTOR = 15;
public static final int TYPE_GEOMAGNETIC_ROTATION_VECTOR = 20;
public static final int TYPE_GRAVITY = 9;
public static final int TYPE_GYROSCOPE = 4;
public static final int TYPE_GYROSCOPE_UNCALIBRATED = 16;
public static final int TYPE_HEART_BEAT = 31;
public static final int TYPE_HEART_RATE = 21;
public static final int TYPE_LIGHT = 5;
public static final int TYPE_LINEAR_ACCELERATION = 10;
public static final int TYPE_LOW_LATENCY_OFFBODY_DETECT = 34;
public static final int TYPE_MAGNETIC_FIELD = 2;
public static final int TYPE_MAGNETIC_FIELD_UNCALIBRATED = 14;
public static final int TYPE_MOTION_DETECT = 30;
public static final int TYPE_POSE_6DOF = 28;
public static final int TYPE_PRESSURE = 6;
public static final int TYPE_PROXIMITY = 8;
public static final int TYPE_RELATIVE_HUMIDITY = 12;
public static final int TYPE_ROTATION_VECTOR = 11;
public static final int TYPE_SIGNIFICANT_MOTION = 17;
public static final int TYPE_STATIONARY_DETECT = 29;
public static final int TYPE_STEP_COUNTER = 19;
public static final int TYPE_STEP_DETECTOR = 18;
我們可以通過 getSensorList 來拿到這個設備支援的 Sensor
比如我們這裡印出 sensor 類型、廠商名稱、版本
val allSensors = sensorManager.getSensorList(Sensor.TYPE_ALL)
for(sensor in allSensors){
Log.i("sensors", "${sensor.name} - ${sensor.vendor} - ${sensor.version}")
}
這是紅米手機的一個例子
Accelerometer - BOSCH - 2062500
Magnetometer - Yamaha - 35193090
Magnetometer Uncalibrated - Yamaha - 35193090
ALSPS - LiteOn - 2
......
我們經常通過 android.util.Log 來印出一些資訊,而常見的有這幾個 Log 方法
Log.v - v 代表 verbose - 任何信息都會輸出
Log.d - d 代表 debug - 輸出調試信息
Log.i - i 代表 information
Log.w - w 代表 warning - 輸出警告資訊
Log.e - e 代表 error - 輸出警告資訊。