轮播图、样式组件以及、网格布局的概念以及应用场景使用方法
1.轮播图(Swiper)
1.1概念
Swiper组件是一个容器组件,当制作一个比如说音乐播放器首页的顶部轮播时,使用轮播图组件是最佳时刻,
1.2用法
以Swiper为容器,内容作为Swiper的子组件就可以,设置Swiper的尺寸会保持和Swiper的组件拉伸到保持一致,设置内容的尺寸会将Swper的组件进行兼容
Swiper() {
// 显示轮播的内容
// (设置尺寸,进行兼容swiper)
}
// 设置尺寸(内容拉伸、优先级高)
.width('100%')
.height(100)
1.3常用属性
loop:boolean:是否开启循环,默认值为true
autoPlay:boolean:是否自动播放,默认值为flase
interval:number:使用自动播放的时间间隔,单位为毫秒,默认值为3000
vertical:boolean:是否为纵向滑动,默认值为false
Swiper() {
Text('0')
.textAlign(TextAlign.Center)
.backgroundColor(Color.Red)
.fontColor(Color.White)
.fontSize(50)
Text('1')
.textAlign(TextAlign.Center)
.backgroundColor(Color.Green)
.fontColor(Color.White)
.fontSize(50)
Text('2')
.textAlign(TextAlign.Center)
.backgroundColor(Color.Blue)
.fontColor(Color.White)
.fontSize(50)
}
.width('100%')
.height(200)
.autoPlay(true)
.interval(1000)
.vertical(true)
根据上述代码实现的内容有纵向滑动、自动播放、播放间隔
1.4设置导航点
默认的导航点一般情况下都不满足当下的开发环境,导航点一共有两种显示方式,一种是原点,另一种是数字,确定好排版,调整位置以及外观
indicator:Dotlndicator|Digitlndicator|boolean
Dotlndicator:园点指示器的样式
Digitlndicator:数字指示样式
boolean:启用导航指示器,默认值为true
1.5设置导航点位置、大小等
left、top、righ、bottom,设置导航点Swper组件左、上、右、下的距离,默认值为0
item '+' Width/Height:length:设置Swiper组件的圆点指示器的宽度/高度,默认值为6,单位为vp
selectedItem '+' Width/Height:设置Swiper选中组件的圆点指示器的宽度/高度,默认值为6,单位为vp
color/selectColor:设置Swiper组件/Swiper选中组件圆点指示器的颜色,默认值'#182431'(10%透明度)/'#007D'
.width('100%')
.height(160)
.indicator(
Indicator.dot() // 圆点
.selectedColor(Color.White) // 选中颜色
.selectedItemWidth(30) // 选中宽度
.selectedItemHeight(4) // 选中高度
.itemWidth(10) // 默认宽度
.itemHeight(4) // 默认宽度
)
1.6页面切换方式
页面切换需要配合点击事件,对象进行操作如:向左滑动1,向右滑动1,经常性制作一个button
shouw '+' Next/Previous() : void : 翻至下一页/上一页翻页带动效切换过程,翻页时长可以通过Swiper组件duration和curve指定。
@Entry
@Component
struct SwiperDemo {
// 1.创建控制器对象
controller: SwiperController = new SwiperController()
build() {
Column({ space: 10 }) {
// 2. 设置给 Swiper
Swiper(this.controller) {
}
Row() {
Button('上一页')
.onClick(() => {
// 3.调用控制器的方式实现切换效果
this.controller.showPrevious()
})
Button('下一页')
.onClick(() => {
this.controller.showNext()
})
}
}
.width('100%')
.height('100%')
// .padding(20)
}
}
2.样式组件(@Extend,@Styles,@Build)
制作一个页面时,有很多组件基本格式一样,为了美观性,减少重复的代码量,把应该重复使用的代码进行封装,传递参数,就可以提高编码效率和美观性。
2.1.@Extend
可以扩展组件的样式、事件实现重复使用的效果,比如:
Swiper() {
Text('0')
.textAlign(TextAlign.Center)
.backgroundColor(Color.Red)
.fontColor(Color.White)
.fontSize(30)
.onClick(() => {
AlertDialog.show({
message: '轮播图 1'
})
})
Text('1')
.textAlign(TextAlign.Center)
.backgroundColor(Color.Green)
.fontColor(Color.White)
.fontSize(30)
.onClick(() => {
AlertDialog.show({
message: '轮播图 2'
})
})
Text('2')
.textAlign(TextAlign.Center)
.backgroundColor(Color.Blue)
.fontColor(Color.White)
.fontSize(30)
.onClick(() => {
AlertDialog.show({
message: '轮播图 3'
})
})
}
这种情况就非常适合封装
语法:
//定义在全局
@Extend(组件名)
function functionName(){
.属性()
.事件(()=>{})
}
//使用
组件(){}
.functionName(参数...)
注意:
① 扩展的组件和使用的组件同名,比如 @Extend(Text) ,那么后续通过 Text 才可以点出该扩展
② function 的名字不能与组件本身拥有的属性同名,自身属性优先级更高
例如:Text组件上本身自带有一个fontStyle属性,我们就不能再@Extend(Text) function fontStyle()一个同名方法了
例子:
@Entry
@Component
struct Extends_demo {
@State message: string = '样式&结构重复使用'
build() {
Column({ space: 10 }) {
Text(this.message)
.fontSize(30)
Swiper() {
Text('0')
.textExtend(Color.Red, '轮播图 1')
Text('1')
.textExtend(Color.Green, '轮播图 2')
Text('2')
.textExtend(Color.Blue, '轮播图 3')
}
.width('100%')
.height(160)
}
.width('100%')
.height('100%')
}
}
@Extend(Text)
function textExtend(backgroudColor: ResourceColor, info: string) {
.textAlign(TextAlign.Center)
.backgroundColor(backgroudColor)
.fontColor(Color.White)
.fontSize(30)
.onClick(() => {
AlertDialog.show({
message: info
})
})
}
2.2.@Styles
不同于@Extend用来给某个组件进行扩展,@Styles可以抽取通用时间和属性@Styles扩展通用样式和事件给多个和组件使用
语法:
//全局定义
@Styles function functionName(){
.通用事件属性
.通用事件(()=>{})
}
@Component
sturc FancyUse{
//组件内定义
@Styles fancy(){
.通用属性
.通用事件(()=>{})
}
}
//使用
组件().fancy()
组件().functionName()
例子:
@Styles
function globalSize() {
.width(100)
.height(100)
}
@Entry
@Component
struct Day01_03_Styles {
@State message: string = '@styles';
@State bgColor: ResourceColor = Color.Gray
build() {
Column({ space: 10 }) {
Text(this.message)
.width(100)
.height(100)
.backgroundColor(this.bgColor)
.onClick(() => {
this.bgColor = Color.Orange
})
Column() {
}
.globalSize()
.sizeAndColorFancy()
Button('按钮')
.width(100)
.height(100)
.backgroundColor(this.bgColor)
.onClick(() => {
this.bgColor = Color.Orange
})
}
.width('100%')
.height('100%')
}
@Styles
sizeAndColorFancy() {
.backgroundColor(this.bgColor)
.onClick(() => {
this.bgColor = Color.Orange
})
}
}
2.3.@Builder
🌟🌟可以抽取结构,又叫叫自定义构建函数,(非常常用,前面俩个都可以不用,就用这个也可以)
语法:
// 自定义 全局 构建函数
@Builder function MyGlobalBuilderFunction(param1,param2...) {
// 结构、属性、事件放这里
}
// 使用
MyGlobalBuilderFunction(param1,param2...)
// 自定义 组件内 构建函数
@Builder MyBuilderFunction( param1,param2...) {
// 结构、属性、事件放这里
}
// 使用
this.MyBuilderFunction(param1,param2...)
//例如:
@Builder
function GlobalTextItem(title: string) {
Text(title)
.fontSize(30)
.onClick(() => {
// 逻辑略
})
}
@Builder
GlobalTextItem(title: string) {
Text(title)
.fontSize(30)
.onClick(() => {
// 逻辑略
})
}
例子:
// 全局 Builder
@Builder
function navItem(icon: ResourceStr, text: string) {
Column({ space: 10 }) {
Image(icon)
.width('80%');
Text(text);
}
.width('25%')
.onClick(() => {
AlertDialog.show({
message: '点了' + text
})
})
}
@Entry
@Component
struct Day01_04_Builder {
@State message: string = '@Builder';
build() {
Column({ space: 20 }) {
Text(this.message)
.fontSize(30)
Row() {
// 这两个使用全局的
navItem($r('app.media.ic_reuse_01'), '阿里拍卖')
navItem($r('app.media.ic_reuse_02'), '菜鸟')
// 这两个使用本地的
this.navItem($r('app.media.ic_reuse_03'), '芭芭农场')
this.navItem($r('app.media.ic_reuse_04'), '阿里药房')
}
}
.width('100%')
.height('100%')
}
// 本地 Builder
@Builder
navItem(icon: ResourceStr, text: string) {
Column({ space: 10 }) {
Image(icon)
.width('80%');
Text(text);
}
.width('25%')
.onClick(() => {
AlertDialog.show({
message: '点了' + text
})
})
}
}
2.4.## 2.4. @Extend、@Styles、@Builder 对比
@Etend:适合抽取特定组件样式、事件:可以传递参数
@Styles:适合抽取公共组件样式、事件:不可以传递参数
@Builder:适合抽取结构、样式、事件:可以传递参数
3.Grid网格布局
页面是由一网格布局组成的,特定情况下需要行列合并,就可以使用Grid/Griditem实现
3.1.固定行列
结构
//整体结构和List相同
Grid() {
GridItem(){
// 展示的内容放在这里
}
GridItem(){
// 展示的内容放在这里
}
}
常用属性
colums/rows '+' Template : string : 设置当前网格布局列/行的数量不设置默认是1,例如:'1fr 1fr 1fr' 是将父组件分3列,将父组件允许的宽分为4等份,第一列占1份,第二列占1份,第三列占2份。
colunns/rows '+' Gap : length : 设置列与列/行与行的间距。
列子:
@Entry
@Component
struct Index {
@Builder gridItemBuilder(text:string){
GridItem(){
Text(text)
}
.backgroundColor('#0094ff')
}
build() {
Column(){
Grid(){
this.gridItemBuilder('1')
this.gridItemBuilder('2')
this.gridItemBuilder('3')
this.gridItemBuilder('4')
this.gridItemBuilder('5')
this.gridItemBuilder('6')
this.gridItemBuilder('7')
this.gridItemBuilder('8')
this.gridItemBuilder('9')
}
.width('100%')
.height(300)
.backgroundColor(Color.Gray)
// 1. columnsTemplate+rowsTemplate可以固定几行几列来显示
.columnsTemplate('1fr 1fr 1fr')
.rowsTemplate('1fr 1fr 1fr')
.columnsGap(5)
.rowsGap(5)
}
.width('100%')
.height('100%')
}
}
🌟🌟3.2.淘宝二楼案例
interface TaoBaoItemContent {
title: string
icon: string
}
@Entry
@Component
struct TaobaoPage {
contentList: TaoBaoItemContent[] = [
{ title: '淘金币', icon: 'app.media.ic_taobao_01' },
{ title: '一起摇现金', icon: 'app.media.ic_taobao_02' },
{ title: '闲鱼', icon: 'app.media.ic_taobao_03' },
{ title: '中通快递', icon: 'app.media.ic_taobao_04' },
{ title: '芭芭农场', icon: 'app.media.ic_taobao_05' },
{ title: '淘宝珍库', icon: 'app.media.ic_taobao_06' },
{ title: '阿里拍卖', icon: 'app.media.ic_taobao_07' },
{ title: '阿里药房', icon: 'app.media.ic_taobao_08' },
{ title: '小黑盒', icon: 'app.media.ic_taobao_09' },
{ title: '菜鸟', icon: 'app.media.ic_taobao_10' },
{ title: 'U先试用', icon: 'app.media.ic_taobao_11' },
{ title: '有好价', icon: 'app.media.ic_taobao_12' },
{ title: '极有家', icon: 'app.media.ic_taobao_13' },
{ title: '天猫榜单', icon: 'app.media.ic_taobao_14' },
{ title: '天天特卖', icon: 'app.media.ic_taobao_15' },
{ title: '每日好店', icon: 'app.media.ic_taobao_16' },
{ title: '全球购', icon: 'app.media.ic_taobao_17' },
{ title: '我的爱车', icon: 'app.media.ic_taobao_18' },
{ title: '造点新货', icon: 'app.media.ic_taobao_19' },
{ title: '首单优惠', icon: 'app.media.ic_taobao_20' },
{ title: '潮Woo', icon: 'app.media.ic_taobao_21' },
{ title: '亲宝贝', icon: 'app.media.ic_taobao_22' },
{ title: '领券中心', icon: 'app.media.ic_taobao_23' },
{ title: '天猫奢品', icon: 'app.media.ic_taobao_24' },
{ title: 'iFashion', icon: 'app.media.ic_taobao_25' }
]
build() {
Column() {
Column() {
// 返回区域
this.BackBuilder()
// 搜索区域
this.SearchBuilder()
// 网格区域
this.GridBuilder()
}
}
.width('100%')
.height('100%')
.linearGradient({
colors: [
['#271b41', 0],
['#481736', 1],
]
})
}
@Builder
BackBuilder() {
Row() {
Image($r('app.media.ic_taobao_back'))
.fillColor(Color.White)
.width(30)
Text('最近使用')
.fontSize(20)
.fontColor(Color.White)
}
.width('100%')
.padding({ top: 40 })
}
@Builder
SearchBuilder() {
Stack() {
Text()
.width('100%')
.height(40)
.backgroundColor(Color.White)
.opacity(.3)
.borderRadius(20)
Row({ space: 10 }) {
Image($r('app.media.ic_taobao_search'))
.width(25)
.fillColor(Color.White)
Text('搜索')
.fontSize(15)
.fontColor(Color.White)
}
.padding({ left: 10 })
.width('100%')
}
.padding(10)
}
@Builder
GridBuilder() {
Grid() {
ForEach(this.contentList, (item: TaoBaoItemContent, index: number) => {
this.GridItemBuilder(item)
})
}
.rowsTemplate('1fr 1fr 1fr 1fr 1fr') // 如果不写高度超出后会出现滚动
.columnsTemplate('1fr 1fr 1fr 1fr 1fr')
.width('100%')
.height(360)
}
@Builder
GridItemBuilder(item: TaoBaoItemContent) {
GridItem() {
Column({ space: 10 }) {
Image($r(item.icon))
.width(40)
.borderRadius(20)
Text(item.title)
.fontColor(Color.White)
.fontSize(14)
}
}
}
}
3.3.合并行列
日常开发中很常见这种布局,由不同大小不均匀分的情况有很多,比如一些购物平台
row '+' Start/End : nember : 指定当前元素起始/终点行号。
column '+' Start/End : number : 指定当前元素起始/终点列号。
列子
@Entry
@Component
struct GridPage03 {
nums: number[] = Array.from({ length: 12 })
build() {
Grid() {
ForEach(this.nums, (item: number, index: number) => {
if (index === 2) {
GridItem() {
Text(index + '')
.fontColor(Color.White)
.fontSize(30)
}
.backgroundColor('#9dc3e6')
.columnStart(3)
.columnEnd(4)
} else if (index === 3) {
GridItem() {
Text(index + '')
.fontColor(Color.White)
.fontSize(30)
}
.backgroundColor('#9dc3e6')
.rowStart(2)
.rowEnd(3)
} else {
GridItem() {
Text(index + '')
.fontColor(Color.White)
.fontSize(30)
}
.backgroundColor('#9dc3e6')
}
})
}
.columnsTemplate('1fr 1fr 1fr 1fr')
.rowsTemplate('1fr 1fr 1fr')
.width('100%')
.height(260)
.rowsGap(10)
.columnsGap(10)
.padding(10)
}
}
3.4.设置滚动
日常开发中,可以滚动的网格布局也经常出现,比如文件管理、购物、视频列表
设置方式:
水平/垂直 滚动:设置的是rows/colums '+' Template,Grid的滚动方向为水平/垂直方向。
例子:
@Entry
@Component
struct Day01_09_Grid05 {
// 长度为 10 每一项都为 undefined 的数组
list: string[] = Array.from({ length: 30 })
build() {
Column() {
Grid() {
ForEach(this.list, (item: string, index) => {
GridItem() {
Text((index + 1).toString())
.newExtend()
}
.padding(5)
.height('30%')
.width('25%')
})
}
.columnsTemplate('1fr 1fr 1fr') // 竖向滚动
// .rowsTemplate('1fr 1fr 1fr') // 横向滚动
.rowsGap(10)
.width('100%')
.height(300)
.border({ width: 1 })
.padding(5)
}
.width('100%')
.height('100%')
}
}
@Extend(Text)
function newExtend() {
.backgroundColor('#0094ff')
.width('100%')
.height('100%')
.fontSize(30)
.fontColor(Color.White)
.textAlign(TextAlign.Center)
}
3.5.代码控制滚动
- 创建 Scroller 对象
- 设置给 Grid
- 调用 Scroller 对象的 scrollPage 方法
/*// 创建 Scroller 对象
scroller: Scroller = new Scroller()
// 设置给 Grid
Grid(this.scroller) {
// ...
}
// 通过代码控制
this.scroller.scrollPage({
next:true // 下一页
next:false // 上一页
})*/
@Entry
@Component
struct GridDemo {
nums: number[] = Array.from({ length: 200 })
scroller: Scroller = new Scroller()
build() {
Column() {
Grid(this.scroller) {
ForEach(this.nums, (item: number, index: number) => {
GridItem() {
Text(index + 1 + '')
}
.backgroundColor('#0094ff')
.width('25%')
})
}
.padding(10)
.height(450)
.rowsGap(10)
.columnsGap(10)
.rowsTemplate('1fr 1fr 1fr 1fr')
Row() {
Button('上一页')
.width(100)
.onClick(() => {
this.scroller.scrollPage({
next: false
})
})
Button('下一页')
.width(100)
.onClick(() => {
this.scroller.scrollPage({
next: true
})
})
}
.width('100%')
.justifyContent(FlexAlign.SpaceAround)
}
}
}
3.6.自定义滚动条
如果默认的滚动条外观无法满足要求,我们还可以进行自定义
- 使用提供的属性调整(可调整属性有限)
- 使用 ScrollBar 组件自定义(可定制性高)
scrollBar:BarState : 设置滚动条状态。
默认值:BarState.auto
BarState.off 关闭
BarState.on 常驻
BarState.auto 按需显示
scrollBarColor : string | number | Color :设置滚动条的颜色。 scrollBarWidth :string | number : 设置滚动条的宽度。宽度设置后,滚动条正常状态和按压状态宽度均为滚动条的宽度值。
默认值:4
单位:vp
.columnsTemplate('1fr 1fr 1fr') // 竖向滚动
.rowsGap(10)
.width('100%')
.height(300)
.border({ width: 1 })
.padding(5)
.scrollBarWidth(20) // 宽度
.scrollBarColor(Color.Orange) // 滚颜色
.scrollBar(BarState.Off) // 关闭
使用 ScrollBar 组件自定义 如果上一节实现的效果无法满足需求,那么可以使用 ScrollBar 组件进行自定义
scroller : Scroller : 是 :可滚动组件的控制器。用于与可滚动组件进行绑定。
direction :ScrollBarDirection : 否 : 滚动条的方向,控制可滚动组件对应方向的滚动。
默认值:ScrollBarDirection.Vertical
state : BarState : 否 :滚动条状态。
默认值:BarState.Auto
@Entry
@Component
struct Day01_11_Grid07 {
// 长度为 30 每一项都为 undefined 的数组
list: string[] = Array.from({ length: 30 })
scroller: Scroller = new Scroller()
build() {
Column() {
Grid(this.scroller) {
ForEach(this.list, (item: string, index) => {
GridItem() {
this.ItemBuilder(index)
}
.padding(5)
.height('30%')
.width('25%')
})
}
.rowsTemplate('1fr 1fr 1fr') // 竖向滚动
.rowsGap(10)
.width('100%')
.height(300)
.border({ width: 1 })
.padding(5)
.scrollBar(BarState.Off) // 关闭
// 自定义滚动条
ScrollBar({
scroller: this.scroller,
direction: ScrollBarDirection.Horizontal
}) {
Text()
.width(40)
.height(20)
.backgroundColor(Color.Orange)
}
.width(200)
.height(20)
.backgroundColor(Color.Red)
}
.width('100%')
.height('100%')
}
@Builder
ItemBuilder(index: number) {
Text((index + 1).toString())
.backgroundColor('#0094ff')
.width('100%')
.height('100%')
.fontSize(30)
.fontColor(Color.White)
.textAlign(TextAlign.Center)
}
}
4.总结
- Swiper 轮播图
-
- 自动轮播,无限循环
- 自定义导航点
- Grid:网格
-
- 均分行列,跨行,跨列
- 自定义滚动条
-
-
- 创建对象scroller
- scroller 关联给 Grid、ScrollBar
- 通过 ScrollBar 自定义滚动条外观
-
- 提取公共样式 结构
-
- @Extend,给特定元素扩展(可以传参,只能定义到全局)
- @Styles: 通用属性、事件(不能传参,本地,全局都可以定义)
- @Builder: 结构、样式、事件(可以传参,本地,全局都可以定义))