HarmonyOS NEXT零基础入门到实战-第二部分
Swiper 轮播组件
Swiper是一个 容器 组件,当设置了多个子组件后,可以对这些 子组件 进行轮播显示。(文字、图片...)
1、Swiper基本语法
2、Swiper常见属性
3、Swiper样式自定义
4、案例:小米有品
5、作业:手机淘宝
Swiper相关源代码:
@Entry
@Component
struct Index {
build() {
Column() {
// Swiper 包内容,设尺寸
Swiper() {
Text('1')
.backgroundColor(Color.Orange)
Text('2')
.backgroundColor(Color.Yellow)
Text('3')
.backgroundColor(Color.Brown)
}
.width('100%')
// .height(300)
.aspectRatio(2.4) // 设置和图片一致的宽高比,保证图片正常适配
// 常见属性
.loop(true) // 开启循环
.autoPlay(true) // 自动播放,默认3s
.interval(5000) // 自动轮播间隔
.vertical(false) // 横向/纵向
// 定制小圆点
// .indicator(false)
.indicator(
Indicator.dot() // 小圆点
.itemWidth(10) // 默认的宽
.itemHeight(5) // 默认的高
// .color(Color.Gray) // 默认的颜色
.selectedItemWidth(30) // 选中的宽
.selectedItemHeight(5) // 选中的高
.selectedColor(Color.White) // 选中的颜色
)
Swiper() {
Image($r('app.media.hw'))
.objectFit(ImageFit.Cover)
Image($r('app.media.pg'))
.objectFit(ImageFit.Cover)
Image($r('app.media.xm'))
.objectFit(ImageFit.Cover)
}
.width('100%')
.height(300)
.loop(true) // 开启循环
.autoPlay(true) // 自动播放,默认3s
.interval(5000) // 自动轮播间隔
}
}
}
样式&结构重用
@Extend:扩展组件(样式、事件)
比如:
@Extend(Text)
function bannerItem(bgColor: ResourceColor, msg: string) {
.fontSize(30)
.fontColor(Color.White)
.backgroundColor(bgColor)
.textAlign(TextAlign.Center)
.onClick(() => {
AlertDialog.show({
message: msg
})
})
}
Swiper() {
Text('1')
.bannerItem(Color.Orange, '轮播图 1')
Text('2')
.bannerItem(Color.Brown, '轮播图 2')
Text('3')
.bannerItem(Color.Green, '轮播图 3')
}
@Styles:抽取通用属性、事件
针对所有组件的公有属性,比如说宽高、背景色、点击事件等,@Styles不支持传参
1、全局定义(不支持this.调用)
@Styles function commonStyles() {
.width(100)
.height(100)
.onClick(() => { ... })
}
2、在组件内定义(省略function) 才能通过this访问到自己的状态 这种使用相对全局使用较多
@Styles setBg() {
.backgroundColor(Color.Red)
}
@Builder:自定义构建函数(结构、样式、事件)
// 全局 Builder
@Builder
function navItem(icon: ResourceStr, txt: string) {
Column({space: 10}) {
Image(icon)
.width('80%')
Text(txt)
}
.width('25%')
.onClick(() => {
AlertDialog.show({
message: '点了' + txt
})
})
}
@Entry
@Component
struct Index {
@State builderStr: string = '@Builder'
// 局部builder 只能定义在组件内 this.xxx
@Builder
navItem(icon: ResourceStr, txt: string) {
Column({space: 10}) {
Image(icon)
.width('80%')
Text(txt)
}
.width('25%')
.onClick(() => {
AlertDialog.show({
message: '点了' + txt + this.builderStr
})
})
}
build() {
Column() {
Row() {
navItem($r('app.media.xm'), '小米手机')
navItem($r('app.media.hw'), '华为手机')
this.navItem($r('app.media.pg'), '苹果手机')
}
}
}
}
总结
@Extend 抽取 特定组件 样式、事件 可以传递参数
@Styles 抽取 公共样式、事件 不可以传递参数
@Builder 抽取结构、样式、事件 可以传递参数
滚动容器Scroll
当子组件的布局尺寸超过Scroll的尺寸时,内容可以滚动
学习目录:
1、Scroll 的核心用法
2、Scroll 的常见属性
3、Scroll 的控制器
4、Scroll 的事件
5、案例:京东案例实战
源代码:
@Entry
@Component
struct Index {
build() {
Column() {
// 如果希望内容溢出,能够滚动
Scroll() {
Column({space: 10}) {
ForEach(Array.from({length: 10}), (item: string, index: number) => {
Text('测试文本' + (index + 1))
.width('100%')
.height(100)
.textAlign(TextAlign.Center)
.backgroundColor(Color.Orange)
.fontSize(20)
.fontColor(Color.White)
.borderRadius(20)
})
}
.padding(10)
.width('100%')
}
// .scrollable(ScrollDirection.Horizontal)
// .scrollBar(BarState.Auto)
// .scrollBarColor(Color.Blue)
// .scrollBarWidth(5)
.edgeEffect(EdgeEffect.Spring) // 滑动效果:弹簧
}
.width('100%')
.height(200)
}
}
Scroll的控制器:
核心步骤:
1、实例化 Scroller 的控制器
2、绑定给 Scroll 组件
3、控制器的方法 控制滚动, 控制器属性 获取滚动距离
Scroll 事件:
Scroll 组件提供了一些事件,让开发者可以在适当的时候添加逻辑
Scroll(){
}
.onScroll((x, y) => {
// 滚动时一直触发 可以结合 scroller的currentOffset方法 获取滚动距离
})
.onWillScroll((offset: number) => {
console.log('onWillScroll 已经滑动的距离', this.myScroller.currentOffset().yOffset + offset)
})
.onScroll((x, y) => {
console.log('onScroll 已经滑动的距离', this.myScroller.currentOffset().yOffset)
})
滚动容器Scroll - 京东案例实战
需求说明:
1、点击火箭回到顶部
2、火箭显示效果切换
2.1 默认隐藏
2.2 超过400 ---->显示,反之--->隐藏
@State yOffset : number = 0;
.onScroll((x, y) => {
yOffset = this.myScroller.currentOffset().yOffset
})
if(yOffset > 400) {
// 渲染
}
源代码:
@Entry
@Component
struct Index {
// 1、创建 Scroller 对象(实例化)
myScroller: Scroller = new Scroller()
build() {
Column() {
// 如果希望内容溢出,能够滚动
// 2、绑定给 Scroll 组件
Scroll(this.myScroller) {
Column({space: 10}) {
ForEach(Array.from({length: 10}), (item: string, index: number) => {
Text('测试文本' + (index + 1))
.width('100%')
.height(100)
.textAlign(TextAlign.Center)
.backgroundColor(Color.Orange)
.fontSize(20)
.fontColor(Color.White)
.borderRadius(20)
})
}
.padding(10)
.width('100%')
}
.width('100%')
.height(400)
// .scrollable(ScrollDirection.Horizontal)
// .scrollBar(BarState.Auto)
// .scrollBarColor(Color.Blue)
// .scrollBarWidth(5)
.edgeEffect(EdgeEffect.Spring) // 滑动效果:弹簧
.onWillScroll((offset: number) => {
console.log('onWillScroll 已经滑动的距离', this.myScroller.currentOffset().yOffset + offset)
})
.onScroll((x, y) => {
console.log('onScroll 已经滑动的距离', this.myScroller.currentOffset().yOffset)
})
Button('控制滚动条位置').margin(20)
.onClick(() => {
this.myScroller.scrollEdge(Edge.Top) // 会滚动顶部
})
Button('获取已经滚动的距离')
.onClick(() => {
const y = this.myScroller.currentOffset().yOffset
AlertDialog.show({
message: `y:${y}`
})
})
}
}
}
====
容器组件 Tabs
当页面内容较多时,可以通过Tabs组件进行 分类展示
学习目录:
1、Tabs 基本用法
2、Tabs 常见属性
3、滚动导航栏
4、自定义TabBar
5、案例: 小米有品底部Tabs
源代码:
@Entry
@Component
struct Index {
titles: string[] = [
'首页', '关注', '热门', '军事','体育',
'八卦', '数码', '财经', '美食','旅行'
]
build() {
Column() {
// 调整位置 顶部或者底部(参数)
Tabs({barPosition: BarPosition.Start}) {
ForEach(this.titles, (item: string, index) => {
TabContent() {
Text(`${item}内容`)
}
.tabBar(item)
})
}
.vertical(false) // 调整导航水平或者垂直
.scrollable(true) // 是否开启手势滑动
.animationDuration(0) // 点击滑动动画时间
.barMode(BarMode.Scrollable) // 滚动导航栏
}
}
}
自定义的TabBar
1、基础结构 2、高亮切换
源代码:
@Entry
@Component
struct Index {
// 准备状态,存储激活的索引
@State selectedIndex: number = 0;
build() {
// 调整位置 顶部或者底部(参数)
Tabs({barPosition: BarPosition.End}) {
TabContent() {
Text('购物车')
}
.tabBar(this.myBuilder(0, '购物车', $r('app.media.startIcon'), $r('app.media.xm')))
TabContent() {
Text('我的')
}
.tabBar(this.myBuilder(1, '我的', $r('app.media.startIcon'), $r('app.media.hw')))
}
// .vertical(false) // 调整导航水平或者垂直
// .scrollable(true) // 是否开启手势滑动
// .animationDuration(0) // 点击滑动动画时间
// .barMode(BarMode.Scrollable) // 滚动导航栏
.onChange((index: number) => {
this.selectedIndex = index
})
}
@Builder
myBuilder(itemIndex: number,title: string, img: ResourceStr, selectedImg: ResourceStr) {
Column() {
Image(itemIndex == this.selectedIndex ? selectedImg : img)
.width(30)
Text(title)
.fontColor(itemIndex == this.selectedIndex ? Color.Red : Color.Black)
}
}
}
案例 小米有品底部Tabs:
实现思路:
1、基础结构 2、高亮控制 3、中间特殊结构
源代码:
@Entry
@Component
struct Index {
// 准备状态,存储激活的索引
@State selectedIndex: number = 0;
build() {
// 调整位置 顶部或者底部(参数)
Tabs({barPosition: BarPosition.End}) {
TabContent() {
Text('购物车')
}
.tabBar(this.myBuilder(0, '购物车', $r('app.media.startIcon'), $r('app.media.xm')))
// 特殊形状的Tab
TabContent(){
Text('活动内容')
}
.tabBar(this.centerBuilder())
TabContent() {
Text('我的')
}
.tabBar(this.myBuilder(2, '我的', $r('app.media.startIcon'), $r('app.media.hw')))
}
// .vertical(false) // 调整导航水平或者垂直
// .scrollable(true) // 是否开启手势滑动
// .animationDuration(0) // 点击滑动动画时间
// .barMode(BarMode.Scrollable) // 滚动导航栏
.onChange((index: number) => {
this.selectedIndex = index
})
}
@Builder
myBuilder(itemIndex: number,title: string, img: ResourceStr, selectedImg: ResourceStr) {
Column() {
Image(itemIndex == this.selectedIndex ? selectedImg : img)
.width(30)
Text(title)
.fontColor(itemIndex == this.selectedIndex ? Color.Red : Color.Black)
}
}
@Builder
centerBuilder() {
Image($r('app.media.pg'))
.width(30)
.height(30)
.margin({bottom: 20})
}
}