最近項目中有個需求,關于滑動組件 Scroll 底部指示器跟隨手勢滑動等比例展示的效果,下圖展示了要實現的效果。
image.png
自定義指示器組件
這里其實不是一個進度條,所以需要我們需要自定義繪制該組件,在鴻蒙中繪制組件單獨使用,用于在頁面上繪制指定的圖形。有7種繪制類型,分別為Circle(圓形)、Ellipse(橢圓形)、Line(直線)、Polyline(折線)、Polygon(多邊形)、Path(路徑)、Rect(矩形),這里我么使用 Rect 進行矩形繪制,一個黑色的 Rect當做指示器的背景,藍色當做指示器的進度。然后動態設置進度的左邊距。
@Entry
@Component
export struct RectIndicator {
@Prop marginLeft: number = 0 //indicator距離進度距離左邊間距,默認是 0
indicatorHeight: number = 20 //indicator的高度
indicatorWidth: number = 200 //indicator的背景寬度
indicatorProgressWidth: number = 160 //indicator 的進度寬度
build() {
Stack() {
//繪制矩形背景
Rect({ width: this.indicatorWidth, height: this.indicatorHeight })
.radius(this.indicatorHeight / 2)
.fill($r('app.color.bg_gray'))
.stroke(Color.Transparent)
//繪制矩形進度
Rect({ width: this.indicatorProgressWidth, height: this.indicatorHeight })
.radius(this.indicatorHeight / 2)
.fill($r('app.color.main_color'))
.margin({ left: this.marginLeft })
.stroke(Color.Transparent)
}.alignContent(Alignment.Start)
}
}
添加 Scroll 監聽
新建一個 RectIndicator 類,需要把兩個矩形層疊在一起,所以外層使用Stack布局進行嵌套。調用該自定義組件的時候,可以設置 組件的寬度(indicatorWidth) ,高度(indicatorHeight),進度的寬度(indicatorProgressWidth)以及動態設置進度的左邊距(marginLeft),可以通過監聽 Scroll 的滑動事件來動態設置 marginLeft。
Scroll(this.scroll) {
Row() {
ForEach(SUB_MENUS, (item: Menu, index) => {
Column() {
Image(item.menuIcon).width(28).height(28)
Text(item.menuText).fontSize(12).fontColor($r("app.color.text_two")).margin({ top: 5 })
}.width("20%").id("item")
})
}
}.scrollable(ScrollDirection.Horizontal)
.margin({ top: 12 })
.scrollBar(BarState.Off)
//滑動監聽
.onDidScroll((_xOffset, _yOffset, scrollState) => {
//當前狀態為滑動狀態
if (scrollState == ScrollState.Scroll) {
//獲取滾動的偏移量,通過控制器獲取比較準確
const currentOffsetX = this.scroll.currentOffset().xOffset
LogUtil.debug("滑動偏移量", vp2px(currentOffsetX).toString())
//子組件寬度*2=未顯示出來的組件/指示器灰色部分
let ratio = this.itemWidth * 2 / 10
//指示器進度的偏移量=scroll 的偏移量/比率
this.indicatorLeft = vp2px(currentOffsetX) / ratio
}
})
onDidScroll 可以對滑動組件(包括但不限于 Scroll)設置監聽,這里判斷 scrollState 為滑動狀態,獲取當前滑動的偏移量 currentOffsetX,通過Scroll 的偏移量計算出 指示器的左間距(indicatorLeft)。
使用自定義RectIndicator組件
RecIndicator({
marginLeft: this.indicatorLeft, //左間距
indicatorHeight: 4, //指示器的高度
indicatorWidth: 30, //指示器的背景寬度
indicatorProgressWidth: 20 //指示器進度的寬度
}).margin({ top: 8, bottom: 8 })
使用方法:調用RecIndicator自定義組件,將高度,寬度等相關參數傳遞組件內,這里的進度寬度,可以通過 Scroll 組件長度計算出來,這里我就這只給一個寬度,不影響使用。
需要注意的是,indicatorLeft需要加一個@State 注解,保證組件可以根據indicatorLeft來實時刷新 UI。