1 前言
这次接着开发天气APP,上次已经实现了从和风天气获取实时、24h以及7天的天气数据了,但只是将实时数据显示出来。这次要完成24h和7天的数据显示,用到List和Scroll容器。
2 List组件
2.1 介绍
列表是一种复杂的容器,当列表项达到一定数量,内容超过屏幕大小时,可以自动提供滚动功能。它适合用于呈现同类数据类型或数据类型集,例如图片和文本。在列表中显示数据集合是许多应用程序中的常见要求(如通讯录、音乐列表、购物清单等)。
使用列表可以轻松高效地显示结构化、可滚动的信息。通过在List组件中按垂直或者水平方向线性排列子组件ListItemGroup或ListItem,为列表中的行或列提供单个视图,或使用循环渲染迭代一组行或列,或混合任意数量的单个视图和ForEach结构,构建一个列表。List组件支持使用条件渲染、循环渲染、懒加载等渲染控制方式生成子组件。
2.2 布局
列表作为一种容器,会自动按其滚动方向排列子组件,向列表中添加组件或从列表中移除组件会重新排列子组件。
如下图所示,在垂直列表中,List按垂直方向自动排列ListItemGroup或ListItem。
ListItemGroup用于列表数据的分组展示,其子组件也是ListItem。ListItem表示单个列表项,可以包含单个子组件。

2.3 设置主轴方向
List组件主轴默认是垂直方向,即默认情况下不需要手动设置List方向,就可以构建一个垂直滚动列表。
若是水平滚动列表场景,将List的listDirection属性设置为Axis.Horizontal即可实现。listDirection默认为Axis.Vertical,即主轴默认是垂直方向。
List() {
}
.listDirection(Axis.Horizontal)
2.4 使用forEach迭代列表内容
通常,应用通过数据集合动态地创建列表。使用循环渲染可从数据源中迭代获取数据,并在每次迭代过程中创建相应的组件,降低代码复杂度。
ArkTS通过ForEach提供了组件的循环渲染能力。以简单形式的联系人列表为例,将联系人名称和头像数据以Contact类结构存储到contacts数组,使用ForEach中嵌套ListItem的形式来代替多个平铺的、内容相似的ListItem,从而减少重复代码。
示例
build() {
List() {
ForEach(this.contacts, (item: Contact) => {
ListItem() {
Row() {
Image(item.icon)
.width(40)
.height(40)
.margin(10)
Text(item.name).fontSize(20)
}
.width('100%')
.justifyContent(FlexAlign.Start)
}
}, (item: Contact) => JSON.stringify(item))
}
.width('100%')
}
3 Scroll容器
3.1 基本介绍
Scroll是可滚动的容器组件,当子组件的布局尺寸超过父组件的尺寸时,内容可以滚动。
- 从API version 7开始支持,后续版本新增内容会用上角标标记起始版本。
- 嵌套List子组件滚动时,若List不设置宽高则默认全部加载,对性能有要求的场景建议指定List的宽高。
- 滚动的前提是主轴方向大小小于内容大小。
- 通用属性clip的默认值为true。
- 支持单个子组件。
3.2 接口
| 接口 |
描述 |
|---|
| Scroll(scroller?: Scroller) |
创建Scroll滚动容器。scroller为可滚动组件的控制器,用于与可滚动组件绑定,不允许和其他滚动类组件绑定同一个滚动控制对象。从API version 11开始支持在原子化服务中使用。 |
3.3 属性
除支持通用属性和滚动组件通用属性外,还支持以下属性:
| 属性 |
类型 |
说明 |
原子化服务API支持版本 |
|---|
| scrollable |
(value: ScrollDirection) |
设置滚动方向,默认值为ScrollDirection.Vertical。 |
11+ |
| scrollBar |
(barState: BarState) |
设置滚动条状态,若容器组件无法滚动或子组件大小为无穷大,滚动条不显示或不支持拖动和伴随滚动。从API version 10开始,滚动组件有圆角时,滚动条会自动计算避让距离。 |
11+ |
| scrollBarColor |
(color: Color |
number |
string) |
| scrollBarWidth |
(value: number |
string) |
设置滚动条的宽度,不支持百分比设置。宽度设置后,正常和按压状态宽度均为此值,若超过Scroll组件主轴方向的高度则变为默认值。默认值为4vp,取值范围:小于0按默认值处理,0时不显示滚动条。 |
| scrollSnap^{10+} |
(value: ScrollSnapOptions) |
设置Scroll组件的限位滚动模式。 |
11+ |
| edgeEffect |
(edgeEffect: EdgeEffect, options?: EdgeEffectOptions) |
设置边缘滑动效果,支持弹簧效果和阴影效果,默认值为EdgeEffect.None。options(11+)用于设置组件内容大小小于自身时是否开启滑动效果,默认{ alwaysEnabled: true }。 |
11+ |
| enableScrollInteraction^{10+} |
(value: boolean) |
设置是否支持滚动手势,true时可通过手指或鼠标滚动,false时不行,但不影响控制器Scroller的滚动接口,默认值为true。 |
11+ |
| nestedScroll^{10+} |
(value: NestedScrollOptions) |
设置前后两个方向的嵌套滚动模式,实现与父组件的滚动联动,默认值为{ scrollForward: NestedScrollMode.SELF_ONLY, scrollBackward: NestedScrollMode.SELF_ONLY }。 |
11+ |
| friction^{10+} |
(value: number |
Resource) |
设置摩擦系数,手动划动滚动区域时生效,仅影响惯性滚动过程。默认值:非可穿戴设备11+为0.7,12+为0.75;可穿戴设备为0.9。取值范围:(0, +∞),小于等于0按默认值处理。 |
| enablePaging^{11+} |
(value: boolean) |
设置是否支持划动翻页,若同时设置划动翻页和限位滚动,限位滚动优先生效。默认值为false。 |
12+ |
| initialOffset^{12+} |
(value: OffsetOptions) |
设置初始滚动偏移量,只在首次布局时生效,后续动态修改不生效。输入为百分比时,偏移量为Scroll组件主轴方向大小与百分比数值之积。 |
12+ |
4 代码实现
4.1 Index.ets
新增了Scroll容器,然后将实时数据、24h、7天的数据都封装进单独的组件中,以保持主页代码的整洁。
build() {
Scroll() {
Column() {
nowWeatherDataComponent({
selectCity: $selectCity,
cityArr: $cityArr,
weatherNow: $weatherNow,
weatherUiModel: $weatherUiModel,
readDataSuccess: $readDataSuccess
})
.margin({ bottom: 10 })
weatherData24hComponent({
readDataSuccess:$readDataSuccess,
weatherUiModel:$weatherUiModel
})
.margin({ bottom: 10 })
weatherData7dComponent({
weatherUiModel:$weatherUiModel,
readDataSuccess:$readDataSuccess
})
.margin({ bottom: 10 })
}
}
.scrollable(ScrollDirection.Vertical)
.scrollBar(BarState.Off)
.edgeEffect(EdgeEffect.None)
.backgroundColor('#ffdee0e0')
}
4.2 weatherData24hComponent 组件
获取24h天气数据代码如下,其中使用到了forEach遍历来创建ListItem的方式,精简代码。
export struct weatherData24hComponent {
@Link readDataSuccess: boolean
@Link weatherUiModel :WeatherUiModel
build() {
if (this.readDataSuccess == true) {
List() {
ForEach(this.weatherUiModel.hoursArr, (hour: string, index: number) => {
ListItem() {
Column({ space: 15 }) {
Text(this.weatherUiModel.hourlyTemp[index] + '℃')
.textAlign(TextAlign.Center)
.fontSize(16)
.height(20)
Image($rawfile((this.weatherUiModel.hourlyIcon[index].toString() + '.svg')))
.height(16)
.width(16)
if(this.weatherUiModel.hourlyRain[index]>0){
Text(this.weatherUiModel.hourlyRain[index] + '%')
.textAlign(TextAlign.Center)
.fontSize(16)
.height(20)
.fontColor('#ff3176bc')
}
else{
Text(this.weatherUiModel.hourlyRain[index] + '%')
.textAlign(TextAlign.Center)
.fontSize(16)
.height(20)
.fontColor(Color.Gray)
}
Text(hour)
.textAlign(TextAlign.Center)
.fontSize(16)
.height(20)
}
.margin({ bottom: 5, top: 5 })
}
.width(80)
.height(150)
})
}
.listDirection(Axis.Horizontal)
.backgroundColor(Color.White)
.borderRadius(15)
.width('90%')
.height(150)
} else {
Row() {
Text('无数据')
.fontSize(20)
.fontColor(Color.Gray)
}
.justifyContent(FlexAlign.Center)
.backgroundColor(Color.White)
.borderRadius(15)
.width('90%')
.height(150)
}
}
}
4.3 weatherData7dComponent
获取7天天气的组件代码如下
@Component
export struct weatherData7dComponent {
@Link weatherUiModel: WeatherUiModel
@Link readDataSuccess: boolean
@State selectDay: string = '今天';
build() {
if (this.readDataSuccess == true){
Column() {
Row() {
ForEach(this.weatherUiModel.iconDays, (item:number) => {
Column() {
Image($rawfile((item.toString()+'.svg')))
.size({ width: 24, height: 24 })
}
.align(Alignment.Center)
.layoutWeight(1)
})
}
.margin({top:5})
Row() {
ForEach(this.weatherUiModel.tempDayMax, (item:number) => {
Column() {
Text(item.toString()+ '°')
.fontSize(14)
.fontColor('#ffec9e0d')
}
.align(Alignment.Center)
.layoutWeight(1)
})
}
Row() {
ForEach(this.weatherUiModel.tempDayMin, (item:number) => {
Column() {
Text(item.toString()+ '°')
.fontSize(14)
.fontColor('#ff2b8de2')
}
.align(Alignment.Center)
.layoutWeight(1)
})
}
Row() {
ForEach(this.weatherUiModel.dayArr, (item:string) => {
Column() {
if (item == this.selectDay) {
Text(item)
.fontColor(Color.White)
.textAlign(TextAlign.Center)
.height(40)
.width(40)
.border({ radius: 40 })
.fontSize(14)
.backgroundColor(Color.Black)
} else {
Text(item)
.textAlign(TextAlign.Center)
.height(40)
.width(40)
.fontSize(14)
}
}
.layoutWeight(1)
.align(Alignment.Center)
})
}
.margin({bottom:5})
}
.width('90%')
.backgroundColor(Color.White)
.borderRadius(15)
.height(150)
.justifyContent(FlexAlign.SpaceAround)
}
else{
Column(){
Text('无数据')
.fontSize(20)
.fontColor(Color.Gray)
}
.justifyContent(FlexAlign.Center)
.width('90%')
.backgroundColor(Color.White)
.borderRadius(15)
.height(150)
}
}
}
5 实机演示
基本数据展示多加了相对湿度和云量的展示

24小时数据以及7天数据的显示
