スワイパー戦闘
1. プロジェクトの構造
Swiper コントロールの最初の使用法は以前に書かれています. この記事では、@Link、@State、@Watchを組み合わせて、ビブラート スライド ビデオ再生と同様の効果を実現します。この記事のソースコードのアドレスはSwiper 実戦 です。
プロジェクト構造は下の図に示すとおりです。
これはPageVideo.ets
、ビデオ再生のリストを提供するために使用される APP のホームページです。動画再生の一時停止・開始を通知するスクロールで動画を切り替えるPlayView.ets
動画プレイヤーです。VideoItem.ets には、ビデオの再生アドレスなどのビデオ情報が含まれています。PageVideo.ets
PlayView.ets
2. PageVideo と PlayView の簡単な説明
2.1 @State 変数の使用
PageVideo
@State
および の 2 つの変更された変数が提供されます。これら 2 つの状態が変更されると、pageShow
プレイヤーは調整するように通知されます。number
PlayView
@Entry
@Component
export struct PageVideo {
@State videoArray: Array<VideoItem> = initializeOnStartup() // 数据源
//当切换视频的时候,会通知PlayView播放当前的视频,同时关闭上一个视频
@State index: number = 0 // 当前滑动的索引位置
@State pageShow: boolean = false // 当前页面是否可见,仅对@Entry修饰的主页面PageVideo而言,子组件需要用@Watch监听该状态
}
2.2 @Link および @Watch 変数の使用
では、PlayView
これら 2 つの状態が変化したことをどのように認識しますか? この時点で、@Link
ラベルが役割を果たします。PlayView
コードは次のとおりです。
@Component
export struct PlayView {
// 四条控制页面可见、页面不可见的控制
private isShow: boolean = false // 是否是可见状态
@Link @Watch("needPageShow") index: number // 监听父组件索引index状态变化, 不能在组件内部进行初始化
@Link @Watch("needPageShow") pageShow: boolean // 监听父组件是否可见pageShow状态变化, 不能在组件内部进行初始化
}
その中で、 @Watchタグで定義されたメソッドも使用されますneedPageShow
. number と pageShow の値が変更されると、このメソッドが呼び出されて、ビデオを制御して前のビデオを一時停止し、現在のビデオを再生します:
// 监听父组件index、pageShow属性变化就会触发的方法,@Watch
needPageShow() {
console.log("playView*** needPageShow")
if (this.pageShow) {
// 页面可见时触发
if (this.position == this.index) {
// 判断index与当前所在位置是否相同
this.isShow = true;
this.onPageShow()
} else {
if (this.isShow) {
// 已经是可见的状态改为不可见,并触发不可见方法回调
this.isShow = false;
this.onPageSwiperHide()
}
}
} else {
// 页面不可见触发
if (this.position == this.index) {
if (this.isShow) {
// 已经是可见的状态改为不可见,并触发不可见方法回调
this.isShow = false;
this.onPageHide()
}
}
}
}
2.3、Swiperの使用とPlayViewの初期化
PlayVideoではSwiper
動画数に応じてコントロールが初期化され、コントロールのサブコントロールはPlayView
. PlayView を初期化する場合、@Link で変更された変数を初期化するときに $ で変更する必要があることに注意してください。
build() {
Column() {
Swiper() {
ForEach(this.videoArray.map((item, index) => {
return {
i: index, data: item };
}),
item => {
//初始化@Link修饰的变量时需要用$修饰。
PlayView({
index: $index, pageShow: $pageShow, item: item.data, position: item.i })
},
item => item.data.id.toString())
}
.indicator(false) // 默认开启指示点
.loop(false) // 默认开启循环播放
.vertical(true) // 默认横向切换、更改为竖向滑动
.onChange((index: number) => {
//滚动Swiper的时候用来监听页面的变化
//此处会触发PlayView的needPageShow方法。
this.index = index
})
}
}
2.4. ページの表示状態が変化したときにビデオを一時停止して再生する
ホームボタンを押すと、アプリはバックグラウンドに入ります。つまり、APP の表と裏の状態が変化したときに、一時PlayView
停止または再生するように通知する必要があります。実装されonPageShow
、 PlayVideo では、関数が値の変化を監視し、実行されたメソッドがビデオの一時停止と再生を制御するために使用されるため、値の値が変化するとonPageHide
、これら 2 つのメソッドで値pageShow
が変更されます。pageShow
PlayView
@Link
PlayView
needPageShow
// 当此页面可见时触发,仅@Entry修饰的自定义组件生效
onPageShow(): void {
//当pageShow的值发生改变时,PlayView因为@Link的作用会监听到值的改变,从而
this.pageShow = true;
}
// 当此页面不可见时触发,仅@Entry修饰的自定义组件生效
onPageHide(): void {
this.pageShow = false;
}
2.5 PlayView および PageView ソース コード:
2つのすべてのソースコードは次のとおりです.もちろん、読者はSwiperを介してプロジェクト全体をダウンロードして分析および学習できます.
import {
VideoItem} from '../play/VideoItem'
@Component
export struct PlayView {
// 四条控制页面可见、页面不可见的控制
private isShow: boolean = false // 是否是可见状态
@Link @Watch("needPageShow") index: number // 监听父组件索引index状态变化, 不能在组件内部进行初始化
@Link @Watch("needPageShow") pageShow: boolean // 监听父组件是否可见pageShow状态变化, 不能在组件内部进行初始化
private position: number // 当前页面所在位置
@ObjectLink private item: VideoItem // @Observed与@ObjectLink配合使用实现 class修饰的模型数据改变触发UI更新
@State private playState: number = 0 // 0表示停止播放--stop 1表示开始播放--start 2表示暂停播放--pause
// @ts-ignore
private videoController: VideoController = new VideoController() // 视频播放器控制器
build() {
Stack({
alignContent: Alignment.Center | Alignment.End }) {
Video({
src: this.item.src, // 视频播放地址
controller: this.videoController // 视频播放器控制器
})
.controls(false) // 不需要控制栏
.autoPlay(this.playState == 1 ? true : false) // 首次可见状态自动播放
.objectFit(ImageFit.Contain) // 视频窗口自适应视频大小
.loop(true) // 循环播放
.onClick(() => {
// 点击播放、再点击暂停播放
if (this.playState == 1) {
this.playState = 2;
this.videoController.pause();
} else if (this.playState == 2) {
this.playState = 1;
this.videoController.start();
}
})
Column() {
Image(this.item.isLikes ? $r('app.media.vote1') : $r('app.media.vote0')) // 点赞图标
.width(36).height(36)
.onClick(() => {
if (this.item.isLikes) {
this.item.likesCount--;
} else {
this.item.likesCount++;
}
this.item.isLikes = !this.item.isLikes;
}).margin({
top: 40 })
Text(this.item.likesCount == 0 ? '点赞' : ('' + this.item.likesCount)).fontSize(16).fontColor(0xffffff) // 评论图标
Image($r('app.media.comment'))
.width(36).height(36).margin({
top: 20 })
Text(this.item.commentCount == 0 ? '评论' : ('' + this.item.commentCount))
.fontSize(16)
.fontColor(0xffffff) // 转发图标
Image($r('app.media.share'))
.width(36).height(36).margin({
top: 20 })
}.offset({
x: '-5%', y: '-10%' }) // 位置调整
Text(this.item.title)
.fontSize(16)
.fontColor(0xffffff)
.margin(10)
.offset({
x: '-50%', y: '40%' })
}.backgroundColor(Color.Black)
.width('100%')
.height('100%')
}
// 自定义的方法。页面可见状态会被调用,多次调用
onPageShow(): void {
console.log("pageView*** OnPageShow")
if (this.playState != 1) {
this.playState = 1;
this.videoController.start();
}
}
// 自定义的方法。页面不可见状态会被调用,多次调用,这种不可见是Swiper滑动时触发的
private onPageSwiperHide(): void {
console.log("playView*** onPageSwiperHide")
if (this.playState != 0) {
this.playState = 0;
this.videoController.stop(); // 停止视频播放
}
}
// 自定义的方法。页面不可见状态会被调用,多次调用,这种不可见是点击页面跳转、或者应用回到桌面时触发的
onPageHide(): void {
console.log("playView*** onPageHide")
if (this.playState != 2) {
this.playState = 2;
this.videoController.pause(); // 暂停视频播放
}
}
// 监听父组件index、pageShow属性变化就会触发的方法,@Watch
needPageShow() {
console.log("playView*** needPageShow")
if (this.pageShow) {
// 页面可见时触发
if (this.position == this.index) {
// 判断index与当前所在位置是否相同
this.isShow = true;
this.onPageShow()
} else {
if (this.isShow) {
// 已经是可见的状态改为不可见,并触发不可见方法回调
this.isShow = false;
this.onPageSwiperHide()
}
}
} else {
// 页面不可见触发
if (this.position == this.index) {
if (this.isShow) {
// 已经是可见的状态改为不可见,并触发不可见方法回调
this.isShow = false;
this.onPageHide()
}
}
}
}
}
import {
VideoItem, initializeOnStartup } from '../play/VideoItem'
import {
PlayView } from '../play/PlayView'
@Entry
@Component
export struct PageVideo {
@State videoArray: Array<VideoItem> = initializeOnStartup() // 数据源
//当切换视频的时候,会通知PlayView播放当前的视频,同时关闭上一个视频
@State index: number = 0 // 当前滑动的索引位置
@State pageShow: boolean = false // 当前页面是否可见,仅对@Entry修饰的主页面PageVideo而言,子组件需要用@Watch监听该状态
build() {
Column() {
Swiper() {
ForEach(this.videoArray.map((item, index) => {
return {
i: index, data: item };
}),
item => {
PlayView({
index: $index, pageShow: $pageShow, item: item.data, position: item.i })
},
item => item.data.id.toString())
}
.indicator(false) // 默认开启指示点
.loop(false) // 默认开启循环播放
.vertical(true) // 默认横向切换、更改为竖向滑动
.onChange((index: number) => {
this.index = index
})
}
}
// 当此页面可见时触发,仅@Entry修饰的自定义组件生效
onPageShow(): void {
this.pageShow = true;
}
// 当此页面不可见时触发,仅@Entry修饰的自定义组件生效
onPageHide(): void {
this.pageShow = false;
}
}
参考文献:
HarmonyOSの実用的なプロジェクトのリスト、知識と洞察を共有し、HarmonyOSのユニークな魅力を一緒に探ります。https://gitee.com/harmonyos/codelabs