HarmonyOS NEXT 實(shí)現(xiàn)拖動(dòng)卡片背景模糊效果

大家好,我是 V 哥。
最近看到在 HarmonyOS NEXT開發(fā)中,實(shí)現(xiàn)拖動(dòng)卡片背景模糊的案例效果,在拖動(dòng)時(shí)背景圖片模糊,松開后恢復(fù)正常。感覺很酷,寫一個(gè)案例玩一下。

image.png

需求分析

首先,咱們來一起分析一下這個(gè)效果要怎么實(shí)現(xiàn)。

分析需求:卡片可拖動(dòng),拖動(dòng)時(shí)背景模糊,松開后恢復(fù)。這需要處理拖拽事件和動(dòng)態(tài)調(diào)整背景的模糊效果。咱們需要確定如何監(jiān)聽拖拽動(dòng)作,以及如何動(dòng)態(tài)改變背景的樣式。

ArkUI中的組件,比如Stack布局可以用來放置背景和卡片??ㄆ赡苄枰褂每赏蟿?dòng)的組件,比如PanGesture或者拖拽事件相關(guān)的組件。在HarmonyOS中,手勢(shì)處理通常是通過Gesture組件來實(shí)現(xiàn)的,比如PanGesture用于拖動(dòng)手勢(shì)。

接下來,背景圖片的模糊效果。在ArkUI中,有類似于前端的backdrop-filter樣式,或者需要使用某種圖像處理模塊。

然后,狀態(tài)管理的問題。當(dāng)卡片被拖動(dòng)時(shí),需要觸發(fā)背景模糊,松開后恢復(fù)。這需要維護(hù)一個(gè)狀態(tài)變量,比如isDragging,當(dāng)拖拽開始的時(shí)候設(shè)置為true,拖拽結(jié)束或松開的時(shí)候設(shè)置為false。這個(gè)狀態(tài)變量控制背景的模糊效果是否應(yīng)用。

接下來,拖拽的實(shí)現(xiàn)。使用PanGesture手勢(shì),監(jiān)聽onActionStart、onActionUpdate、onActionEnd事件。在onActionStart時(shí)設(shè)置isDragging為true,onActionEnd或onActionCancel時(shí)設(shè)置為false。同時(shí),根據(jù)手勢(shì)的偏移量更新卡片的位置,可能需要使用絕對(duì)定位,比如設(shè)置卡片的position為絕對(duì)定位,然后通過left和top屬性來調(diào)整位置,或者使用translate屬性進(jìn)行平移。

關(guān)于卡片的定位,需要將卡片放在一個(gè)容器中,比如Stack布局,這樣卡片可以自由移動(dòng)。然后通過手勢(shì)事件中的偏移量來更新卡片的位置。需要注意處理手勢(shì)事件的offsetX和offsetY,或者在onActionUpdate中獲取手指移動(dòng)的差值,然后累加到卡片的位置上。

然后,背景的動(dòng)態(tài)模糊。假設(shè)背景是一個(gè)Image組件,當(dāng)isDragging為true時(shí),應(yīng)用blur效果。例如,在ArkUI中,Image組件可能有effect屬性,可以設(shè)置為ImageEffect.blur(radius),根據(jù)isDragging的狀態(tài)調(diào)整radius的值?;蛘呖赡苄枰褂脳l件渲染,根據(jù)狀態(tài)改變樣式類。

咱們需要?jiǎng)?chuàng)建一個(gè)狀態(tài)變量,比如blurRadius,初始為0,拖動(dòng)時(shí)設(shè)置為5,這樣背景圖片的模糊效果就會(huì)動(dòng)態(tài)變化。同時(shí),動(dòng)畫效果可能需要使用動(dòng)畫API,比如animateTo,讓模糊過渡更平滑。

另外,需要注意性能問題,頻繁的模糊效果可能會(huì)影響性能,需要確認(rèn)HarmonyOS中是否優(yōu)化了這類效果,或者是否有更好的實(shí)現(xiàn)方式,比如使用離屏渲染或者緩存模糊后的圖片,不過這可能比較復(fù)雜,作為基礎(chǔ)功能可能直接動(dòng)態(tài)調(diào)整即可。

現(xiàn)在,整合這些思路,代碼的大致結(jié)構(gòu)可能是這樣的:

? 外層使用Stack布局,包含背景Image和可拖動(dòng)的卡片。
? 卡片組件包裹在Gesture組件中,監(jiān)聽PanGesture事件。
? 當(dāng)拖拽開始時(shí),設(shè)置isDragging為true,更新背景的模糊效果。
? 拖拽過程中,根據(jù)手勢(shì)的偏移量更新卡片的位置。
? 拖拽結(jié)束時(shí),恢復(fù)背景的模糊效果。

案例實(shí)現(xiàn)

V 哥來總結(jié)一下實(shí)現(xiàn)步驟:

  1. 創(chuàng)建頁面組件,使用Stack布局包含背景和卡片。
  2. 背景圖片應(yīng)用模糊效果,根據(jù)isDragging狀態(tài)變化。
  3. 卡片使用Gesture組件處理PanGesture手勢(shì)。
  4. 拖動(dòng)手勢(shì)事件中更新卡片的位置,并控制isDragging狀態(tài)。
  5. 狀態(tài)變化觸發(fā)背景模糊的樣式更新。
  6. 可能需要添加過渡動(dòng)畫使模糊效果更平滑。

在HarmonyOS NEXT中,可以通過以下步驟實(shí)現(xiàn)可拖動(dòng)卡片并控制背景模糊效果:

@Entry
@Component
struct DragCardExample {
  @State cardPosition: { x: number, y: number } = { x: 0, y: 0 };
  @State isDragging: boolean = false;
  private initialPosition: { x: number, y: number } = { x: 0, y: 0 };

  build() {
    Stack() {
      // 背景圖片
      Image($r('app.media.background'))
        .width('100%')
        .height('100%')
        .objectFit(ImageFit.Cover)
        .blur(this.isDragging ? 10 : 0) // 根據(jù)拖動(dòng)狀態(tài)調(diào)整模糊度
        .animation({ duration: 300, curve: Curve.EaseInOut })

      // 可拖動(dòng)卡片
      Gesture(
        GesturePriority.Low,
        PanGesture({
          onActionStart: () => {
            this.isDragging = true;
            this.initialPosition = { ...this.cardPosition };
          },
          onActionUpdate: (event: GestureEvent) => {
            this.cardPosition = {
              x: this.initialPosition.x + event.offsetX,
              y: this.initialPosition.y + event.offsetY
            };
          },
          onActionEnd: () => {
            this.isDragging = false;
            // 這里可以添加自動(dòng)回中或其他結(jié)束邏輯
          },
          onActionCancel: () => {
            this.isDragging = false;
          }
        })
      ) {
        Column() {
          Text('拖拽我')
            .fontSize(20)
            .fontColor(Color.Black)
        }
        .width(200)
        .height(150)
        .padding(20)
        .backgroundColor(Color.White)
        .borderRadius(16)
        .shadow({ radius: 8, color: '#30000000', offsetX: 2, offsetY: 4 })
      }
      .position({ x: this.cardPosition.x, y: this.cardPosition.y })
      .animation({ duration: 100, curve: Curve.Linear })
    }
    .width('100%')
    .height('100%')
  }
}

實(shí)現(xiàn)原理說明:

  1. 狀態(tài)管理:
    ? @State cardPosition:記錄卡片的當(dāng)前位置
    ? @State isDragging:控制拖動(dòng)狀態(tài)
    ? initialPosition:記錄拖動(dòng)前的初始位置

  2. 手勢(shì)處理:
    ? 使用PanGesture實(shí)現(xiàn)拖動(dòng)手勢(shì)識(shí)別
    ? onActionStart:記錄初始位置并設(shè)置拖動(dòng)狀態(tài)
    ? onActionUpdate:實(shí)時(shí)更新卡片位置
    ? onActionEnd/Cancel:重置拖動(dòng)狀態(tài)

  3. 背景模糊控制:
    ? 使用blur()API根據(jù)isDragging狀態(tài)動(dòng)態(tài)調(diào)整模糊度
    ? 添加animation實(shí)現(xiàn)平滑的過渡效果

  4. 卡片樣式:
    ? 使用position實(shí)現(xiàn)絕對(duì)定位
    ? 添加陰影和圓角提升視覺效果
    ? 為位置變化添加微小的動(dòng)畫提升拖動(dòng)手感

擴(kuò)展建議:

  1. 邊界控制: 添加位置限制防止卡片拖出屏幕
   // 在onActionUpdate中添加限制邏輯
   const maxX = 屏幕寬度 - 卡片寬度;
   const maxY = 屏幕高度 - 卡片高度;
   x = Math.min(Math.max(x, 0), maxX);
   y = Math.min(Math.max(y, 0), maxY);
  1. 磁性吸附效果: 在onActionEnd中添加自動(dòng)居中邏輯
   animateTo({ duration: 200 }, () => {
     this.cardPosition = { x: 0, y: 0 };
   });
  1. 性能優(yōu)化: 對(duì)于復(fù)雜背景,建議:
    ? 使用緩存后的模糊圖片
    ? 控制模糊半徑不超過15px
    ? 在模糊層添加backdropBlur()代替全圖模糊

最后

這個(gè)實(shí)現(xiàn)方案完整展示了如何在HarmonyOS NEXT中結(jié)合手勢(shì)識(shí)別、狀態(tài)管理和視覺效果API,實(shí)現(xiàn)具有交互視覺反饋的可拖動(dòng)卡片效果。關(guān)注威哥愛編程,鴻蒙開發(fā)一定行。
想要學(xué)習(xí)鴻蒙開發(fā),一定繞不開學(xué)習(xí) ArkTS 語言,V 哥寫了三本鴻蒙開發(fā)之路的書,第一本《鴻蒙 HarmonyOS NEXT開發(fā)之路 卷1 ArkTS 篇》已上市,歡迎鴻蒙開發(fā)愛好者讀一讀,可以幫助你快速系統(tǒng)的拿下 ArkTS,每二本鴻蒙應(yīng)用開發(fā)篇和項(xiàng)目實(shí)踐篇也即將上市,清華大學(xué)出版社正在緊張校稿中。

image.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容