及时做APP开发实战(九)-系统级震动反馈实现
本文将详细介绍如何在HarmonyOS NEXT中实现番茄钟的系统级震动反馈,提升用户体验。
一、需求背景
1.1 功能需求
番茄钟应用需要在关键时刻提供震动反馈,提醒用户状态变化:
┌─────────────────────────────────────┐
│ 震动反馈场景 │
├─────────────────────────────────────┤
│ 番茄钟完成 → 长震动 + 模式震动 │
│ 休息开始 → 短震动提示 │
│ 休息结束 → 双击震动提醒 │
└─────────────────────────────────────┘
1.2 技术选型
HarmonyOS提供 @ohos.vibrator 模块实现震动功能:
| startVibration | 触发震动 |
| stopVibration | 停止震动 |
| VibratorStopMode | 停止模式枚举 |
二、权限配置
2.1 添加震动权限
在 module.json5 中添加权限声明:
{
"module": {
"requestPermissions": [
{
"name": "ohos.permission.VIBRATE",
"reason": "$string:vibrate_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
}
]
}
}
2.2 添加权限说明
在 string.json 中添加权限说明:
{
"string": [
{
"name": "vibrate_reason",
"value": "用于番茄钟计时结束时提供震动反馈提醒"
}
]
}
三、FeedbackUtil工具类实现
3.1 类结构设计
┌─────────────────────────────────────┐
│ FeedbackUtil │
├─────────────────────────────────────┤
│ – instance: FeedbackUtil │
├─────────────────────────────────────┤
│ + getInstance(): FeedbackUtil │
│ + vibrate(duration): void │
│ + vibratePattern(pattern): void │
│ + stopVibrate(): void │
│ + pomodoroComplete(): void │
│ + breakStart(): void │
│ + breakEnd(): void │
└─────────────────────────────────────┘
3.2 完整实现代码
import vibrator from '@ohos.vibrator';
import { BusinessError } from '@ohos.base';
export class FeedbackUtil {
private static instance: FeedbackUtil | null = null;
// 私有构造函数
private constructor() {}
// 获取单例
public static getInstance(): FeedbackUtil {
if (!FeedbackUtil.instance) {
FeedbackUtil.instance = new FeedbackUtil();
}
return FeedbackUtil.instance;
}
/**
* 触发震动反馈
* @param duration 震动持续时间(毫秒),默认200ms
*/
public vibrate(duration: number = 200): void {
try {
vibrator.startVibration({
type: 'time',
duration: duration
}, {
id: 0,
usage: 'alarm'
}, (error: BusinessError) => {
if (error) {
console.error(`[FeedbackUtil] 震动失败: ${error.message}`);
} else {
console.info('[FeedbackUtil] 震动反馈成功');
}
});
} catch (err) {
const e: BusinessError = err as BusinessError;
console.error(`[FeedbackUtil] 震动异常: ${e.message}`);
}
}
/**
* 触发模式震动
* @param pattern 震动模式 [静止, 震动, 静止, 震动, …]
*/
public vibratePattern(pattern: number[]): void {
try {
vibrator.startVibration({
type: 'preset',
effectId: 'haptic.clock.timer',
count: 1
}, {
id: 0,
usage: 'alarm'
}, (error: BusinessError) => {
if (error) {
console.error(`[FeedbackUtil] 模式震动失败: ${error.message}`);
}
});
} catch (err) {
const e: BusinessError = err as BusinessError;
console.error(`[FeedbackUtil] 模式震动异常: ${e.message}`);
}
}
/**
* 停止震动
*/
public stopVibrate(): void {
try {
vibrator.stopVibration(
vibrator.VibratorStopMode.VIBRATOR_STOP_MODE_TIME,
(error: BusinessError) => {
if (error) {
console.error(`[FeedbackUtil] 停止震动失败: ${error.message}`);
}
}
);
} catch (err) {
const e: BusinessError = err as BusinessError;
console.error(`[FeedbackUtil] 停止震动异常: ${e.message}`);
}
}
/**
* 番茄钟完成反馈
* 长震动 + 特效震动
*/
public pomodoroComplete(): void {
this.vibrate(500);
setTimeout(() => {
this.vibratePattern([100, 100, 100, 100]);
}, 600);
}
/**
* 休息开始反馈
*/
public breakStart(): void {
this.vibrate(150);
}
/**
* 休息结束反馈
*/
public breakEnd(): void {
this.vibrate(100);
setTimeout(() => {
this.vibrate(100);
}, 200);
}
}
四、业务场景集成
4.1 在PomodoroPage中使用
import { FeedbackUtil } from '../utils/FeedbackUtil';
@Entry
@Component
struct PomodoroPage {
// 工具类实例
private feedbackUtil: FeedbackUtil = FeedbackUtil.getInstance();
// 计时完成
async onTimerComplete() {
this.stopTimer();
this.isRunning = false;
if (this.isBreak) {
// 休息结束
this.isBreak = false;
this.timeLeft = this.customDuration * 60;
this.feedbackUtil.breakEnd(); // 双击震动
} else {
// 番茄钟完成
this.pomodoroCount++;
// … 保存记录逻辑
this.feedbackUtil.pomodoroComplete(); // 长震动+模式震动
// 进入休息
this.timeLeft = Constants.SHORT_BREAK_DURATION * 60;
this.isBreak = true;
this.feedbackUtil.breakStart(); // 短震动
}
}
}
4.2 震动时机说明
【图1:震动反馈时机】
┌─────────────────────────────────────┐
│ 番茄钟生命周期 │
├─────────────────────────────────────┤
│ [开始专注] │
│ ↓ │
│ [专注中…] │
│ ↓ │
│ [专注完成] → pomodoroComplete() │
│ ↓ (500ms + 模式震动) │
│ [进入休息] → breakStart() │
│ ↓ (150ms震动) │
│ [休息中…] │
│ ↓ │
│ [休息结束] → breakEnd() │
│ (双击震动) │
└─────────────────────────────────────┘
五、API详解
5.1 startVibration参数
vibrator.startVibration(
effect: VibrateEffect, // 震动效果
attribute: VibrateAttribute, // 震动属性
callback: AsyncCallback<void> // 回调
)
VibrateEffect类型:
| time | 时长震动 | { type: 'time', duration: 200 } |
| preset | 预设效果 | { type: 'preset', effectId: 'haptic.clock.timer' } |
| file | 文件震动 | { type: 'file', hapticScene: 'xxx' } |
VibrateAttribute属性:
{
id: 0, // 震动马达ID
usage: 'alarm' // 使用场景:alarm/notification/communication等
}
5.2 stopVibration参数
vibrator.stopVibration(
stopMode: VibratorStopMode, // 停止模式
callback: AsyncCallback<void>
)
VibratorStopMode枚举:
| VIBRATOR_STOP_MODE_TIME | 停止时长震动 |
| VIBRATOR_STOP_MODE_PRESET | 停止预设震动 |
| VIBRATOR_STOP_MODE_FILE | 停止文件震动 |
六、最佳实践
6.1 单例模式
// ✅ 推荐:使用单例避免重复创建
private feedbackUtil: FeedbackUtil = FeedbackUtil.getInstance();
// ❌ 不推荐:每次都创建新实例
let feedbackUtil = new FeedbackUtil(); // 构造函数私有,无法直接创建
6.2 异常处理
// ✅ 推荐:捕获所有可能的异常
try {
vibrator.startVibration(effect, attribute, callback);
} catch (err) {
const e: BusinessError = err as BusinessError;
console.error(`震动异常: ${e.message}`);
}
// ❌ 不推荐:不处理异常
vibrator.startVibration(effect, attribute, callback);
6.3 权限检查
// 在使用前检查权限
import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
async checkVibratePermission(): Promise<boolean> {
const atManager = abilityAccessCtrl.createAtManager();
const grantStatus = await atManager.verifyAccessToken(
this.context.applicationInfo.accessTokenId,
'ohos.permission.VIBRATE'
);
return grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
}
七、效果测试
7.1 测试环境说明
⚠️ 重要提示:模拟器不支持震动功能,需要在真机上测试震动效果。
【图2:测试环境对比】
| 模拟器 | ❌ 不支持 | 用于UI和逻辑测试 |
| 真机 | ✅ 支持 | 用于震动效果测试 |
7.2 测试场景
【图3:震动效果时序图】
时间轴:番茄钟完成 → 休息开始 → 休息结束
│
├─ [0ms] 触发 pomodoroComplete()
│ └─ 500ms长震动 ▓▓▓▓▓
│
├─ [600ms] 触发模式震动
│ └─ haptic.clock.timer 特效
│
├─ [800ms] 触发 breakStart()
│ └─ 150ms短震动 ▓▓
│
└─ [休息结束] 触发 breakEnd()
└─ 双击震动 ▓ ▓ (100ms × 2)
7.3 真机测试步骤
- 启动番茄钟
- 等待倒计时结束(可设置短时间测试)
- 手机会震动反馈
7.4 用户体验优化
┌─────────────────────────────────────┐
│ 震动强度建议 │
├─────────────────────────────────────┤
│ 重要提醒(完成)→ 强震动 │
│ 状态切换(休息)→ 中等震动 │
│ 轻量提示 → 轻震动 │
└─────────────────────────────────────┘
7.5 效果截图
【图4:番茄钟完成界面】

倒计时结束,显示完成状态
【图5:进入休息界面】

自动切换到休息模式
八、总结
本文实现了番茄钟的系统级震动反馈功能:
震动反馈是提升用户体验的重要手段,合理使用可以让应用更加人性化。







