HarmonyOS 鸿蒙Next自然壁纸实战教程-视频列表

HarmonyOS 鸿蒙Next自然壁纸实战教程-视频列表

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)

如何获取资料

获取资料的途径,可以关注我们 官网的公众号 青蓝逐码 ,输入 项目名称 《自然壁纸》 即可获得以上资料。

![获取资料]

为什么需要关注公众号

如果我们的资源,网友连关注公众号的欲望都没有,说明我们的这个资料和资源也没有什么太大价值,那么不要也罢,可以让用户付出一些成本的,才是能证明有真正价值的东西。

关于我们

[关于青蓝逐码组织]

如果你兴趣想要了解更多的鸿蒙应用开发细节和最新资讯甚至你想要做出一款属于自己的应用!欢迎在评论区留言或者私信或者看我个人信息,可以加入技术交流群。

![关于我们]


更多关于HarmonyOS 鸿蒙Next自然壁纸实战教程-视频列表的实战教程也可以访问 https://www.itying.com/category-93-b0.html

2 回复

鸿蒙Next自然壁纸实现视频列表功能,主要使用Video组件和ListContainer组件。在ets文件中,首先创建VideoItem类定义视频数据结构。通过@State装饰器管理视频列表数据,使用ForEach循环渲染ListContainer。每个ListItem包含Video组件,设置displayControls属性为false实现自动播放。通过onClick事件处理视频切换,使用currentTime方法控制播放进度。视频资源建议放在resources/base/media目录下,用$r引用。注意在config.json中声明ohos.permission.READ_MEDIA权限。

更多关于HarmonyOS 鸿蒙Next自然壁纸实战教程-视频列表的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


这是一个关于HarmonyOS Next开发中实现视频列表功能的详细教程。从技术实现来看,主要涉及以下几个关键点:

  1. 视频组件使用:使用Video组件替代Image组件来渲染视频内容,这是与图片列表的主要区别。

  2. 多线程下载:由于视频文件较大,使用taskpool实现多线程下载,避免阻塞UI线程。

  3. 列表优化:采用LazyForEach结合List实现高效渲染,并设置cachedCount为10来优化性能。

  4. 分类展示:通过Scroll组件实现横向分类滚动,使用ButtonType.Capsule样式展示分类标签。

  5. 导航跳转:点击视频卡片通过Navigation跳转到视频详情页。

代码结构清晰,展示了HarmonyOS ArkUI的声明式开发特点,包括组件嵌套、样式设置和事件处理等。特别是对视频缩略图、播放时长等细节的处理值得参考。

这个教程对于想学习HarmonyOS视频相关功能开发的开发者很有帮助,展示了从搜索、分类到列表展示的完整流程。

回到顶部