溫馨提示:本篇博客的詳細代碼已發布到 git : https://gitcode.com/nutpi/HarmonyosNext 可以下載運行哦!
HarmonyOS NEXT ImageItemView組件深度剖析:手勢交互與動畫實現(二)
一、手勢系統架構
.gesture(GestureGroup(GestureMode.Exclusive, // 手勢互斥模式TapGesture({ count: 2 }), // 雙擊TapGesture({ count: 1 }), // 單擊PinchGesture({ fingers: 2 }), // 雙指捏合PanGesture({ fingers: 1 }) // 單指滑動)
)
- GestureGroup:手勢組合容器,管理多個手勢的相互關系
- GestureMode.Exclusive:互斥模式,同一時刻只有一個手勢生效
- 優先級順序:后聲明的手勢優先級更高(這里雙擊手勢優先于單擊)
二、雙擊縮放實現
TapGesture({ count: 2 }).onAction(() => {if (this.imageScaleInfo.scaleValue > 默認值) {// 縮小邏輯fn = () => {this.isEnableSwipe = true; // 啟用滑動切換this.imageScaleInfo.reset(); // 重置縮放this.matrix = matrix4.identity(); // 重置變換矩陣};} else {// 放大邏輯fn = () => {this.isEnableSwipe = false; // 禁用滑動切換const ratio = this.calcFitScaleRatio(...); // 計算適配比例this.matrix = matrix4.identity().scale({x: ratio, y: ratio});};}runWithAnimation(fn); // 帶動畫執行})
- 狀態切換邏輯:
- 當前已放大 → 雙擊恢復默認
- 當前默認狀態 → 雙擊放大至屏幕適配尺寸
- 關鍵方法:
calcFitScaleRatio
:計算填滿屏幕所需比例runWithAnimation
:HarmonyOS動畫API,實現平滑過渡
三、捏合縮放實現
PinchGesture({ fingers: 2 }).onActionUpdate((event) => {// 實時計算縮放比例this.imageScaleInfo.scaleValue = 上次值 * event.scale;// 邊界限制const maxScale = 最大縮放值 * 1.3; // 允許超出20%的彈性效果const minScale = 默認值 * 0.7; // 允許縮小到70%this.imageScaleInfo.scaleValue = Math.min(maxScale, Math.max(minScale, this.imageScaleInfo.scaleValue));// 應用矩陣變換this.matrix = matrix4.identity().scale({x: 當前比例,y: 當前比例});}).onActionEnd(() => {// 彈性回彈處理if (當前比例 < 默認值) {runWithAnimation(() => 重置到默認值);} else if (當前比例 > 最大縮放值) {runWithAnimation(() => 調整到最大值);}})
- 核心參數:
event.scale
:捏合手勢的實時縮放系數(>1放大,<1縮小)lastValue
:記錄上次縮放值,保證連續性
- 邊界處理技巧:
- 允許超出最大/最小值一定比例(提升操作手感)
- 手勢結束后執行彈性動畫
四、滑動位移實現
PanGesture({ fingers: 1 }).onActionUpdate((event) => {if (當前是默認縮放比例) return; // 默認狀態禁止滑動// 計算新偏移量this.imageOffsetInfo.currentX = 上次X + event.offsetX;this.imageOffsetInfo.currentY = 上次Y + event.offsetY;}).onActionEnd(() => {// 保存當前偏移量this.imageOffsetInfo.stash();})
- 位移條件:
- 僅在放大狀態下允許滑動
- 默認狀態下的滑動留給父組件處理(用于圖片切換)
- 坐標計算:
offsetX/Y
:手勢相對于起點的位移量- 需要疊加上次的偏移量實現連續移動
五、動畫系統應用
runWithAnimation(() => {// 狀態變更操作this.imageScaleInfo.scaleValue = 目標值;this.matrix = 新矩陣;
});
- 動畫原理:
- 包裹在
runWithAnimation
中的狀態變更會自動應用動畫 - 系統默認使用彈性動畫(spring)效果
- 包裹在
- 自定義動畫:
runWithAnimation(() => {// 操作 }, {duration: 300, // 動畫時長curve: Curve.EaseInOut // 緩動曲線 })
六、矩陣變換原理
matrix4.identity() // 創建單位矩陣.scale({ x: 2, y: 2 }) // 縮放變換.translate({ x: 100, y: 50 }) // 位移變換.copy(); // 創建新實例
- 矩陣操作順序:
- 先縮放后位移(矩陣乘法順序,實際是反向應用)
- 建議先執行縮放再執行位移
- 坐標系特點:
- 以組件中心點為變換原點
- 位移量基于縮放后的坐標系