自定义转场:实现缩略图查看大图缩放并且位置复原效果

聊天窗口,或者朋友圈,有缩略图场景,点击缩略图,从缩略图位置逐渐放大至全屏查看大图,在大图模式下,点击后缩小至原来缩略图位置。

HarmonyOS
2024-05-26 11:06:01
浏览
收藏 0
回答 1
待解决
回答 1
按赞同
/
按时间
NGKSWCIDT

使用的核心API

模态转场动画,属性动画。

核心代码解释

获取位置信息工具类,通过组件id获取当前组件的位置信息

class Utils { 
  static rect_left: number 
  static rect_top: number 
  static rect_right: number 
  static rect_bottom: number 
  static rect_value: Record<string, number> 
  
  //获取组件所占矩形区域坐标 
  static getComponentRect(key:string):Record<string, number> { 
    let strJson = getInspectorByKey(key) 
    let obj:Record<string, string> = JSON.parse(strJson) 
    console.info("fxm [getInspectorByKey] current component obj is: " + JSON.stringify(obj)) 
    let rectInfo:string[] = JSON.parse('[' + obj.$rect + ']') 
    console.info("fxm [getInspectorByKey] rectInfo is: " + rectInfo) 
    Utils.rect_left = JSON.parse('[' + rectInfo[0] + ']')[0] 
    Utils.rect_top = JSON.parse('[' + rectInfo[0] + ']')[1] 
    Utils.rect_right = JSON.parse('[' + rectInfo[1] + ']')[0] 
    Utils.rect_bottom = JSON.parse('[' + rectInfo[1] + ']')[1] 
    return Utils.rect_value = { 
      "left": Utils.rect_left, "top": Utils.rect_top, "right": Utils.rect_right, "bottom": Utils.rect_bottom 
    } 
  } 
} 

在缩略图页面Index中定义点击缩略图的位置变量

// 标记当前点击缩略图位置信息 
bounds:Record<string, number> = {} 

在缩略图页面Index中定义模态转场

// 第一步:定义全屏模态转场控制变量 
  // 模态转场控制变量,在PageB中@Link双向绑定保持模态状态统一 
  @State isPresent: boolean = false; 
  
// 第二步:定义模态展示界面大图页面PageB 
  // 通过@Builder构建模态展示界面 
  @Builder 
  MyBuilder() { 
    Column() { 
      PageB({ 
        isPresent: this.isPresent,// @State状态变量初始化PageB中@Link变量 
        left: this.bounds['left'], 
        top: this.bounds['top'], 
      }) 
    }.backgroundColor(Color.Transparent) 
  } 
  
build() { 
    Column() { 
      Image($r('app.media.transition_image1')) 
        .width(150) 
        .height(150) 
        .onClick(() => { 
          // 第三步:通过模态接口调起模态展示界面,通过转场动画或者共享元素动画去实现对应的动画效果 
          this.isPresent = !this.isPresent; 
          this.bounds = Utils.getComponentRect('smallImage2') 
        }) 
        .id('smallImage2') 
  
      Image($r('app.media.transition_image1')) 
        .width(150) 
        .height(150) 
        .onClick(() => { 
          // 第三步:通过模态接口调起模态展示界面,通过转场动画或者共享元素动画去实现对应的动画效果 
          this.isPresent = !this.isPresent; 
          this.bounds = Utils.getComponentRect('smallImage') 
        }) 
        .id('smallImage') 
  
      Image($r('app.media.transition_image1')) 
        .width(150) 
        .height(150) 
        .onClick(() => { 
          // 第三步:通过模态接口调起模态展示界面,通过转场动画或者共享元素动画去实现对应的动画效果 
          this.isPresent = !this.isPresent; 
          this.bounds = Utils.getComponentRect('smallImage1') 
        }) 
        .id('smallImage1') 
    } 
    // 通过选定的模态状态变量,绑定模态展示界面,ModalTransition这里选择NONE不显示系统动画效果。 
    .bindContentCover(this.isPresent, this.MyBuilder(), ModalTransition.NONE) 
    .justifyContent(FlexAlign.SpaceAround) 
    .width('100%') 
    .height('100%') 
  } 

在大图页面PageB中定义模态变量与缩略图页面Index保持状态同步

@Link isPresent: boolean 

在大图页面PageB中定义位置信息和页面背景

left: number = 0 // 缩略图Index传入左边距 
top: number = 0 // 缩略图Index传入左边距 
  
@State cWidth: number | string = 150 // 大图Image组件初始高度与缩略图保持一致 
@State cHeight: number | string = 150 // // 大图Image组件初始高度与缩略图保持一致 
@State positionX: number = 0 // 大图Image组件初始化positionX 
@State positionY: number = 0 // 大图Image组件初始化positionY 
  
@State backColor: Color = Color.Transparent; // 页面背景颜色初始为透明 

大图页面实现放大动画

aboutToAppear(): void { 
    // 用左和上边距初始化大图Image组件位置 
    this.positionX = px2vp(this.left) 
    this.positionY = px2vp(this.top) 
    // 延迟动画,避免与模态冲突 
    setTimeout(() => { 
      animateTo({ 
        duration: 500, 
        curve: Curve.Friction, 
        delay: 0, 
        iterations: 1, 
        playMode: PlayMode.Normal, 
        onFinish: () => { 
          console.log(this.positionY.toString()) 
        } 
      }, () => { 
        this.cWidth = '100%' // 动画至全屏宽度 
        this.cHeight = '100%' // 动画至全屏高度 
        this.positionX = 0; // 动画至x坐标为0 
        this.positionY = 0; // 动画至y坐标为0 
        this.backColor = Color.Black // 动画至背景颜色为黑色 
      }) 
    }, 100) 
  } 

初始化大图Image组件和容器,添加返回动画

build() { 
    Column({ space: 0 }) { 
      Image($r('app.media.transition_image1')) 
        .objectFit(ImageFit.Auto) 
        .position({ x: this.positionX, y: this.positionY })  
        .width(this.cWidth) 
        .height(this.cHeight) 
        .onClick(() => { 
        // 点击大图返回至缩略图 
          animateTo({ 
            duration: 500, 
            curve: Curve.Friction, 
            delay: 0, 
            iterations: 1, 
            playMode: PlayMode.Normal, 
            onFinish: () => { 
              this.isPresent = false // 动画结束则模态退出PageB,回到Index 
            } 
          }, () => { 
            this.cWidth = 150 // 恢复至初始宽度 
            this.cHeight = 150 // 恢复至初始高度 
            this.positionX = px2vp(this.left) // 恢复至初始x坐标 
            this.positionY = px2vp(this.top) // 恢复至初始y坐标 
            this.backColor = Color.Transparent // 恢复至透明背景 
          }) 
        }) 
    } 
    .justifyContent(FlexAlign.Center) 
    .clip(true) 
    .width('100%') 
    .height('100%') 
    .backgroundColor(this.backColor) 
  }

注明适配的版本信息

IDE版本:4.1.3.500

SDK版本: 4.1.0

分享
微博
QQ
微信
回复
2024-05-27 10:50:13
相关问题
缩略图,如何获取文件的缩略图
311浏览 • 1回复 待解决
鸿蒙能获取图片指定大小的缩略图
8209浏览 • 1回复 待解决
自定义弹窗自定义转场动画
446浏览 • 1回复 待解决
如何设置自定义弹窗位置
829浏览 • 1回复 待解决
如何实现动画转场效果
397浏览 • 1回复 待解决
TextInput是否能自定义hover效果
934浏览 • 1回复 待解决
如何实现H5自定义事件
853浏览 • 1回复 待解决
如何实现自定义应用入场动画
405浏览 • 1回复 待解决