侧栏联动功能模块:
1、切换左侧导航,右侧滚动到对应的内容。
2、滚动右侧的内容,左侧会切换对应的导航。
1、涉及知识点
List(列表组件)、ListItemGroup(列表item分组)
2、效果预览
3、实现思路
整体UI处理:左右两侧均为List组件,一层树状数据,左侧取顶层数据,右侧取一层数据,并使用ListItemGroup对List进行分组处理。
1、左侧点击:通过Scroll组件的 scrollToIndex 方法滚动到对应的位置;
2、右侧滚动左侧跟随:通过 onScrollIndex 监听滚动的Index位置;
// onScrollIndex监听和左侧点击
scrollIndexChangeAction(index: number, isClassify: boolean) {
if (this.currentIndex !== index) {
// 改变状态.
this.currentIndex = index;
if (isClassify) {
//滚动
this.scroller.scrollToIndex(index);
} else {
// 判断左侧滚动还是右侧滚动
this.sidebarScroller.scrollToIndex(index);
}
}
}
4、组件封装和调用
4.1 组件封装
@Component
export struct SidebarItem {
@Prop isSelected: boolean = false;
classifyName?: string;
onClickAction = () => {}
build() {
Text(this.classifyName)
.fontSize(14)
.fontColor(this.isSelected ? '#182431' : '#99182431')
.fontFamily(this.isSelected ? 'HarmonyHeiTi-Medium' : 'HarmonyHeiTi')
.fontWeight(this.isSelected ? 500 : 400)
.textAlign(TextAlign.Center)
.backgroundColor(this.isSelected ? '#F1F3F5' : '')
.width('100%')
.height(56)
.onClick(this.onClickAction)
}
}
@Component
export default struct SidebarLinkage {
@BuilderParam CourseItem: (item) => void;
@Prop dataList: Array<any> = [];
@Prop requestSuccess: boolean = false;
@State currentIndex: number = 0; // selected classify index.
private sidebarScroller: Scroller = new Scroller();
private scroller: Scroller = new Scroller();
@Builder blcokHeader(classifyName: string) {
Row() {
Text(classifyName)
.fontSize(18)
.fontColor('#182431')
.fontFamily('HarmonyHeiTi-Medium')
.fontWeight(500)
}
.padding({ left: 8 })
.height(56)
.width('100%')
.backgroundColor('#F1F3F5')
}
scrollIndexChangeAction(index: number, isClassify: boolean) {
if (this.currentIndex !== index) {
// change the classify status.
this.currentIndex = index;
if (isClassify) {
// scroll the course scroll.
this.scroller.scrollToIndex(index);
} else {
// scroll the classify scroll.
this.sidebarScroller.scrollToIndex(index);
}
}
}
build() {
Row() {
if (this.requestSuccess) {
List({ scroller: this.sidebarScroller }) {
ForEach(this.dataList, (item: any, index?: number) => {
ListItem() {
SidebarItem({
classifyName: item.classifyName,
isSelected: this.currentIndex === index,
onClickAction: () => {
if (index !== undefined) {
this.scrollIndexChangeAction(index, true);
}
}
})
}
}, (item: any) => item.classifyName + this.currentIndex)
}
.height('100%')
.width(100)
.backgroundColor('#0D182431')
.scrollBar(BarState.Off)
List({ scroller: this.scroller }) {
ForEach(this.dataList, (item: any) => {
ListItemGroup({
header: this.blcokHeader(item.classifyName),
space: 12
}) {
ForEach(item.courseList, (courseItem: any) => {
ListItem() {
this.CourseItem({ itemStr: JSON.stringify(courseItem) })
}
}, (courseItem: any) => `${courseItem.courseId}`)
}
}, (item: any) => `${item.classifyId}`)
}
.padding({ left: 8, right: 12 })
.sticky(StickyStyle.Header)
.layoutWeight(1)
.edgeEffect(EdgeEffect.None)
.onScrollIndex((start: number) => this.scrollIndexChangeAction(start, false))
} else {
Text('loading...')
.fontFamily('HarmonyHeiTi-Medium')
.textAlign(TextAlign.Center)
.fontSize(18)
.height('100%')
.width('100%')
}
}
.backgroundColor('#F1F3F5')
}
}
4.2 组件调用
import SidebarLinkage from '../../../../../SidebarLinkage/src/main/ets/components/SidebarLinkage/SidebarLinkage'
@Entry
@Component
struct IndexPage {
@State requestSuccess: boolean = false; // is loading data.
@State classifyList: Array<any> = [];
aboutToAppear() {
// loading data.
setTimeout(() => {
this.classifyList = [
{ "classifyId": 1, "classifyName": "音乐",
"courseList": [{
"classifyId": 0,
"courseId": 1,
"courseName": "YouTube1",
"imageUrl": $r('app.media.youtube'),
"price": 0
},{
"classifyId": 1,
"courseId": 2,
"courseName": "YouTube2",
"imageUrl": $r('app.media.youtube'),
"price": 12
},{
"classifyId": 1,
"courseId": 3,
"courseName": "YouTube3",
"imageUrl": $r('app.media.youtube'),
"price": 22
},{
"classifyId": 1,
"courseId": 4,
"courseName": "YouTube4",
"imageUrl": $r('app.media.youtube'),
"price": 43
},{
"classifyId": 1,
"courseId": 5,
"courseName": "YouTube5",
"imageUrl": $r('app.media.youtube'),
"price": 430
},{
"classifyId": 1,
"courseId": 6,
"courseName": "YouTube6",
"imageUrl": $r('app.media.youtube'),
"price": 120
}]
},
{ "classifyId": 2, "classifyName": "游戏",
"courseList": [{
"classifyId": 2,
"courseId": 1,
"courseName": "Twitter1",
"imageUrl": $r('app.media.twitter'),
"price": 797970
},{
"classifyId": 2,
"courseId": 2,
"courseName": "Twitter2",
"imageUrl": $r('app.media.twitter'),
"price": 98790
},{
"classifyId": 2,
"courseId": 3,
"courseName": "Twitter3",
"imageUrl": $r('app.media.twitter'),
"price": 7337
},{
"classifyId": 2,
"courseId": 4,
"courseName": "Twitter4",
"imageUrl": $r('app.media.twitter'),
"price": 33330
},{
"classifyId": 2,
"courseId": 5,
"courseName": "Twitter5",
"imageUrl": $r('app.media.twitter'),
"price": 7770
},{
"classifyId": 2,
"courseId": 6,
"courseName": "Twitter6",
"imageUrl": $r('app.media.twitter'),
"price": 30
}]
},
{ "classifyId": 3, "classifyName": "旅游",
"courseList": [{
"classifyId": 3,
"courseId": 1,
"courseName": "whatsapp1",
"imageUrl": $r('app.media.whatsapp'),
"price": 6330
},{
"classifyId": 3,
"courseId": 2,
"courseName": "whatsapp2",
"imageUrl": $r('app.media.whatsapp'),
"price": 730
},{
"classifyId": 3,
"courseId": 3,
"courseName": "whatsapp3",
"imageUrl": $r('app.media.whatsapp'),
"price": 330
},{
"classifyId": 3,
"courseId": 4,
"courseName": "whatsapp4",
"imageUrl": $r('app.media.whatsapp'),
"price": 730
},{
"classifyId": 3,
"courseId": 5,
"courseName": "whatsapp5",
"imageUrl": $r('app.media.whatsapp'),
"price": 0
},{
"classifyId": 3,
"courseId": 6,
"courseName": "whatsapp6",
"imageUrl": $r('app.media.whatsapp'),
"price": 0
},{
"classifyId": 3,
"courseId": 7,
"courseName": "whatsapp7",
"imageUrl": $r('app.media.whatsapp'),
"price": 70
},{
"classifyId": 3,
"courseId": 8,
"courseName": "whatsapp8",
"imageUrl": $r('app.media.whatsapp'),
"price": 60
},{
"classifyId": 3,
"courseId": 9,
"courseName": "whatsapp9",
"imageUrl": $r('app.media.whatsapp'),
"price": 40
},{
"classifyId": 3,
"courseId": 10,
"courseName": "whatsapp10",
"imageUrl": $r('app.media.whatsapp'),
"price": 20
},{
"classifyId": 3,
"courseId": 11,
"courseName": "whatsapp11",
"imageUrl": $r('app.media.whatsapp'),
"price": 0
}]
}
];
this.requestSuccess = true;
}, 2000);
}
@Builder CourseItemBuilder(item: any) {
Row() {
Image(JSON.parse(item.itemStr) !== undefined ? JSON.parse(item.itemStr)?.imageUrl : '')
.height('100%')
.aspectRatio(1)
Column() {
Text(JSON.parse(item.itemStr)?.courseName)
.fontSize(14)
.fontColor('#182431')
.fontFamily('HarmonyHeiTi-Medium')
.maxLines(2)
.textOverflow({ overflow: TextOverflow.Clip })
.lineHeight(20)
.width('100%')
Text('$ 999.99')
.fontSize(16)
.fontColor(Color.Pink)
.fontFamily('HarmonyHeiTi-Medium')
Text(JSON.parse(item.itemStr)?.price === 0 ? '免费' : `$${JSON.parse(item.itemStr)?.price}`)
.fontSize(18)
.fontColor('#FA2A2D')
.fontFamily('HarmonyHeiTi-Medium')
}
.padding(12)
.layoutWeight(1)
.alignItems(HorizontalAlign.Start)
.justifyContent(FlexAlign.SpaceBetween)
.height('100%')
}
.clip(true)
.borderRadius(18)
.backgroundColor($r('app.color.start_window_background'))
.width('100%')
.height(96)
}
build() {
Column() {
SidebarLinkage({
dataList: this.classifyList,
requestSuccess: this.requestSuccess,
CourseItem: this.CourseItemBuilder
})
}
}
}
源码:https://gitee.com/bingtengaoyu/harmonyos-advanced-componen/tree/master/SidebarLinkage