早期微信「搖一搖」功能風靡一時,許多開發者也想在自家 App 中加入類似的互動體驗。本文將從加速度感測器原理出發,手把手教你完成一個「搖一搖觸發手機震動」的 Demo,並解析關鍵 API 與權限設定。
Android 手機內建多種感測器,實現搖一搖主要依賴 加速度感測器。當使用者搖晃手機時,三軸加速度值會瞬間飆升;我們只需在 SensorEventListener.onSensorChanged() 中監聽三軸數值,若任一軸絕對值超過預設閾值(如 20 m/s²),即判定為「搖動事件」,進而觸發震動或其他業務邏輯。
SensorManager 系統服務。SensorEventListener 介面,覆寫 onSensorChanged() 與 onAccuracyChanged()。SensorManager.registerListener() 註冊監聽器,指定感測器類型為 Sensor.TYPE_ACCELEROMETER。Android 震動功能由 Vibrator 系統服務提供,需在 AndroidManifest.xml 宣告權限:
<uses-permission android:name="android.permission.VIBRATE"/>
常用兩種震動模式:
vibrator.vibrate(milliseconds),參數為震動持續時間(毫秒)。vibrator.vibrate(pattern, repeat),pattern 為 long 陣列,意義為 [靜止時間, 震動時間, 靜止時間, 震動時間...];repeat 為 -1 表示不重複,索引值表示從該索引開始循環。public class VibratorHelper {
public static void vibrateOnce(Activity activity, long milliseconds) {
Vibrator vibrator = (Vibrator) activity.getSystemService(Context.VIBRATOR_SERVICE);
vibrator.vibrate(milliseconds);
}
public static void vibratePattern(Activity activity, long[] pattern, int repeat) {
Vibrator vibrator = (Vibrator) activity.getSystemService(Context.VIBRATOR_SERVICE);
vibrator.vibrate(pattern, repeat);
}
}
public class MainActivity extends Activity {
private SensorManager sensorManager;
private SensorEventListener shakeListener;
private AlertDialog.Builder dialogBuilder;
private boolean isRefresh = false; // 防止重複觸發
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
shakeListener = new ShakeSensorListener();
dialogBuilder = new AlertDialog.Builder(this);
dialogBuilder.setPositiveButton("確定", (dialog, which) -> {
isRefresh = false;
dialog.cancel();
}).setMessage("搖到了一位帥氣小哥哥!").create();
}
@Override
protected void onResume() {
super.onResume();
// 註冊監聽器,採用最快更新速率
sensorManager.registerListener(shakeListener,
sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_FASTEST);
}
@Override
protected void onPause() {
super.onPause();
// Activity 進入背景時解除註冊,省電
sensorManager.unregisterListener(shakeListener);
}
private class ShakeSensorListener implements SensorEventListener {
private static final int SHAKE_THRESHOLD = 20; // 閾值可依實測調整
@Override
public void onSensorChanged(SensorEvent event) {
if (isRefresh) return; // 正在處理中,忽略
float x = Math.abs(event.values[0]);
float y = Math.abs(event.values[1]);
float z = Math.abs(event.values[2]);
if (x >= SHAKE_THRESHOLD || y >= SHAKE_THRESHOLD || z >= SHAKE_THRESHOLD) {
Toast.makeText(MainActivity.this, "加速度: " + Math.max(x, Math.max(y, z)), Toast.LENGTH_SHORT).show();
VibratorHelper.vibrateOnce(MainActivity.this, 300);
isRefresh = true;
dialogBuilder.show();
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// 精度變更時處理,通常不需理會
}
}
}
onPause() 解除註冊,否則會導致記憶體洩漏與耗電。掌握感測器與震動服務的串接,即可為 App 增加豐富的體感互動體驗。