08-自然壁纸实战教程-视频列表
前言
视频列表页面本质上也是一个数据展示的列表,不同之处在于之前是是展示壁纸,Image组件负责渲染,这里展示的是视频,使用Video组件,另外视频页面也实现了下载的基本功能,由于视频往往比图片要大,所以这里的下载是比较耗时的,因此使用了多线程技术taskpool实现了视频的下载,并且保存到相册。
视频搜索
这个模块其实是老模块了,这里直接提供代码
// 顶部搜索栏
Row() {
TextInput({ placeholder: '搜索视频...', text: $$this.videoViewModel.searchText })
.width('80%')
.height(40)
.backgroundColor('#F5F5F5')
.borderRadius(20)
.padding({ left: 15, right: 15 })
.onChange((text) => {
this.videoViewModel.params.q = text
})
.onSubmit(async () => {
await this.videoViewModel.search()
})
Button('搜索')
.width('18%')
.height(40)
.margin({ left: 8 })
.borderRadius(20)
.backgroundColor('#3366CC')
.onClick(async () => {
await this.videoViewModel.search()
})
}
.width('100%')
.padding(10)
.margin({ top: 6 })
视频分类
视频分类页面也是一个常规的分类滚动结构,可以出用Scroll组件完成基本结构
Row() {
Text('类型:')
.fontSize(16)
.fontWeight(FontWeight.Medium)
.margin({ right: 10 })
// 使用Scroll实现横向滚动
Scroll() {
Row() {
// 使用categories数据源
ForEach(LocalData.CategoryData, (item: ICategory) => {
Button({ type: ButtonType.Capsule }) {
Text(item.text)
.fontSize(16)
.fontColor(this.videoViewModel.selectedCategory === item.value ? '#FFFFFF' : '#333333')
.padding({ left: 5, right: 5 })
}
.backgroundColor(this.videoViewModel.selectedCategory === item.value ? '#3366CC' : '#F0F0F0')
.margin({ right: 12 })
.height(40)
.width('auto')
.padding({ left: 15, right: 15 })
.onClick(() => {
this.videoViewModel.selectCategory(item.value)
})
})
}
.width('auto')
}
.scrollable(ScrollDirection.Horizontal)
.scrollBar(BarState.Off)
.width('80%')
.layoutWeight(1)
}
.width('100%')
.padding({ left: 10, right: 10, bottom: 10 })
.alignItems(VerticalAlign.Center)
LocalData.CategoryData 数据源
static readonly CategoryData: ICategory[] = [
{
"id": 0,
"text": "背景",
"value": "backgrounds",
"icon": "🌅"
},
{
"id": 1,
"text": "时尚",
"value": "fashion",
"icon": "👔"
},
{
"id": 2,
"text": "自然",
"value": "nature",
"icon": "🌲"
},
{
"id": 3,
"text": "科学",
"value": "science",
"icon": "🔬"
},
{
"id": 4,
"text": "教育",
"value": "education",
"icon": "📚"
},
{
"id": 5,
"text": "感情",
"value": "feelings",
"icon": "❤️"
},
{
"id": 6,
"text": "健康",
"value": "health",
"icon": "🏥"
},
{
"id": 7,
"text": "人",
"value": "people",
"icon": "👥"
},
{
"id": 8,
"text": "宗教",
"value": "religion",
"icon": "🙏"
},
{
"id": 9,
"text": "地方",
"value": "places",
"icon": "🌆"
},
{
"id": 10,
"text": "动物",
"value": "animals",
"icon": "🐱"
},
{
"id": 11,
"text": "工业",
"value": "industry",
"icon": "🏭"
},
{
"id": 12,
"text": "计算机",
"value": "computer",
"icon": "💻"
},
{
"id": 13,
"text": "食品",
"value": "food",
"icon": "🍜"
},
{
"id": 14,
"text": "体育",
"value": "sports",
"icon": "🏃"
},
{
"id": 15,
"text": "交通",
"value": "transportation",
"icon": "🚗"
},
{
"id": 16,
"text": "旅行",
"value": "travel",
"icon": "✈️"
},
{
"id": 17,
"text": "建筑物",
"value": "buildings",
"icon": "🏢"
},
{
"id": 18,
"text": "商业",
"value": "business",
"icon": "💼"
},
{
"id": 19,
"text": "音乐",
"value": "music",
"icon": "🎵"
}
]
视频列表
这里是视频列表,我们发送请求获取到视频数据后,使用 LazyForEach
结合 List
实现的视频列表渲染
// 视频列表
if (this.videoViewModel.videoList.totalCount() > 0) {
List() {
LazyForEach(this.videoViewModel.videoList, (video: VideoData, index: number) => {
ListItem() {
Column() {
// 视频缩略图
Stack() {
Image(video.videos?.medium?.thumbnail || '')
.width('100%')
.height(200)
.borderRadius(8)
.objectFit(ImageFit.Cover)
// 播放时长
if (video.duration) {
Text(CommonUtils.formatDuration(video.duration))
.fontSize(12)
.fontColor($r('sys.color.comp_background_list_card'))
.backgroundColor('rgba(0, 0, 0, 0.6)')
.borderRadius(4)
.padding({
left: 6,
right: 6,
top: 2,
bottom: 2
})
}
}
.width('100%')
.alignContent(Alignment.BottomEnd)
// 视频信息
Row() {
Column() {
Text(video.tags.split(',')[0] || '未知标题')
.fontSize(16)
.fontWeight(FontWeight.Bold)
.margin({ top: 8, bottom: 4 })
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
Row() {
Text(`${video.views || 0} 次观看`)
.fontSize(12)
.fontColor('#666666')
Text(`${video.likes || 0} 赞`)
.fontSize(12)
.fontColor('#666666')
.margin({ left: 10 })
}
}
.alignItems(HorizontalAlign.Start)
.layoutWeight(1)
}
.width('100%')
.padding({
left: 4,
right: 4,
top: 4,
bottom: 8
})
}
.width('100%')
.borderRadius(8)
.backgroundColor($r('sys.color.comp_background_list_card'))
.margin({ bottom: 12 })
}
.onAppear(() => {
if (index == (this.videoViewModel.videoList.totalCount() - 5)) {
this.videoViewModel.loadMore()
}
})
.onClick(() => {
NavigationUtils.getInstance().navigatePush(NavigationConst.Video_Player_View, video)
})
}, (video: VideoData, index: number) => video.id.toString())
}
.width('100%')
.layoutWeight(1)
.padding({ left: 10, right: 10 })
.cachedCount(10)
}
视频详情
视频详情是通过点击视频卡片,然后通过Navigation跳转实现的
NavigationUtils.getInstance().navigatePush(NavigationConst.Video_Player_View, video)