HarmonyOS鸿蒙Next中一种短视频软件首页的设计思路
HarmonyOS鸿蒙Next中一种短视频软件首页的设计思路 短视频软件首页刷视频的解决方案,使用swiper实现
获取视频信息
import { backInfo_video, IStandard, sendInfo_video, sendRequest } from '@st/basic';
import { emitter } from '@kit.BasicServicesKit';
import { backInfo_username, sendInfo_username } from '@st/basic/src/main/ets/utils/interfaces';
@Entry
@Component
export struct homeView {
@State rawList: VideoItem[] = []
@Provide
@Watch("updateVideoList")
activeIndex: number = 0
@State page: number = 0
scroller: Scroller = new Scroller()
topList: string[] = ['经验', '热点', '直播', '精选', '团购', '关注', '商城', '本地', '推荐']
@State clickIndex: number = this.topList.length - 1
// TODO:视频滑动过去后从头开始播放,每次不保存视频进度,超出立即销毁
async aboutToAppear() {
await this.getVideoList()
}
aboutToDisappear() {
emitter.off(0)
}
// 获取视频信息
async getVideoList() {
const resData = await sendRequest<IStandard<backInfo_video[]>, sendInfo_video>({
url: 'videos',
method: 'post',
data: {
page: this.page + 1,
pageSize: 5
}
})
console.log(JSON.stringify(resData.data.result))
this.page += 1
// 获取返回数据的长度,长度<=上面那个发送数据的pageSize
const videoPoolLen = resData.data.result.length
// 遍历 --> 创建基本格式 --> 提取部分字段 --> push进去
for (let i = 0; i < videoPoolLen; i++) {
// 查询视频作者的用户昵称
// 封装的sendRequest方法,基于axios库,需要可查看我之前的帖子,或使用fetch等其它请求方法。
const resUsername = await sendRequest<IStandard<backInfo_username>, sendInfo_username>({
url: 'username',
data: {
id: resData.data.result[i].uploader_id
},
method: 'post'
})
const temPushVideoPoolInfo: VideoItem = {
videoUrl: resData.data.result[i].url,
imgUrl: resData.data.result[i].cover_url,
title: resData.data.result[i].title,
description: resData.data.result[i].description,
uploaderId: resData.data.result[i].uploader_id,
updatedTime: resData.data.result[i].updated_time,
category: resData.data.result[i].category,
commentCount: resData.data.result[i].comment_count,
likeCount: resData.data.result[i].like_count,
viewCount: resData.data.result[i].view_count,
shareCount: resData.data.result[i].share_count,
saveCount: resData.data.result[i].save_count,
status: resData.data.result[i].status,
userNickname: resUsername.data.result.username || '未知用户'
}
this.rawList.push(temPushVideoPoolInfo)
}
}
// TODO:下拉刷新
async refreshVideoList() {
// 首先置空列表
this.rawList = []
// 然后重置page的值
this.page = 0
// 然后触发获取视频信息
this.getVideoList()
}
async updateVideoList() {
if (this.activeIndex + 1 === this.rawList.length) {
this.getVideoList()
}
}
build() {
Stack({ alignContent: Alignment.TopStart }) {
// 视频的swiper部分
Swiper() {
ForEach(this.rawList, (item: VideoItem, index: number) => {
PlayVideo({ item, index })
})
}
.index($$this.activeIndex)
.cachedCount(5)
.loop(false)
.indicator(false)
.vertical(true)
.width('100%')
.height('100%')
// 顶部的横向滚动栏
Column() {
Row() {
Column() {
Image($r('app.media.more'))
.height(20)
.fillColor(Color.White)
.margin({ left: 10, right: 10 })
Image($r('app.media.exchange'))
.width(13)
.fillColor('rgba(0.0.0.0)')
.opacity(0)
}
Scroll(this.scroller) {
Row() {
ForEach(this.topList, (item: string, index) => {
Column() {
Text(item)
.fontColor(Color.White)
.height(20)
.width('14%')
.textAlign(TextAlign.Center)
Column() {
Image($r('app.media.exchange'))
.width(12)
.fillColor(index === this.topList.length - 1 ? Color.White : 'rgba(0.0.0.0)')
.opacity(index === this.topList.length - 1 ? 1 : 0)
}
.width('14%')
}
})
}
.layoutWeight(1)
}
.scrollBar(BarState.Off)
.scrollable(ScrollDirection.Horizontal)
.layoutWeight(1)
.onAppear(() => {
this.scroller.scrollPage({
next: true
})
})
Column() {
Image($r('app.media.search'))
.height(20)
.fillColor(Color.White)
.margin({ right: 10, left: 10 })
Image($r('app.media.exchange'))
.width(13)
.fillColor('rgba(0.0.0.0)')
.opacity(0)
}
}
.width('100%')
.margin({ top: 20 })
}
.width('100%')
}
.width('100%')
.height('100%')
}
}
自定义组件 – 播放视频
@Component
struct PlayVideo {
item: VideoItem = new VideoItem()
index: number = -1
@Consume
@Watch("updateActiveIndex")
activeIndex: number
controller: VideoController = new VideoController()
@State
playIng: boolean = true
updateActiveIndex() {
if (this.activeIndex === this.index) {
this.controller.start()
this.playIng = true
} else {
this.controller.pause()
this.playIng = false
}
}
// 将后端返回的视频标签数组拼接一下
openArray(cate: string[]) {
let reArr: string = ''
for (let i = 0; i < cate.length; i++) {
reArr += ' #' + cate[i]
}
return reArr
}
build() {
Stack({ alignContent: Alignment.TopStart }) {
// 主体思路分为两层,层叠布局。下层为视频swiper部分。
// 上层叠加为信息展示区、按钮操作区、空白区通过controller绑定控制视频的播放暂停与快进等,或自定义其它操作
// 视频层
Column() {
if (!this.playIng) {
Image($r('app.media.play_circle_fill'))
.width(60)
.height(60)
.fillColor(Color.Gray)
.position({ x: '50%', y: '50%' })
.translate({ x: '-50%', y: '-50%' })
.zIndex(999)
}
Video({
src: this.item.videoUrl,
previewUri: this.item.imgUrl,
controller: this.controller
})
.width('100%')
.autoPlay(this.index === 0)
.loop(true)
.aspectRatio(1.8)
.controls(false)
}
.justifyContent(FlexAlign.Center)
.backgroundColor(Color.Black)
.width('100%')
.height('100%')
// 操作+展示层
Column() {
// 四行:text占位、操作主体区、相关搜索、进度条
// text占位
Text('')
.width('100%')
.height(53) // margin-top的20,文字20,exchange13
// 操作主体区
// 左右两个区域
Row() {
// 左Column:滑动点击区+视频信息区
Column() {
// 滑动点击区暂时Text占位,宽度100%,高度占满
Text('')
.width('100%')
.layoutWeight(1)
.onClick(() => {
if (this.playIng) {
this.controller.pause()
} else {
this.controller.start()
}
this.playIng = !this.playIng
})
// 视频信息区继续Column平铺
Column({ space: 10 }) {
// 弹幕开关
Image($r('app.media.danmu'))
.width(25)
.fillColor(Color.White)
.margin({ left: 10 })
// 点击推荐
Row({ space: 5 }) {
Image($r('app.media.good_filling'))
.width(15)
.fillColor(Color.White)
.margin({ left: 5 })
Text('点击推荐')
.fontSize(12)
.fontColor(Color.White)
Image($r('app.media.right_arrow'))
.width(15)
.fillColor(Color.White)
.margin({ right: 5 })
}
.height(25)
.margin({ left: 10 })
.borderRadius(5)
.backgroundColor('rgba(100,100,100,0.3)')
// 用户名
Text('@' + this.item.userNickname)
.margin({ left: 10 })
.fontColor(Color.White)
.fontWeight(700)
.fontSize(18)
// 视频简介(两行可展开)
Text(this.item.description + this.openArray(this.item.category))
.fontSize(14)
.maxLines(2)
.margin({ left: 10, bottom: 10 })
.fontColor(Color.White)
.textOverflow({ overflow: TextOverflow.Ellipsis })
}
.width('100%')
.alignItems(HorizontalAlign.Start)
}
.width('85%')
// 右Column:加速播放区+按钮操作区
Column() {
// 加速播放区域,暂时用text占位
Text('')
.width('100%')
.layoutWeight(1)
// 按钮操作区域
Column({ space: 5 }) {
Stack({ alignContent: Alignment.Bottom }) {
Image($r('app.media.user_normal'))
.width('100%')
.border({ color: Color.White, width: 2 })
.borderRadius(100)
.fillColor(Color.White)
.backgroundColor(Color.Gray)
Image($r('app.media.plus'))
.width(18)
.padding(5)
.borderRadius(10)
.fillColor(Color.White)
.backgroundColor(Color.Red)
.offset({ x: 0, y: 9 })
}
.width('70%')
.margin({ bottom: 5 })
Column() {
Image($r('app.media.like_fill'))
.width('100%')
.fillColor(Color.White)
Text(this.item.likeCount.toString())
.width('100%')
.fontColor(Color.White)
.textAlign(TextAlign.Center)
}
.width('60%')
Column() {
Image($r('app.media.interactive_fill'))
.width('100%')
.fillColor(Color.White)
Text(this.item.commentCount.toString())
.width('100%')
.fontColor(Color.White)
.textAlign(TextAlign.Center)
}
.width('60%')
Column() {
Image($r('app.media.collection_fill'))
.width('100%')
.fillColor(Color.White)
Text(this.item.saveCount.toString())
.width('100%')
.fontColor(Color.White)
.textAlign(TextAlign.Center)
}
.width('60%')
Column() {
Image($r('app.media.share_fill'))
.width('100%')
.fillColor(Color.White)
Text(this.item.shareCount.toString())
.width('100%')
.fontColor(Color.White)
.textAlign(TextAlign.Center)
}
.width('60%')
Image($r('app.media.music'))
.width('70%')
.borderRadius(100)
.fillColor(Color.White)
.backgroundColor(Color.Grey)
}
.margin({ bottom: 10 })
}
.width('15%')
}
.width('100%')
.layoutWeight(1)
// 相关搜索
Row() {
Image($r('app.media.search'))
.width(15)
.margin({ left: 10, right: 10 })
.fillColor(Color.White)
Text('相关搜索 · ')
.fontColor(Color.White)
.fontSize(15)
Text('${搜索类目}')
.fontColor(Color.White)
.fontSize(15)
Text('') // 占位
.layoutWeight(1)
Image($r('app.media.right_arrow'))
.width(20)
.margin({ right: 5 })
.fillColor(Color.White)
}
.height(30)
.width('100%')
.backgroundColor('rgba(100,100,100,0.3)')
// 进度条,暂时用分割线占位
Divider()
.width('100%')
.strokeWidth(2)
.backgroundColor(Color.Pink)
}
}
.height('100%')
.width('100%')
}
}
class VideoItem {
title: string = ''
description: string = ''
uploaderId: number = 0
updatedTime: string = ''
videoUrl: string = ''
category: string[] = []
commentCount: number = 0
likeCount: number = 0
viewCount: number = 0
shareCount: number = 0
saveCount: number = 0
status: number = 0
imgUrl: string = ''
userNickname?: string = ''
}
更多关于HarmonyOS鸿蒙Next中一种短视频软件首页的设计思路的实战教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS鸿蒙Next中设计短视频软件首页时,可以采用以下思路:
-
界面布局:首页通常采用全屏展示,视频内容占据主要区域。顶部可以设置导航栏,包括搜索、消息、个人中心等功能入口。底部可以设置标签栏,用于快速切换不同分类或功能模块。
-
视频流展示:视频流采用瀑布流或垂直滚动方式,支持自动播放和手动滑动切换。每个视频卡片可以包含封面、标题、作者信息、点赞、评论等交互元素。
-
交互设计:支持上下滑动切换视频,左右滑动切换分类或功能模块。双击屏幕可点赞,长按可弹出更多操作选项,如分享、收藏、举报等。
-
个性化推荐:根据用户行为和偏好,动态调整视频推荐内容。首页可以设置“推荐”、“关注”、“热门”等不同分类,满足用户多样化需求。
-
实时更新:首页内容需实时更新,确保用户每次打开都能看到最新视频。可以通过推送通知或下拉刷新方式,提醒用户有新内容。
-
性能优化:由于视频加载和播放对性能要求较高,需优化视频缓存、预加载和播放流畅度,确保用户体验。
-
适配与兼容:确保首页设计在不同设备上都能良好显示和操作,包括手机、平板、智慧屏等。
通过以上设计思路,可以在HarmonyOS鸿蒙Next中实现一个功能完善、交互流畅、用户体验良好的短视频软件首页。
更多关于HarmonyOS鸿蒙Next中一种短视频软件首页的设计思路的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS鸿蒙Next中,短视频软件首页的设计应注重简洁与高效。采用瀑布流布局,支持智能推荐与个性化内容展示,提升用户体验。利用鸿蒙的分布式能力,实现跨设备无缝切换观看。同时,集成高效的视频加载与播放技术,确保流畅性。此外,通过鸿蒙的原子化服务,用户可快速分享、评论,增强社交互动。整体设计应遵循鸿蒙的设计规范,确保一致性与易用性。