赞
踩
HarmonyOS应用开发02-程序框架UIAbility、启动模式与路由跳转
HarmonyOS应用开发03-基础组件-让我们来码出复杂酷炫的UI
想要实现一个列表,在前面是使用 ForEach 循环 StudentListItem.est 构建的,不会由滑动效果,数据源增加时,会发现现在这个“列表”显示不全,而且也是无法滑动的。对于数据源数量较多、需要分页加载的列表,我们使用 List去实现。
接下来学习使用HarmonyOS-ArkTS语言开发方式中的基本组件,这样我们就可以使用基本组件去实现较为复杂丰富的UI。
Column表示沿垂直方向布局的容器。Row表示沿水平方向布局的容器。
在布局容器中,默认存在两根轴,分别是主轴和交叉轴,这两个轴始终是相互垂直的。不同的容器中主轴的方向不一样的。
子组件在主轴方向上的对齐使用justifyContent属性来设置,其参数类型是FlexAlign。FlexAlign定义了以下几种类型:
子组件在交叉轴方向上的对齐方式使用alignItems属性来设置。
Column和Row容器的接口都有一个可选参数space,表示子组件在主轴方向上的间距。
容器组件 | 接口 |
---|---|
Column | Column(value?:{space?: string |
Row | Row(value?:{space?: string |
List组件的相关API参考:List组件
Grid组件的相关API参考:Grid组件
循环渲染(ForEach):循环渲染
在上文Demo中增加 getStudentList2
返回数据数量:
import { DataItemBean } from './DataItemBean'; export class DataModel { getStudentList2(): Array<DataItemBean> { let studentList: DataItemBean[] = [ { "title": "丁程鑫", "image": "https://c-ssl.duitang.com/uploads/item/201805/06/20180506084619_2svWA.jpeg", }, { "title": "贺峻霖", "image": "https://c-ssl.duitang.com/uploads/blog/202107/05/20210705215458_36c2b.jpg", }, { "title": "肖战", "image": "https://c-ssl.duitang.com/uploads/blog/202112/17/20211217211133_85430.jpeg", }, ... { "title": "丁程鑫2", "image": "https://c-ssl.duitang.com/uploads/item/201805/06/20180506084619_2svWA.jpeg", }, { "title": "贺峻霖2", "image": "https://c-ssl.duitang.com/uploads/blog/202107/05/20210705215458_36c2b.jpg", }, { "title": "肖战2", "image": "https://c-ssl.duitang.com/uploads/blog/202112/17/20211217211133_85430.jpeg", }, ... ]; return studentList; } } export default new DataModel();
再次运行APP,会发现数据充满整个屏幕,而且是不能进行滑动的,数据显示不全。要想可以滑动列表显示全部数据,这时就需要用到现行列表组件。常见的列表有线性列表(List列表)和网格布局(Grid列表)。
列表往往由多个列表项组成,所以我们需要在List组件中使用多个ListItem组件来构建列表,这就会导致代码的冗余。使用循环渲染(ForEach)遍历数组的方式构建列表,可以减少重复代码
在 StudentListPage.ets
代码中:
ForEach(this.studentList2, (item: DataItemBean) => {
StudentListItem({ studentData: item })
}, (item: string) => JSON.stringify(item))
// 列表
List({ space: 16 }) {
ForEach(this.studentList2, (item: DataItemBean) => {
ListItem() {
StudentListItem({ studentData: item })
}
}, (item: string) => JSON.stringify(item))
}
.width('100%')
.height('50%')
运行代码,即可滑动显示所有数据。
List组件子组件ListItem之间默认是没有分割线的,部分场景子组件ListItem间需要设置分割线,这时候您可以使用List组件的divider属性。divider属性包含四个参数:
List({ space: 16 }) {
ForEach(this.studentList2, (item: DataItemBean) => {
ListItem() {
StudentListItem({ studentData: item })
}
}, (item: string) => JSON.stringify(item))
}
.width('100%')
.height('50%')
.divider({ strokeWidth: 3, color: Color.Gray, startMargin: 30, endMargin: 0 })
List组件里面的列表项默认是按垂直方向排列的,如果您想让列表沿水平方向排列,您可以将List组件的listDirection属性设置为Axis.Horizontal。
listDirection参数类型是Axis,定义了以下两种类型:
listDirection(Axis.Vertical)
listDirection(Axis.Horizontal)
使用ForEach渲染网格布局
columnsTemplate
: 设置当前网格布局列的数量,不设置时默认1列。设置columnsTemplate的值为’1fr 1fr 1fr 1fr’,表示这个网格为4列,将Grid允许的宽分为4等分,每列占1份;rowsTemplate
:设置当前网格布局行的数量,不设置时默认1行。rowsTemplate的值为’1fr 1fr 1fr 1fr’,表示这个网格为4行,将Grid允许的高分为4等分,每行占1份。columnsGap
:设置列与列的间距。eg:使用columnsGap设置列间距为10vp.rowsGap
:设置行与行的间距。eg:使用rowsTemplate设置行间距也为10vp。layoutDirection
设置布局的主轴方向。默认值:GridDirection.Row1、网格布局如果使用了固定的行数和列数,则构建出的网格是不可滚动的。
2、有时候因为内容较多,需要通过滚动的方式来显示更多的内容,就需要一个可以滚动的网格布局。只需要设置rowsTemplate和columnsTemplate中的一个即可。
(1)、在 StudentListItem.ets
代码中修改Item布局:
import router from '@ohos.router'; import CommonConstants from '../common/constants/CommonConstants'; import { DataItemBean } from '../viewmodel/DataItemBean'; @Component export default struct StudentListItem { @State isChecked: boolean = false; private studentData?: DataItemBean; aboutToAppear() { console.log("DataItemBean", this.studentData.title) console.log("DataItemBean", this.studentData.image) } @Builder checkIcon(icon: Resource) { Image(icon) .objectFit(ImageFit.Contain) .width($r('app.float.checkbox_width')) .height($r('app.float.checkbox_height')) .margin($r('app.float.checkbox_margin')) } build() { Column() { Row() { Text(this.studentData.title) .fontColor(this.isChecked ? Color.Red : Color.Black) .fontSize(this.isChecked ? $r('app.float.item_checked_font_size') : $r('app.float.item_font_size')) .fontWeight(500) .opacity(this.isChecked ? 0.5 : 1.0) .decoration({ type: this.isChecked ? TextDecorationType.LineThrough : TextDecorationType.None }) Blank() Image($r('app.media.ic_arrow_next')) .width('30vp') .height('30vp') .onClick(() => { // console.log('Next Click' + this.name); console.log('Next Click' + this.studentData.title); console.log('Next Click' + this.studentData.image); router.pushUrl({ // url: 'pages/StudentDetailPage', url: CommonConstants.STUDENT_DETAIL_URL, params: { // name: this.name, studentData: this.studentData } }).catch((error) => { console.log('Next Click', 'IndexPage push error' + JSON.stringify(error)); }) }) } .width('100%') .padding({ left: 10, right: 10 }) if (this.isChecked) { this.checkIcon($r('app.media.ic_checked')) } else { this.checkIcon($r('app.media.ic_unchecked')) } } .borderRadius(10) .backgroundColor($r('app.color.start_window_background')) .width('100%') .height($r('app.float.grid_item_height')) .padding({ top: 10 }) .justifyContent(FlexAlign.SpaceEvenly) .onClick(() => { this.isChecked = !this.isChecked; }) } }
(2)、在 StudentListPage.ets
代码中修改List组件为Grid组件:
import DataModel from '../viewmodel/DataModel'; import StudentListItem from '../view/StudentListItem'; import router from '@ohos.router'; import prompt from '@system.prompt'; import { DataItemBean } from '../viewmodel/DataItemBean'; // import DataItemBean from '../viewmodel/DataItemBean'; const TAG = '[StudentListPage]'; @Entry @Component export struct StudentListPage { // private studentList: Array<string> = []; private studentList2: Array<DataItemBean> = []; @State backMessage: string = ''; @State isRowModel: boolean = true; // 调用router.back()方法,不会新建页面,返回的是原来的页面,在原来页面中@State声明的变量不会重复声明, // 以及也不会触发页面的aboutToAppear()生命周期回调,因此无法直接在变量声明以及页面的aboutToAppear() // 生命周期回调中接收和解析router.back()传递过来的自定义参数。 onPageShow() { this.backMessage = router.getParams()?.['backMessage']; console.log(TAG, 'StudentDetailPage返回数据:StudentListPage => ' + this.backMessage) if (this.backMessage != undefined && this.backMessage != "") { this.showToast(this.backMessage) } } aboutToAppear() { // this.studentList = DataModel.getStudentList(); this.studentList2 = DataModel.getStudentList2(); // this.backMessage = router.getParams()?.['backMessage']; } showToast(message: string) { prompt.showToast({ message: message }) } build() { Navigation() { Row() { if (this.isRowModel) { Grid() { ForEach(this.studentList2, (item: DataItemBean) => { GridItem() { StudentListItem({ studentData: item, isRowModel: false }) } }, (item: string) => JSON.stringify(item)) } // .width('90%') .columnsTemplate('1fr 1fr 1fr') // .rowsTemplate('1fr 1fr 1fr') .columnsGap(10) .rowsGap(10) // .layoutDirection(GridDirection.Row) } .width('90%') // .margin({ left: 10, right: 10 }) } .title('学生名单') .size({ width: '100%', height: '100%' }) .titleMode(NavigationTitleMode.Mini) .hideBackButton(true) .menus(this.NavigationMenus()) .backgroundColor($r('app.color.page_background')) } }
Tabs组件的更多属性和参数的使用,可以参考API:Tabs
@Builder装饰器的使用,可以参考:@Builder
使用Tabs组件来实现类似Android开发中的BottomNavigationBar组件效果、TabIndicator效果;
TabContent
的属性设 tabBar
置 TabBar
的显示内容。使用通用属性width和height设置了Tabs组件的宽高,使用barWidth和barHeight设置了TabBar的宽度和高度barMode
设置TabBar布局模式使用Tabs组件接口中的参数barPosition设置页签位置。此外页签显示位置还与vertical属性相关联,vertical属性用于设置页签的排列方向,当vertical的属性值为false(默认值)时页签横向排列,为true时页签纵向排列。
BarPosition.Start
vertical属性方法设置为false(默认值)时,页签位于容器顶部。
vertical属性方法设置为true时,页签位于容器左侧。
BarPosition.End
vertical属性方法设置为false时,页签位于容器底部。
vertical属性方法设置为true时,页签位于容器右侧。
@State currentIndex: number = CommonConstants.STUDENT_LIST_TAB_INDEX // 设置Tabs控制器 Tabs组件的控制器,用于控制Tabs组件进行页签切换。不支持一个TabsController控制多个Tabs组件 private tabsController: TabsController = new TabsController(); // TabContent的tabBar属性除了支持string类型,还支持使用@Builder装饰器修饰的函数。 // 可以使用@Builder装饰器,构造一个生成自定义TabBar样式的函数,实现上面的底部页签效果 @Builder TabBuilder(title: string, index: number, selectImage: Resource, normalImage: Resource) { Column() { Image(this.currentIndex === index ? selectImage : normalImage) .width($r('app.float.mainPage_baseTab_size')) .height($r('app.float.mainPage_baseTab_size')) Text(title) .margin({ top: $r('app.float.mainPage_baseTab_top') }) .fontSize(this.currentIndex === index ? $r('app.float.main_tab_selected_fontSize') : $r('app.float.main_tab_normal_fontSize')) .fontColor(this.currentIndex === index ? $r('app.color.mainPage_selected_color') : $r('app.color.mainPage_normal_color')) } .justifyContent(FlexAlign.Center) .height($r('app.float.mainPage_barHeight')) .width(CommonConstants.FULL_WIDTH) .onClick(() => { this.currentIndex = index; // 控制Tabs切换到指定页签 this.tabsController.changeIndex(this.currentIndex); }) }
MainPage.ets
,初始化TabsController去设置Tabs组件;import CommonConstants from '../common/constants/CommonConstants' import GalleryPage from '../view/GalleryPage'; import { StudentListPage } from './StudentListPage'; @Entry @Component struct MainPage { @State currentIndex: number = CommonConstants.STUDENT_LIST_TAB_INDEX // 设置Tabs控制器 Tabs组件的控制器,用于控制Tabs组件进行页签切换。不支持一个TabsController控制多个Tabs组件 private tabsController: TabsController = new TabsController(); // TabContent的tabBar属性除了支持string类型,还支持使用@Builder装饰器修饰的函数。 // 可以使用@Builder装饰器,构造一个生成自定义TabBar样式的函数,实现上面的底部页签效果 @Builder TabBuilder(title: string, index: number, selectImage: Resource, normalImage: Resource) { Column() { Image(this.currentIndex === index ? selectImage : normalImage) .width($r('app.float.mainPage_baseTab_size')) .height($r('app.float.mainPage_baseTab_size')) Text(title) .margin({ top: $r('app.float.mainPage_baseTab_top') }) .fontSize(this.currentIndex === index ? $r('app.float.main_tab_selected_fontSize') : $r('app.float.main_tab_normal_fontSize')) .fontColor(this.currentIndex === index ? $r('app.color.mainPage_selected_color') : $r('app.color.mainPage_normal_color')) } .justifyContent(FlexAlign.Center) .height($r('app.float.mainPage_barHeight')) .width(CommonConstants.FULL_WIDTH) .onClick(() => { this.currentIndex = index; // 控制Tabs切换到指定页签 this.tabsController.changeIndex(this.currentIndex); }) } build() { Tabs({ barPosition: BarPosition.End, controller: this.tabsController, }) { TabContent() { StudentListPage() } .tabBar( this.TabBuilder( CommonConstants.STUDENT_LIST_TITLE, CommonConstants.STUDENT_LIST_TAB_INDEX, $r('app.media.ic_home_selected'), $r('app.media.ic_home_normal') )) TabContent() { GalleryPage() } .tabBar( this.TabBuilder( CommonConstants.PICTURE_TITLE, CommonConstants.PICTURE_TAB_INDEX, $r('app.media.ic_checked'), $r('app.media.ic_unchecked') )) } .vertical(true) .scrollable(true) // 设置为true时可以通过滑动页面进行页面切换,为false时不可滑动切换页面。默认值:true .width(CommonConstants.FULL_WIDTH) // 设置Tabs组件宽度 .height(CommonConstants.FULL_HEIGHT) // 设置Tabs组件高度 .backgroundColor(Color.White) // 设置Tabs组件背景颜色 .barWidth(CommonConstants.FULL_WIDTH) // 设置TabBar宽度 .barHeight($r('app.float.mainPage_barHeight')) // 设置TabBar高度 .barMode(BarMode.Scrollable) // Tabs的布局模式有Fixed(默认)和Scrollable两种 .onChange((index: number) => { // Tabs的布局模式有Fixed(默认)和Scrollable两种 this.currentIndex = index; }) } }
其中在 GalleryPage().ets
中先放置一个Text组件显示页面;
@Component
export default struct GalleryPage {
build() {
Column() {
Text('Gallery')
.fontSize('22fp')
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
.backgroundColor($r('app.color.page_background'))
}
}
设置 Tabs
组件的属性 barPosition: BarPosition.End
,并且设置 .vertical(false)
,就将页签位于容器底部,设置TabBar宽度为 100%
,高度设置为 56vp
@Entry @Component struct MainPage { ... build() { Tabs({ barPosition: BarPosition.End, controller: this.tabsController, }) { ... } .vertical(false) .scrollable(true) // 设置为true时可以通过滑动页面进行页面切换,为false时不可滑动切换页面。默认值:true .width(CommonConstants.FULL_WIDTH) // 设置Tabs组件宽度 .height(CommonConstants.FULL_HEIGHT) // 设置Tabs组件高度 .backgroundColor(Color.White) // 设置Tabs组件背景颜色 .barWidth(CommonConstants.FULL_WIDTH) // 设置TabBar宽度 .barHeight($r('app.float.mainPage_barHeight')) // 设置TabBar高度 .barMode(BarMode.Fixed) // Tabs的布局模式有Fixed(默认)和Scrollable两种 .onChange((index: number) => { // Tabs的布局模式有Fixed(默认)和Scrollable两种 this.currentIndex = index; }) } }
设置 Tabs
组件的属性 barPosition: BarPosition.End
,并且设置 .vertical(true)
,就将页签位于容器底部,设置TabBar宽度为 56vp
,高度设置为100%
@Entry @Component struct MainPage { ... build() { Tabs({ barPosition: BarPosition.End, controller: this.tabsController, }) { ... } .vertical(true) .scrollable(true) // 设置为true时可以通过滑动页面进行页面切换,为false时不可滑动切换页面。默认值:true .width(CommonConstants.FULL_WIDTH) // 设置Tabs组件宽度 .height(CommonConstants.FULL_HEIGHT) // 设置Tabs组件高度 .backgroundColor(Color.White) // 设置Tabs组件背景颜色 .barWidth($r('app.float.mainPage_barHeight')) // 设置TabBar宽度 .barHeight(CommonConstants.FULL_WIDTH) // 设置TabBar高度 .barMode(BarMode.Fixed) // Tabs的布局模式有Fixed(默认)和Scrollable两种 .onChange((index: number) => { // Tabs的布局模式有Fixed(默认)和Scrollable两种 this.currentIndex = index; }) } }
滑块视图容器,提供子组件滑动轮播显示的能力
SwiperController
给组件绑定一个控制器,用来控制组件翻页
子组件是否自动播放。默认值:false
loop为false时,自动轮播到最后一页时停止轮播。手势切换后不是最后一页时继续播放。
使用自动播放时播放的时间间隔,单位为毫秒。默认值:3000
是否启用导航点指示器。默认值:true
是否开启循环。默认值:true
设置为true时表示开启循环,在LazyForEach懒循环加载模式下,加载的组件数量建议大于5个。
子组件切换的动画时长,单位为毫秒。默认值:400
是否为纵向滑动。默认值:false
设置子组件与子组件之间间隙。默认值:0
说明:不支持设置百分比。
禁用组件滑动切换功能。默认值:false
设置导航点样式:
left: 设置导航点距离Swiper组件左边的距离。
top: 设置导航点距离Swiper组件顶部的距离。
right: 设置导航点距离Swiper组件右边的距离。
bottom: 设置导航点距离Swiper组件底部的距离。
size: 设置导航点的直径。不支持设置百分比。默认值:6vp。
mask: 设置是否显示导航点蒙层样式。
color: 设置导航点的颜色。
selectedColor: 设置选中的导航点的颜色。
onChange
onChange(event: (index: number) => void)
index:number
, 代表当前显示元素的索引。实现效果:在List组件、Grid组件上面增加Swiper轮播组件,整体滑动:
StudentListPage.ets
中修改:@Builder SwiperBuilder(studentList: Array<DataItemBean>) { Swiper(this.swiperController) { ForEach(studentList, (item: DataItemBean) => { Image(item.image) .borderRadius($r('app.float.home_swiper_borderRadius')) .width('100%') .height('240vp') .objectFit(ImageFit.Fill) .onClick(() => { router.pushUrl({ // url: 'pages/StudentDetailPage', url: CommonConstants.STUDENT_DETAIL_URL, params: { studentData: item } }).catch((error) => { console.log('Next Click', 'IndexPage push error' + JSON.stringify(error)); }) }) }, (item: DataItemBean) => JSON.stringify(item)) } .autoPlay(true) .indicatorStyle({ mask: true, bottom: '10vp' }) .margin({ top: $r('app.float.home_swiper_margin'), bottom: $r('app.float.home_swiper_margin') }) }
嵌入 Scroll
列表中:
import DataModel from '../viewmodel/DataModel'; import StudentListItem from '../view/StudentListItem'; import router from '@ohos.router'; import prompt from '@system.prompt'; import { DataItemBean } from '../viewmodel/DataItemBean'; import CommonConstants from '../common/constants/CommonConstants'; const TAG = '[StudentListPage]'; @Entry @Component export struct StudentListPage { private studentList2: Array<DataItemBean> = []; ... // Swiper控制器 private swiperController: SwiperController = new SwiperController(); ... @Builder NavigationMenus() { Row() { Toggle({ type: ToggleType.Switch, isOn: true }) .selectedColor(Color.Red) .switchPointColor(Color.White) .onChange((isOn: boolean) => { // this.isListModel = !this.isListModel this.isListModel = isOn }) } } @Builder SwiperBuilder(studentList: Array<DataItemBean>) { Swiper(this.swiperController) { ForEach(studentList, (item: DataItemBean) => { Image(item.image) .borderRadius($r('app.float.home_swiper_borderRadius')) .width('100%') .height('240vp') .objectFit(ImageFit.Fill) .onClick(() => { router.pushUrl({ // url: 'pages/StudentDetailPage', url: CommonConstants.STUDENT_DETAIL_URL, params: { studentData: item } }).catch((error) => { console.log('Next Click', 'IndexPage push error' + JSON.stringify(error)); }) }) }, (item: DataItemBean) => JSON.stringify(item)) } .autoPlay(true) .indicatorStyle({ mask: true, bottom: '10vp' }) .margin({ top: $r('app.float.home_swiper_margin'), bottom: $r('app.float.home_swiper_margin') }) } build() { Navigation() { Row() { Scroll() { Column() { // Swiper组件 this.SwiperBuilder(this.studentList2) // 列表 // List组件子组件ListItem之间默认是没有分割线的,部分场景子组件ListItem间需要设置分割线, // 这时候可以使用List组件的divider属性。divider属性包含四个参数: // 1、strokeWidth: 分割线的线宽。 // 2、color: 分割线的颜色。 // 3、startMargin:分割线距离列表侧边起始端的距离。 // 4、endMargin: 分割线距离列表侧边结束端的距离 List({ space: 16 }) { ForEach(this.studentList2, (item: DataItemBean) => { ListItem() { StudentListItem({ studentData: item, isRowModel: true }) } }, (item: string) => JSON.stringify(item)) } // .width('90%') .divider({ strokeWidth: 1, color: Color.Gray, startMargin: 30, endMargin: 0 }) // .listDirection(Axis.Horizontal) Text('---没有更多了---').fontSize('22vp').margin('30vp') } } .scrollBar(BarState.Off) .edgeEffect(EdgeEffect.Spring) } .width('90%') } .title('学生名单') .size({ width: '100%', height: '100%' }) .titleMode(NavigationTitleMode.Mini) .hideBackButton(true) .menus(this.NavigationMenus()) .backgroundColor($r('app.color.page_background')) } }
嵌入 Scroll
列表中:
import DataModel from '../viewmodel/DataModel'; import StudentListItem from '../view/StudentListItem'; import router from '@ohos.router'; import prompt from '@system.prompt'; import { DataItemBean } from '../viewmodel/DataItemBean'; import CommonConstants from '../common/constants/CommonConstants'; const TAG = '[StudentListPage]'; @Entry @Component export struct StudentListPage { private studentList2: Array<DataItemBean> = []; ... // Swiper控制器 private swiperController: SwiperController = new SwiperController(); ... build() { Navigation() { Row() { Scroll() { Column() { // Swiper组件 this.SwiperBuilder(this.studentList2) Grid() { ForEach(this.studentList2, (item: DataItemBean) => { GridItem() { StudentListItem({ studentData: item, isRowModel: false }) } }, (item: string) => JSON.stringify(item)) } .columnsTemplate('1fr 1fr 1fr') .rowsTemplate('1fr 1fr 1fr 1fr 1fr') .columnsGap('10vp') .rowsGap('10vp') .height('640vp') // .layoutDirection(GridDirection.Row) Text('---没有更多了---').fontSize('22vp').margin('30vp') } } .scrollBar(BarState.Off) .edgeEffect(EdgeEffect.Spring) } .width('90%') // .margin({ left: 10, right: 10 }) } .title('学生名单') .size({ width: '100%', height: '100%' }) .titleMode(NavigationTitleMode.Mini) .hideBackButton(true) .menus(this.NavigationMenus()) .backgroundColor($r('app.color.page_background')) } }
StudentListPage.ets
完整代码:import DataModel from '../viewmodel/DataModel'; import StudentListItem from '../view/StudentListItem'; import router from '@ohos.router'; import prompt from '@system.prompt'; import { DataItemBean } from '../viewmodel/DataItemBean'; import CommonConstants from '../common/constants/CommonConstants'; // import DataItemBean from '../viewmodel/DataItemBean'; const TAG = '[StudentListPage]'; @Entry @Component export struct StudentListPage { // private studentList: Array<string> = []; private studentList2: Array<DataItemBean> = []; // 返回上一层数据 @State backMessage: string = ''; // 是否是List组件模式 @State isListModel: boolean = true; // Swiper控制器 private swiperController: SwiperController = new SwiperController(); // 调用router.back()方法,不会新建页面,返回的是原来的页面,在原来页面中@State声明的变量不会重复声明, // 以及也不会触发页面的aboutToAppear()生命周期回调,因此无法直接在变量声明以及页面的aboutToAppear() // 生命周期回调中接收和解析router.back()传递过来的自定义参数。 onPageShow() { this.backMessage = router.getParams()?.['backMessage']; console.log(TAG, 'StudentDetailPage返回数据:StudentListPage => ' + this.backMessage) if (this.backMessage != undefined && this.backMessage != "") { this.showToast(this.backMessage) } } aboutToAppear() { // this.studentList = DataModel.getStudentList(); this.studentList2 = DataModel.getStudentList2(); // this.backMessage = router.getParams()?.['backMessage']; } showToast(message: string) { prompt.showToast({ message: message }) } @Builder NavigationMenus() { Row() { Toggle({ type: ToggleType.Switch, isOn: true }) .selectedColor(Color.Red) .switchPointColor(Color.White) .onChange((isOn: boolean) => { // this.isListModel = !this.isListModel this.isListModel = isOn }) } } @Builder SwiperBuilder(studentList: Array<DataItemBean>) { Swiper(this.swiperController) { ForEach(studentList, (item: DataItemBean) => { Image(item.image) .borderRadius($r('app.float.home_swiper_borderRadius')) .width('100%') .height('240vp') .objectFit(ImageFit.Fill) .onClick(() => { router.pushUrl({ // url: 'pages/StudentDetailPage', url: CommonConstants.STUDENT_DETAIL_URL, params: { studentData: item } }).catch((error) => { console.log('Next Click', 'IndexPage push error' + JSON.stringify(error)); }) }) }, (item: DataItemBean) => JSON.stringify(item)) } .autoPlay(true) .indicatorStyle({ mask: true, bottom: '10vp' }) .margin({ top: $r('app.float.home_swiper_margin'), bottom: $r('app.float.home_swiper_margin') }) } build() { Navigation() { Row() { if (this.isListModel) { Scroll() { Column() { // Swiper组件 this.SwiperBuilder(this.studentList2) // 列表 // List组件子组件ListItem之间默认是没有分割线的,部分场景子组件ListItem间需要设置分割线, // 这时候可以使用List组件的divider属性。divider属性包含四个参数: // 1、strokeWidth: 分割线的线宽。 // 2、color: 分割线的颜色。 // 3、startMargin:分割线距离列表侧边起始端的距离。 // 4、endMargin: 分割线距离列表侧边结束端的距离 List({ space: 16 }) { ForEach(this.studentList2, (item: DataItemBean) => { ListItem() { StudentListItem({ studentData: item, isRowModel: true }) } }, (item: string) => JSON.stringify(item)) } // .width('90%') .divider({ strokeWidth: 1, color: Color.Gray, startMargin: 30, endMargin: 0 }) // .listDirection(Axis.Horizontal) Text('---没有更多了---').fontSize('22vp').margin('30vp') } } .scrollBar(BarState.Off) .edgeEffect(EdgeEffect.Spring) } else { Scroll() { Column() { // Swiper组件 this.SwiperBuilder(this.studentList2) Grid() { ForEach(this.studentList2, (item: DataItemBean) => { GridItem() { StudentListItem({ studentData: item, isRowModel: false }) } }, (item: string) => JSON.stringify(item)) } .columnsTemplate('1fr 1fr 1fr') .rowsTemplate('1fr 1fr 1fr 1fr 1fr') .columnsGap('10vp') .rowsGap('10vp') .height('640vp') // .layoutDirection(GridDirection.Row) Text('---没有更多了---').fontSize('22vp').margin('30vp') } } .scrollBar(BarState.Off) .edgeEffect(EdgeEffect.Spring) } } .width('90%') // .margin({ left: 10, right: 10 }) } .title('学生名单') .size({ width: '100%', height: '100%' }) .titleMode(NavigationTitleMode.Mini) .hideBackButton(true) .menus(this.NavigationMenus()) .backgroundColor($r('app.color.page_background')) } }
本节梳理了HarmonyOS中使用ArkTs语言开发实现基本组件、容器组件、List组件、Grid组件、轮播组件Swiper以及页签切换组件Tabs等基本组件的使用,实现了 一个可以左右滑动切换视图的 带有顶部轮播Banner的
Star List
,并且通过Toggle({ type: ToggleType.Switch, isOn: true })
组件切换List
视图与Grid
列表视图功能。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。