本文將說明 Android 裝置上常見的震動致動器「線性共振致動器 (LRA)」,詳細介紹其特性、產生觸覺回饋的方式,以及如何使用 Android API 建立有效的觸覺模式。 keywords_public: > Android 觸覺技術、觸覺致動器、線性共振致動器、LRA、震動、 觸覺回饋、VibratorFrequencyProfile、VibrationEffect、Android UI
Android 裝置上最常見的震動致動器是線性共振致動器 (LRA)。LRA 會模擬按鈕點按的感覺,在無反應的玻璃表面上提供觸覺回饋。清晰明確的按鈕回饋訊號通常會持續 10 到 20 毫秒。這種感覺可讓使用者互動更加自然。對於虛擬鍵盤,這項點擊回饋可提高打字速度並減少錯誤。
LRA 有幾種常見的共振頻率:
- 部分 LRA 的共振頻率介於 200 至 300 Hz 之間,這與人體皮膚對震動最敏感的頻率一致。這個頻率範圍的震動通常會被形容為平滑、尖銳和穿透。
- 其他 LRA 型號的共振頻率較低,約為 150 Hz。這種感覺在品質上較為柔和飽滿 (在尺寸方面)。
在兩種不同頻率下提供相同輸入電壓時,震動輸出振幅可能不同。頻率與 LRA 共振頻率的差距越大,震動幅度就越小。
特定裝置的觸覺效果會同時使用震動致動器和驅動程式。 包含過驅動和主動煞車功能的觸覺驅動程式可縮短 LRA 的上升時間和鈴聲,進而產生更靈敏清晰的震動。
加快震動器輸出
頻率對輸出加速對應 (FOAM) 說明在特定震動頻率 (以赫茲為單位) 下,可達成的最大輸出加速 (以 G 峰值為單位)。從 Android 16 (API 級別 36) 開始,平台會透過 VibratorFrequencyProfile 內建支援這項對應。您可以搭配使用這個類別與基本和進階封包 API,建立觸覺效果。
大多數 LRA 馬達的 FOAM 都有單一尖峰,通常接近共振頻率。一般來說,當頻率偏離這個範圍時,加速度會呈指數下降。曲線可能不對稱,且共振頻率附近可能出現平緩區,以保護馬達免於損壞。
鄰近的圖表顯示 LRA 馬達的 FOAM 範例。
人類感知偵測門檻
人體感知偵測門檻是指人體可穩定偵測到的最低震動加速度。震動強度會因震動頻率而異。
鄰近的圖表顯示人類觸覺感知偵測閾值,以加速度表示,是時間頻率的函數。門檻資料是根據 Bolanowski Jr. 論文圖 1 的位移門檻轉換而來,S. J. 等人於 1988 年發表的文章「Four channels mediate the mechanical aspects of touch」(四個管道調解觸覺的機械層面)。
Android 會在 BasicEnvelopeBuilder 中自動處理這個門檻,確認所有效果使用的頻率範圍產生的震動幅度,至少要比人類感知偵測門檻高出 10 分貝。
如需進一步瞭解加速度振幅和位移振幅之間的轉換,請參閱線上教學課程。
震動加速度等級
震動強度是感知指標,但人類對震動強度的感知不會隨著震動幅度 (物理參數) 呈線性成長。感知強度的特徵是感覺強度 (SL),定義為相同頻率下高於偵測門檻的 dB 值。
對應的振動加速度幅度 (以 G 峰值為單位) 計算方式如下:
...其中振幅 dB 是 SL 和偵測門檻的總和,也就是相鄰圖中特定頻率的垂直軸值。
旁邊的圖表顯示 10、20、30、40 和 50 dB SL 的震動加速度,以及人類觸覺感知偵測閾值 (0 dB SL),以時間頻率為函數。這項資料是根據 Verrillo, R. 論文中的圖 8 估算而得。T. 等人於 1969 年發表的文章「Sensation magnitude of vibrotactile stimuli.」。
Android 會在 BasicEnvelopeBuilder 中自動處理這項轉換,該函式會將值視為感覺層級空間 (dB SL) 中的標準化強度,並將其轉換為輸出加速度。另一方面,WaveformEnvelopeBuilder 不會套用這項轉換,而是以加速空間中的標準化輸出加速度幅度 (Gs) 做為值。封包 API 假設設計師或開發人員考慮震動強度變化時,會預期感知強度遵循分段線性封包。
裝置上的預設波形平滑度
舉例來說,請考量自訂波形模式在一般裝置上的行為:
Kotlin
val timings: LongArray = longArrayOf(50, 50, 50, 50, 50, 100, 350, 250)
val amplitudes: IntArray = intArrayOf(77, 79, 84, 99, 143, 255, 0, 255)
val repeatIndex = -1 // Don't repeat.
vibrator.vibrate(VibrationEffect.createWaveform(timings, amplitudes, repeatIndex))
Java
long[] timings = new long[] { 50, 50, 50, 50, 50, 100, 350, 250 };
int[] amplitudes = new int[] { 77, 79, 84, 99, 143, 255, 0, 255 };
int repeatIndex = -1 // Don't repeat.
vibrator.vibrate(VibrationEffect.createWaveform(timings, amplitudes, repeatIndex));
下圖顯示輸入波形和輸出加速度,對應於先前的程式碼片段。請注意,每當模式中的振幅出現階梯式變化時 (也就是在 0 毫秒、150 毫秒、200 毫秒、250 毫秒和 700 毫秒時),加速度會逐漸增加,而不是突然增加。此外,在每個振幅變更步驟中,都會出現過衝現象,且當輸入振幅突然降至 0 時,會出現明顯的鈴聲,持續時間至少 50 毫秒。
改良的觸覺回饋模式
為避免過衝並縮短鈴聲時間,請更緩慢地變更振幅。以下顯示修訂版波形和加速度圖:
Kotlin
val timings: LongArray = longArrayOf(
25, 25, 50, 25, 25, 25, 25, 25, 25, 25, 75, 25, 25,
300, 25, 25, 150, 25, 25, 25
)
val amplitudes: IntArray = intArrayOf(
38, 77, 79, 84, 92, 99, 121, 143, 180, 217, 255, 170, 85,
0, 85, 170, 255, 170, 85, 0
)
val repeatIndex = -1 // Don't repeat.
vibrator.vibrate(VibrationEffect.createWaveform(timings, amplitudes, repeatIndex))
Java
long[] timings = new long[] {
25, 25, 50, 25, 25, 25, 25, 25, 25, 25, 75, 25, 25,
300, 25, 25, 150, 25, 25, 25
};
int[] amplitudes = new int[] {
38, 77, 79, 84, 92, 99, 121, 143, 180, 217, 255, 170, 85,
0, 85, 170, 255, 170, 85, 0
};
int repeatIndex = -1; // Don't repeat.
vibrator.vibrate(VibrationEffect.createWaveform(timings, amplitudes, repeatIndex));
建立更複雜的觸覺效果
令人滿意的點擊回應中的其他元素較為複雜,需要瞭解裝置中使用的 LRA。為獲得最佳結果,請使用裝置預先製作的波形和平台提供的常數,以便執行下列操作:
- 執行清除效果和基本體。
- 將這些效果串連在一起,即可組成新的觸覺效果。
這些預先定義的觸覺常數和基本型別可大幅加快工作速度,同時建立高品質的觸覺效果。