HarmonyOS鸿蒙Next中如何做到video组件src更新的时候给视频加个过渡效果

HarmonyOS鸿蒙Next中如何做到video组件src更新的时候给视频加个过渡效果

Video({ src: CommonConstants.videoList[this.currentIndex].src, controller: CommonConstants.videoList[this.currentIndex].controller, }).width(‘100%’).height(‘100%’)

我是 通过改变 this.currentIndex 来实现切换全屏视频的

试了好几种方法都不行 请问如何才能 在 video 组件 src 更新的时候给视频加个过渡效果(在视频加载之前


更多关于HarmonyOS鸿蒙Next中如何做到video组件src更新的时候给视频加个过渡效果的实战教程也可以访问 https://www.itying.com/category-93-b0.html

6 回复

您好,可以使用淡入淡出达成过渡效果。

参考代码如下:

@Entry
@Component
struct VideoTransition {
  [@State](/user/State) currentSrc: Resource = $r('app.media.video1');
  [@State](/user/State) opacityValue: number = 1;
  controller: VideoController = new VideoController();

  build() {

    Column() {

      Video({
        src: this.currentSrc,
        previewUri: $r('app.media.preview'), // 必须设置预览图
        controller: this.controller
      })
        .opacity(this.opacityValue)
        .onPrepared(() => { // 视频加载完成回调
          animateTo({ duration: 500 }, () => {
            this.opacityValue = 1; // 淡入新视频
          });
        })

    }
  }

  // 视频切换方法
  changeVideo(newSrc: Resource) {
    animateTo({ duration: 300 }, () => {
      this.opacityValue = 0; // 先淡出当前视频
    }).then(() => {
      this.currentSrc = newSrc; // 更新视频源
      this.controller.start(); // 自动播放新视频
    });
  }
}
  1. 通过previewUri设置预览图,避免切换时黑屏
  2. 使用animateTo实现透明度动画过渡
  3. 在onPrepared回调中触发动画,确保视频加载完成
  4. 通过@State变量驱动UI更新

更多关于HarmonyOS鸿蒙Next中如何做到video组件src更新的时候给视频加个过渡效果的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


// xxx.ets

@Component struct VideoCreateComponent { @State videoSrc: Resource = $r(‘app.media.uav’); @State previewUri: Resource = $r(‘app.media.uav’); @State curRate: PlaybackSpeed = PlaybackSpeed.Speed_Forward_1_00_X; @State isAutoPlay: boolean = false; @State showControls: boolean = true; @State isShortcutKeyEnabled: boolean = false; @State scaleX: number = 1; @State scaleY: number = 1; @State opacityValue: number = 1; controller: VideoController = new VideoController();

build() { Column() { Column() { Video({ src: this.videoSrc, previewUri: this.previewUri, currentProgressRate: this.curRate, controller: this.controller }) .width(‘100%’) .height(600) .scale({ x: this.scaleX, y: this.scaleY }) .autoPlay(this.isAutoPlay) .controls(this.showControls) .enableShortcutKey(this.isShortcutKeyEnabled) .opacity(this.opacityValue) .onStart(() => { console.info(‘onStart’) }) .onPause(() => { console.info(‘onPause’) }) .onFinish(() => { console.info(‘onFinish’) }) .onError(() => { console.info(‘onError’) }) .onStop(() => { console.info(‘onStop’) }) .onPrepared((e?: DurationObject) => { if (e != undefined) { console.info('onPrepared is ’ + e.duration) } this.controller.setCurrentTime(0) this.controller.start() setTimeout(() => { this.controller.stop() }, 50) }) .onSeeking((e?: TimeObject) => { if (e != undefined) { console.info('onSeeking is ’ + e.time) } }) .onSeeked((e?: TimeObject) => { if (e != undefined) { console.info('onSeeked is ’ + e.time) } }) .onUpdate((e?: TimeObject) => { if (e != undefined) { console.info('onUpdate is ’ + e.time) } }) .onFullscreenChange((e?: FullscreenObject) => { if (e != undefined) { console.info('onFullscreenChange is ’ + e.fullscreen) } }) }.width(‘100%’) .backgroundColor(Color.Black)

  Row() {
    Button('scale过渡').onClick(() => {
      animateTo({
        duration: 500,
        onFinish: () => {
          // 切换视频源
          animateTo({
            duration: 500,
          }, () => {
            if (this.videoSrc.id == $r('app.media.hdc').id) {
              this.videoSrc = $r('app.media.uav')
            } else {
              this.videoSrc = $r('app.media.hdc')
            }
            this.scaleX = 1;
            this.scaleY = 1;
          });
        }
      }, () => {
        this.scaleX = 0;
        this.scaleY = 0;
      });

    }).margin(5)

    Button('显隐过渡').onClick(() => {
      animateTo({
        duration: 500,
        onFinish: () => {
          // 切换视频源
          animateTo({
            duration: 500,
          }, () => {
            if (this.videoSrc.id == $r('app.media.hdc').id) {
              this.videoSrc = $r('app.media.uav')
            } else {
              this.videoSrc = $r('app.media.hdc')
            }
            this.opacityValue = 1;
          });
        }
      }, () => {
        this.opacityValue = 0;
      });

    }).margin(5)
  }
}

} }

interface DurationObject { duration: number; }

interface TimeObject { time: number; }

interface FullscreenObject { fullscreen: boolean; }

核心思路

  1. 分离视频状态:将视频的显示 / 隐藏状态与 currentIndex 解耦,使用独立状态(如 showVideo)控制过渡动画。
  2. 使用 Animate 组件:包裹视频容器,在状态变化时触发进入 / 退出动画(如渐变、缩放等)。
  3. 延迟加载新视频:在旧视频退出动画完成后,再更新 src 并显示新视频,确保过渡效果完整。

兄弟哪里来的 Animate 组件呀,arkts 没有这个组件吧,

在HarmonyOS Next中,可以通过VideoController和自定义动画实现Video组件src更新时的过渡效果。首先创建VideoController实例绑定到Video组件。在更新src前,使用ArkUI的动画API(如animateTo)执行淡出动画,设置opacity从1到0。然后更新src属性,再执行淡入动画,opacity从0到1。关键代码示例:

@State opacity: number = 1;
videoController: VideoController = new VideoController();

changeSrc() {
  animateTo({ duration: 300 }, () => {
    this.opacity = 0;
  });
  // 更新src后
  animateTo({ duration: 300 }, () => {
    this.opacity = 1;
  });
}

Video组件需设置opacity属性绑定状态变量。

在HarmonyOS Next中,可以通过结合动画组件和状态管理来实现视频切换时的过渡效果。以下是实现方案:

  1. 使用Stack布局叠加Video和动画组件:
@State currentIndex: number = 0;
@State showVideo: boolean = true;

build() {
  Stack() {
    if (showVideo) {
      Video({
        src: CommonConstants.videoList[currentIndex].src,
        controller: CommonConstants.videoList[currentIndex].controller,
      })
      .width('100%')
      .height('100%')
      .onReady(() => {
        // 视频加载完成后淡入
        animateTo({ duration: 300 }, () => {
          opacityValue = 1;
        });
      })
      .opacity(opacityValue)
    }

    // 过渡动画层
    if (isChanging) {
      Image($r('app.media.transition_image')) // 可以是纯色或特效图片
        .width('100%')
        .height('100%')
        .transition(TransitionEffect.OPACITY.animation({ duration: 300 }))
    }
  }
}
  1. 切换视频时触发过渡动画:
changeVideo(index: number) {
  // 先显示过渡层
  isChanging = true;
  opacityValue = 0;
  
  // 延迟执行视频切换
  setTimeout(() => {
    currentIndex = index;
    isChanging = false;
  }, 300); // 与动画持续时间保持一致
}

关键点:

  1. 使用opacity属性控制淡入淡出效果
  2. 通过setTimeout确保动画执行完成后再切换视频源
  3. 可以配合transition或animateTo实现更复杂的动画效果

注意:由于Video组件本身的限制,过渡效果主要依靠外层容器的动画来实现。

回到顶部