Demo效果
@Entry
@Component
struct StickyNestedScroll {
@State message: string = 'Hello World'
@State arr: number[] = []
scroller = new Scroller()
@Styles
listCard() {
.backgroundColor(Color.White)
.height(72)
.width("100%")
.borderRadius(12)
}
build() {
Scroll(this.scroller) {
Column() {
Stack({ alignContent: Alignment.Top }) {
Column() {
}.height("200vp").width('100%').backgroundImage($r('app.media.icon_home_top'))
// Text('吸顶').width('100%').height(40).backgroundColor(Color.Black).zIndex(999)
}
Tabs({ barPosition: BarPosition.Start }) {
TabContent() {
List({ space: 10 }) {
ForEach(this.arr, (item: number) => {
ListItem() {
Text("item" + item)
.fontSize(16)
}.listCard()
}, (item: string) => item)
}.width("100%")
.edgeEffect(EdgeEffect.Spring)
.nestedScroll({
scrollForward: NestedScrollMode.PARENT_FIRST,
scrollBackward: NestedScrollMode.SELF_FIRST
})
}.tabBar("Tab1")
TabContent() {
}.tabBar("Tab2")
}
.vertical(false)
.backgroundColor(Color.Brown)
.height("100%")
}.width("100%")
}
.edgeEffect(EdgeEffect.Spring)
.friction(0.6)
.backgroundColor('#DCDCDC')
.scrollBar(BarState.Off)
.width('100%')
.height('100%')
}
aboutToAppear() {
for (let i = 0; i < 30; i++) {
this.arr.push(i)
}
}
@Builder
testHead() {
Text('吸顶').width('100%').height(40).backgroundColor(Color.Black).zIndex(999)
}
}
项目实战效果图
- Tab:(企业统计)
@Builder
TabWidget() {
Row() {
Text('企业统计')
.fontColor($r('app.color.color303242')).fontSize(16).margin({ left: 12 })
}
.height('100%')
.width('calc(100% - 30vp)')
.borderRadius({ topLeft: 8, topRight: 8 })
.backgroundColor(Color.White)
.margin({ left: 15, right: 15 })
.onClick(() => {
this.scroller.scrollTo({ xOffset: 0, yOffset: 2000 })
})
}
- 完整项目代码
仔细看代码里的注释
@Entry
@Component
export struct HomePage {
@State curIndex: number = 0
scroller: Scroller = new Scroller()
@State currentOffset: number = 0;
@StorageLink('systemBarHeight') systemBarHeight: number = 0
@State topOpacity: number = 1;
@State searchHint: string = '请输入企业名称';
@State banner?: BannerBean = new BannerBean()
@State protMarketBean?: ProspectMarketBean[] = new Array<ProspectMarketBean>()
aboutToAppear(): void {
}
build() {
Stack({ alignContent: Alignment.Top }) {
Scroll(this.scroller) {
Column() {
Column() {
// tab 企业统计上面的组件 这里省略 l里面没内容的话 可以设置固定高度测试
// ....
}.width('100%')
Tabs({ barPosition: BarPosition.Start }) {
TabContent() {
// 注意注意: 这里是tab 企业统计下面的界面 这里要用list
List({ space: 10 }) {
ListItem() {
Column() {
HomeWebWidget()
if (this.protMarketBean && this.protMarketBean.length > 0) {
HomeEnterpriseLib({ protMarketBean: this.protMarketBean }).margin({ top: 10 })
}
}.width('100%')
}
}.width("100%").height('100%')
// edgeEffect nestedScroll一定要设置
.edgeEffect(EdgeEffect.Spring)
.nestedScroll({
scrollForward: NestedScrollMode.PARENT_FIRST,
scrollBackward: NestedScrollMode.SELF_FIRST
})
}.tabBar(this.TabWidget())
}
.barWidth('100%')
.barHeight(40)
.vertical(false)
.margin({ top: 10 })
//60=搜索组件的高度 this.systemBarHeight= 状态栏的高度 这样吸顶才是刚好处于搜索组件下方 可自行调整
.height(`calc(100% - ${60 + px2vp(this.systemBarHeight)}vp)`)
}.width("100%")
.backgroundImage($r('app.media.icon_home_top'))
.backgroundImageSize({ width: '100%', height: '50%' })
}
.onScroll(() => {
// 滚动监听 根据偏移量 顶部搜索栏的界面效果
this.currentOffset = this.scroller.currentOffset().yOffset;
// 根据偏移控制透明度
this.topOpacity = (140 - this.currentOffset) / 140; 例
})
.edgeEffect(EdgeEffect.Spring)
.friction(0.6)
.backgroundColor('#F3F3F3')
.scrollBar(BarState.Off)
.width('100%')
.height('100%')
// 滚动偏移量大于0时 显示顶部搜索
if (this.currentOffset > 0) {
this.SearchHeaderWidget()
}
}
}
@Builder
TabWidget() {
Row() {
Text('企业统计')
.fontColor($r('app.color.color303242')).fontSize(16).margin({ left: 12 })
}
.height('100%')
.width('calc(100% - 30vp)')
.borderRadius({ topLeft: 8, topRight: 8 })
.backgroundColor(Color.White)
.margin({ left: 15, right: 15 })
.onClick(() => {
this.scroller.scrollTo({ xOffset: 0, yOffset: 2000 })
})
}
@Builder
SearchHeaderWidget() {
Column() {
Row() {
Image($r('app.media.icon_search')).width(18).height(18).margin({ left: 15 })
Text(this.searchHint).fontColor('#C6C9CF').fontSize(13).margin({ left: 8 })
}
.height(40)
.width('100%')
.backgroundColor(Color.White)
.borderRadius(50)
.onClick(() => {
router.pushUrl({ url: RouterPath.SEARCH, params: { tabIndex: 1 } })
})
.margin({ top: px2vp(this.systemBarHeight) })
}.backgroundColor('#0256FF')
.padding({ left: 15, right: 15, bottom: 10, top: 10 })
.opacity(1 - this.topOpacity) // 顶部搜索组件的透明度
}
}