最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

HarmonyOS鴻蒙吸頂效果的實現(xiàn)方案詳解

 更新時間:2026年06月18日 10:40:35   作者:被溫水煮的青蛙  
這篇文章主要介紹了HarmonyOS鴻蒙吸頂效果實現(xiàn)的相關(guān)資料,在HarmonyOS(鴻蒙)系統(tǒng)中實現(xiàn)吸頂效果(Sticky Header),通常涉及到布局管理和滾動事件監(jiān)聽,文中通過代碼介紹的非常詳細,需要的朋友可以參考下

吸頂效果,即頁面滾動時讓某一區(qū)域(如分類導(dǎo)航欄)固定在頂部,隨頁面滾動"貼"在標題欄下方,類似 Android/iOS 原生設(shè)計中的 StickyHeader。 本文結(jié)合實際生產(chǎn)頁面 HomeExplorePage,深入解析 HarmonyOS ArkUI 中實現(xiàn) Tabs 吸頂?shù)耐暾桨浮?/p>

先看結(jié)論

  • 吸頂是 Tabs + 父子滾動聯(lián)動 共同實現(xiàn)的,不是單一屬性生效。
  • 關(guān)鍵配置只有四個:height('100%')、Tabs.height(calc(...))nestedScroll(...)、edgeEffect(None, { alwaysEnabled: true })。
  • 其中兩個最容易遺漏:
    • .barHeight('auto'):讓 tabBar 高度跟隨內(nèi)容
    • alwaysEnabled: true:邊界處持續(xù)感知,避免“卡一下”

閱讀導(dǎo)航

  1. 想快速落地:看「四個關(guān)鍵屬性」+「方案總結(jié)」
  2. 想理解原理:看「關(guān)鍵③ nestedScroll」和「關(guān)鍵④ edgeEffect」
  3. 想直接復(fù)制:看「完整代碼示例」

一、效果演示

交互行為
頁面初始頂部 Banner 頭圖 + 下方綠色 TabBar 均可見
手指下滑WaterFlow 先滾動 → 列表到頂后外層 Scroll 繼續(xù) → TabBar 被推出屏幕
手指上滑外層 Scroll 先滾回 → TabBar 貼到標題欄下方 → 列表繼續(xù)滾動(吸頂完成)

二、布局結(jié)構(gòu)

整體布局采用 外層 Scroll + 內(nèi)層 Tabs + 子列表 的嵌套結(jié)構(gòu),與業(yè)界通用方案一致:

NavDestination
└── Stack                                    ← 根容器,提供 z 軸層級
    ├── Stack  頂部標題欄                     ← zIndex=2,始終在最前
    │       height = statusBar + 標題高度
    │
    └── Scroll  外層滾動器                     ← 【關(guān)鍵①】height='100%'
        └── Column                            ← 子內(nèi)容回推總高度 → 產(chǎn)生滾動空間
            ├── Banner Column                 ← 頭圖區(qū),上滑滾出屏幕
            └── Tabs  吸頂區(qū)域                 ← 【關(guān)鍵②】calc(100% - avoidance)
                └── TabContent
                    └── WaterFlow/List        ← 【關(guān)鍵③nestedScroll + 關(guān)鍵④edgeEffect】

三、四個關(guān)鍵屬性(重點)

要實現(xiàn)流暢的吸頂效果,必須同時滿足以下四個條件,缺一不可。

關(guān)鍵① —— 外層滾動器:height='100%'

Scroll(this.outerScroller) {
  Column() { /* 子內(nèi)容 */ }
  .width('100%')
}
.width('100%')
.height('100%')   // ← 關(guān)鍵:不約束子 Column 高度,由內(nèi)容回推總高度 → 產(chǎn)生滾動空間
.scrollBar(BarState.Off)

作用: height('100%') 表示 Scroll 的高度基準等于父容器,不對子內(nèi)容做高度截斷。子 Column 的總高度由內(nèi)部所有子組件回推得到,當內(nèi)容超出屏幕時自然產(chǎn)生滾動區(qū)域。

常見誤區(qū):

錯誤寫法問題
內(nèi)層 Stack 設(shè)置 height('100%')鎖死高度,子 Column 無法撐開,Scroll 無滾動空間
constraintSize({ minHeight: '100%' })同樣約束高度,效果等同于上例
Tabs 使用 layoutWeight(1) + height('100%')高度基準偏小,列表內(nèi)容填不滿或溢出

關(guān)鍵② —— Tabs 高度與 barHeight

// 避讓高度 = 狀態(tài)欄高度 + 標題欄高度
private getAvoidanceHeight(): number {
  return WindowHelper.statusBarHeight + 25
}

Tabs({ index: $$this.selectedTabIndex }) {
  TabContent() { this.tabContentBuilder() }
    .tabBar(this.tabBarBuilder())
}
// 【關(guān)鍵②-a】Tabs 高度固定為 Scroll.Column 的剩余空間
.height(`calc(100% - ${this.getAvoidanceHeight()}vp)`)
// 【關(guān)鍵②-b】tabBar 高度由內(nèi)容撐開
.barHeight('auto')
.scrollable(false)            // 禁用 Tabs 內(nèi)置滾動,由子列表承載
.barPosition(BarPosition.Start) // tabBar 在內(nèi)容上方(縱向吸頂)
.clip(true)

關(guān)鍵②-a:height = calc(100% - avoidanceHeight)

原理:

  • 外層 Scroll.Column 布局:頂部 Banner(180) + hint 提示 + Tabs
  • Scroll 設(shè)定 height='100%'(關(guān)鍵①),不約束自身高度,由子元素回推總高
  • 此時 Column 總高度 = Banner(180) + hint + Tabs
  • 如果 Tabs 不設(shè)高度,會被內(nèi)容撐開,可能把 Tabs 自身的一部分內(nèi)容頂出屏幕底部

使用 calc(100% - avoidanceHeight) 后:

高度計算
Scroll 總高屏幕高度(100%)
減去標題欄avoidanceHeight = statusBarHeight + 25
Tabs 實際高度calc(100% - avoidanceHeight) = 屏幕高度 - 標題欄高度

效果: Tabs 精確填滿 Scroll.Column 減去上方 Banner 和 hint 后的剩余垂直空間,列表內(nèi)容不會溢出屏幕。

關(guān)鍵②-b:barHeight('auto')

作用: tabBar 的高度由 Builder 內(nèi)容自動撐開,而非固定數(shù)值。

tabBarBuilder 中,Row 高度為 44(tabs 文字行)+ Divider(1),如果使用固定數(shù)值如 barHeight(48)

  • tabBar 內(nèi)容變化(如增加一行文字)時,高度不會自適應(yīng)
  • 固定數(shù)值與 Builder 實際高度不匹配時,會產(chǎn)生裁剪或留白

barHeight('auto') 讓 HarmonyOS 根據(jù) tabBarBuilder() 實際渲染出的高度來計算 tabBar 區(qū)域,保證與 Builder 內(nèi)容精確匹配。

附加配置:

  • scrollable(false):禁用 Tabs 內(nèi)置滑動切換,內(nèi)容滾動完全由 WaterFlow 承載,避免兩層滾動互相干擾
  • barPosition(BarPosition.Start):tabBar 位于內(nèi)容上方(縱向),橫向 Tabs 吸頂用 End
  • clip(true):裁剪超出區(qū)域,防止 Tabs 內(nèi)容越界

關(guān)鍵③ —— nestedScroll:父子滾動聯(lián)動

WaterFlow({
  scroller: this.waterFlowScroller,
  footer: this.footerBuilder()
}) {
  LazyForEach(this.dataSource, (item: number) => {
    FlowItem() { this.waterFlowItem(item) }
  }, (item: number) => item.toString())
}
// 【關(guān)鍵③】nestedScroll:協(xié)調(diào)父子滾動容器之間的優(yōu)先級
.nestedScroll({
  scrollForward: NestedScrollMode.PARENT_FIRST,  // 向下滾動:列表先滾,到頂后外層 Scroll 接管
  scrollBackward: NestedScrollMode.SELF_FIRST    // 向上滾動:列表先滾回,再由外層 Scroll 接手
})

核心作用: 決定父子兩個滾動容器“誰先響應(yīng)滾動”。

scrollForward: PARENT_FIRST(向下滾動 / 手指上滑):

手指向上滑 → WaterFlow 響應(yīng)滾動
    ↓
WaterFlow 內(nèi)容滾動,列表向上移動
    ↓
WaterFlow 到達列表頂部(內(nèi)容已無剩余)
    ↓
滾動權(quán)交給外層 Scroll
    ↓
外層 Scroll 繼續(xù)向上滾動,Banner 和 TabBar 被推出可視區(qū)
    ↓
TabBar "吸"在屏幕頂部(已滾出外層 Scroll 的可視區(qū),緊貼標題欄)

scrollBackward: SELF_FIRST(向上滾動 / 手指下滑):

手指向下滑 → WaterFlow 優(yōu)先響應(yīng)
    ↓
WaterFlow 到達列表底部(內(nèi)容已無剩余)
    ↓
WaterFlow 響應(yīng)手指繼續(xù)滾動(上拉手勢)
    ↓
WaterFlow 到頂,滾動權(quán)交給外層 Scroll
    ↓
外層 Scroll 向下滑動,TabBar 從標題欄下方落回
    ↓
TabBar 重新出現(xiàn)在屏幕中
模式行為
scrollForward(下滑)PARENT_FIRST列表先滾,到頂后交給外層繼續(xù)
scrollBackward(上滑)SELF_FIRST外層先滾,TabBar 落位后列表再滾

如果子列表是 List,配置方式完全相同,將 WaterFlow 替換為 List 即可。

關(guān)鍵④ —— edgeEffect:吸頂邊界處理

WaterFlow({ ... })
.nestedScroll({ ... })
// 【關(guān)鍵④】edgeEffect:禁用回彈 + 保持邊緣感知,確保吸頂絲滑
.edgeEffect(EdgeEffect.None, { alwaysEnabled: true })

參數(shù)詳解:

EdgeEffect.None — 禁用彈性回彈

回彈效果表現(xiàn)吸頂場景下的影響
Spring(默認)列表到頂/到底時,手指松開后內(nèi)容彈回TabBar 在屏幕頂部抖動,無法穩(wěn)定"吸住"
None列表到頂/到底時,無回彈動畫配合 nestedScroll,TabBar 平滑停在標題欄下方

alwaysEnabled: true — 保持邊緣滾動感知(關(guān)鍵)

這是最容易遺漏的參數(shù),作用如下:

沒有 alwaysEnabled=true:
  WaterFlow 到頂 → 外層 Scroll 無法感知"已到頂" → 卡頓,無法交接滾動權(quán)

有 alwaysEnabled=true:
  WaterFlow 到頂 → 仍能感知邊緣狀態(tài) → nestedScroll 正常觸發(fā) → 絲滑交接

常見誤區(qū): 如果只寫 .edgeEffect(EdgeEffect.None) 而不設(shè)置 alwaysEnabled: true,會出現(xiàn)"卡頓"現(xiàn)象——列表到頂后外層 Scroll 短暫不響應(yīng),然后突然搶走滾動權(quán),導(dǎo)致 TabBar 在頂部抖動。

綜合效果:

  • 子列表到頂時,不觸發(fā)回彈動畫
  • 吸頂邊界時,alwaysEnabled: true 保證滾動感知不斷聯(lián)
  • 配合 nestedScroll 實現(xiàn)"列表到頂 → TabBar 絲滑吸住"的體驗

四、完整代碼示例

以下為抽取核心邏輯后的最小可運行示例,基于 Demo 頁面 WaterFlowStickyDemoPage

import { WindowHelper } from '@zebra/foundation/src/main/ets/utils/WindowHelper'

@ComponentV2
export struct WaterFlowStickyDemoPage {
  // ── 滾動器 ──────────────────────────────────────────────────
  private outerScroller: Scroller = new Scroller()     // 【關(guān)鍵①】外層滾動
  private waterFlowScroller: Scroller = new Scroller() // 【關(guān)鍵③】子列表滾動

  // ── 避讓高度 ──────────────────────────────────────────────
  //  = 狀態(tài)欄高度 + 標題欄高度
  private getAvoidanceHeight(): number {
    return WindowHelper.statusBarHeight + 25
  }

  // ── TabBar ──────────────────────────────────────────────────
  @Builder
  tabBarBuilder() {
    Column() {
      Row() {
        ForEach(['推薦', '熱門', '最新'], (tab: string, index: number) => {
          Column() {
            Text(tab)
              .fontSize(15)
              .fontColor(this.selectedTabIndex === index ? '#00CC66' : '#999999')
            Divider()
              .width(this.selectedTabIndex === index ? 20 : 0)
              .height(2)
              .backgroundColor('#00CC66')
              .margin({ top: 4 })
          }
          .width(60)
        })
      }
      .width('100%')
      .justifyContent(FlexAlign.Center)
      .height(44)
      Divider().width('100%').strokeWidth(1).color('#C8E6C9')
    }
    .width('100%')
    .backgroundColor('#E8F5E9')
  }

  // ── TabContent ─────────────────────────────────────────────
  @Builder
  tabContentBuilder() {
    WaterFlow({
      scroller: this.waterFlowScroller
    }) {
      LazyForEach(this.dataSource, (item: number) => {
        FlowItem() {
          Column() {
            Text(`${item}`)
          }
          .width('100%')
          .height(88 + (item % 7) * 28)
          .backgroundColor(colors[item % colors.length])
          .borderRadius(8)
        }
      }, (item: number) => item.toString())
    }
    .columnsTemplate('1fr 1fr')
    .columnsGap(12)
    .rowsGap(12)
    .padding({ left: 16, right: 16, top: 12, bottom: 12 })
    .scrollBar(BarState.Off)
    // 【關(guān)鍵③】nestedScroll
    .nestedScroll({
      scrollForward: NestedScrollMode.PARENT_FIRST,
      scrollBackward: NestedScrollMode.SELF_FIRST
    })
    // 【關(guān)鍵④】edgeEffect
    .edgeEffect(EdgeEffect.None, { alwaysEnabled: true })
  }

  // ── Tabs 主體 ───────────────────────────────────────────────
  @Builder
  contentBuilder() {
    Tabs({ index: $$this.selectedTabIndex }) {
      TabContent() { this.tabContentBuilder() }
        .tabBar(this.tabBarBuilder())
    }
    // 【關(guān)鍵②-a】Tabs 高度 = Scroll.Column 剩余空間
    .height(`calc(100% - ${this.getAvoidanceHeight()}vp)`)
    // 【關(guān)鍵②-b】tabBar 高度由 Builder 內(nèi)容撐開
    .barHeight('auto')
    .scrollable(false)
    .barPosition(BarPosition.Start)
    .clip(true)
  }

  // ── build ───────────────────────────────────────────────────
  build() {
    NavDestination() {
      Stack({ alignContent: Alignment.Top }) {
        // 頂部標題欄
        Column() {
          Text('頁面標題')
            .fontSize(17)
            .height(25)
        }
        .width('100%')
        .height(WindowHelper.statusBarHeight + 25)
        .padding({ left: 16 })
        .zIndex(2)

        // 外層 Scroll 【關(guān)鍵①】
        Scroll(this.outerScroller) {
          Column() {
            // Banner 頭圖區(qū)
            Column() {
              Text('Banner Area')
            }
            .width('100%')
            .height(180)
            .backgroundColor('#E8F5E9')

            // Tabs 吸頂區(qū)域 【關(guān)鍵②③④】
            this.contentBuilder()
          }
          .width('100%')
        }
        .width('100%')
        .height('100%')   // ← 關(guān)鍵①:height='100%',內(nèi)容回推高度
        .scrollBar(BarState.Off)
      }
      .width('100%')
      .height('100%')
    }
    .hideTitleBar(true)
  }
}

五、實戰(zhàn):HomeExplorePage 中的吸頂實現(xiàn)

生產(chǎn)環(huán)境中的 HomeExplorePage 與 Demo 邏輯完全一致,核心配置如下:

// HomeExplorePage.ets

// ① 外層滾動器 height='100%'
Scroll(this.exploreScroller) {
  Column() {
    // Banner + Tabs
    Tabs()
    // 【關(guān)鍵②-a】Tabs 高度 = Scroll.Column 剩余空間
    .height(`calc(100% - ${this.explorePageDataModel.avoidanceHeight}vp)`)
    // 【關(guān)鍵②-b】tabBar 高度由 Builder 內(nèi)容撐開
    .barHeight('auto')
    .scrollable(false)
    .barPosition(BarPosition.Start)
    .clip(true)
  }
}
.width('100%')
.height('100%')   // ← 關(guān)鍵①

// ② WaterFlow nestedScroll + edgeEffect
WaterFlow({ scroller: this.waterFlowScroller }) {
  LazyForEach(...)
}
// 【關(guān)鍵③】nestedScroll
.nestedScroll({
  scrollForward: NestedScrollMode.PARENT_FIRST,
  scrollBackward: NestedScrollMode.SELF_FIRST
})
// 【關(guān)鍵④】edgeEffect
.edgeEffect(EdgeEffect.None, { alwaysEnabled: true })

六、方案總結(jié)

關(guān)鍵屬性配置作用
① 外層 Scrollheight('100%')由子內(nèi)容回推總高度,產(chǎn)生滾動區(qū)域
②-a Tabs 高度calc(100% - avoidanceHeight)固定占據(jù) Scroll.Column 剩余空間,基準與 Scroll 一致
②-b barHeightbarHeight('auto')tabBar 高度由 Builder 內(nèi)容撐開,避免固定數(shù)值裁剪
③ nestedScrollPARENT_FIRST + SELF_FIRST列表與外層滾動器平滑聯(lián)動,實現(xiàn) TabBar 吸頂
④ edgeEffectEdgeEffect.None, { alwaysEnabled: true }吸頂邊界時不觸發(fā)回彈,保持 TabBar 穩(wěn)定

核心心法: 吸頂?shù)谋举|(zhì)是 父子滾動器的嵌套聯(lián)動 — 子列表到頂后讓出滾動權(quán)給外層 Scroll,上滑時外層 Scroll 先滾回再交還滾動權(quán)給列表。四個關(guān)鍵屬性缺一,聯(lián)動鏈條即斷裂。

到此這篇關(guān)于HarmonyOS鴻蒙吸頂效果實現(xiàn)方案的文章就介紹到這了,更多相關(guān)HarmonyOS鴻蒙吸頂效果內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 使用Git Bash向GitHub上傳本地項目

    使用Git Bash向GitHub上傳本地項目

    這篇文章介紹了使用Git Bash向GitHub上傳本地項目的方法,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-04-04
  • Blazor實現(xiàn)組件嵌套傳遞值的示例詳解

    Blazor實現(xiàn)組件嵌套傳遞值的示例詳解

    這篇文章主要為大家詳細介紹了Blazor實現(xiàn)組件嵌套傳遞值的相關(guān)知識,文中的示例代碼講解詳細,具有一定的學(xué)習(xí)價值,感興趣的可以了解一下
    2023-02-02
  • 初探 SOA

    初探 SOA

    SOA服務(wù)具有平臺獨立的自我描述XML文檔。Web服務(wù)描述語言(WSDL, Web Services Description Language)是用于描述服務(wù)的標準語言。
    2009-01-01
  • eBay 打造基于 Apache Druid 的大數(shù)據(jù)實時監(jiān)控系統(tǒng)

    eBay 打造基于 Apache Druid 的大數(shù)據(jù)實時監(jiān)控系統(tǒng)

    Apache Druid 是一個用于大數(shù)據(jù)實時查詢和分析的高容錯、高性能開源分布式時序數(shù)據(jù)庫系統(tǒng),旨在快速處理大規(guī)模的數(shù)據(jù),并能夠?qū)崿F(xiàn)快速查詢和分析。這篇文章主要介紹了eBay 如何打造基于 Apache Druid 的大數(shù)據(jù)實時監(jiān)控系統(tǒng)?需要的朋友可以參考下
    2019-06-06
  • HarmonyOS鎖屏音頻播放功能完整實現(xiàn)步驟

    HarmonyOS鎖屏音頻播放功能完整實現(xiàn)步驟

    HarmonyOS音頻模塊支持音頻業(yè)務(wù)的開發(fā),提供音頻相關(guān)的功能,主要包括音頻播放、音頻采集、音量管理和短音播放等,這篇文章主要介紹了HarmonyOS鎖屏音頻播放功能完整實現(xiàn)步驟的相關(guān)資料,需要的朋友可以參考下
    2026-06-06
  • 2020史上最全IDEA插件總結(jié)(推薦收藏)

    2020史上最全IDEA插件總結(jié)(推薦收藏)

    這篇文章主要介紹了2020史上最全IDEA插件總結(jié),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2020-06-06
  • Elasticsearch之文檔批量操作示例

    Elasticsearch之文檔批量操作示例

    這篇文章主要為大家介紹了Elasticsearch之文檔批量操作示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-04-04
  • Maui Blazor 使用攝像頭實現(xiàn)代碼

    Maui Blazor 使用攝像頭實現(xiàn)代碼

    由于Maui Blazor中界面是由WebView渲染,所以再使用Android的攝像頭時無法去獲取,因為原生的攝像頭需要綁定界面組件,這篇文章主要介紹了Maui Blazor 使用攝像頭實現(xiàn),需要的朋友可以參考下
    2023-01-01
  • 使用版本控制原因及Git與Subversion介紹

    使用版本控制原因及Git與Subversion介紹

    這篇文章主要為大家介紹了使用版本控制優(yōu)點原因介紹,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-04-04
  • Prometheus和NodeExporter安裝監(jiān)控數(shù)據(jù)說明

    Prometheus和NodeExporter安裝監(jiān)控數(shù)據(jù)說明

    這篇文章主要為大家介紹了Prometheus和node?exporter安裝監(jiān)控數(shù)據(jù)說明,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-07-07

最新評論

沁源县| 调兵山市| 大方县| 潞西市| 井陉县| 朔州市| 林州市| 张家港市| 景德镇市| 漠河县| 屏东县| 大方县| 抚远县| 阿尔山市| 白水县| 怀柔区| 德阳市| 元氏县| 鹤壁市| 米林县| 阿荣旗| 鸡西市| 如皋市| 邳州市| 铁岭市| 三明市| 资阳市| 延边| 沧源| 固原市| 鄂州市| 临朐县| 内黄县| 兴化市| 墨玉县| 渭源县| 文昌市| 兰溪市| 武乡县| 宁津县| 册亨县|