HarmonyOS 查看大图组件,支持多图,可放大缩小,本地图片、网络图片均可

HarmonyOS
2025-01-09 16:06:46
浏览
收藏 0
回答 1
回答 1
按赞同
/
按时间
fox280

可参考以下示例:

1.Page页面:

import router from '@ohos.router'

@Entry
@Component
struct SharedTransitionExample {
  @State active: boolean = false
  @State imageNames: Resource[] = [$r('app.media.image1'), $r('app.media.image2'), $r('app.media.image3')]
  @StorageLink('currentIndex') currentIndex: number = 0

  build() {
    Row() {
      ForEach(this.imageNames, (res: Resource, index: number) => {
        Column() {
          Image(res)
            .width('100%')
            .height('100%')
            .objectFit(ImageFit.Contain) // 在组件上绑定缩放比例,可以通过修改缩放比例来实现组件的缩小或者放大
        }
        .width(100)
        .height(100)
        .clip(true)
        .sharedTransition('sharedImage' + res.id, {
          duration: 200,
          curve: Curve.Linear,
          zIndex: this.currentIndex === index ? 10 : -10
        })
        .onClick(() => {
          this.currentIndex = index
          router.pushUrl({ url: 'pages/Index', params: {
            data: this.imageNames,
          } })
        })
      })
    }.width('100%')
    .height('100%')
  }

  pageTransition() {
    PageTransitionEnter({ duration: 0, curve: Curve.Linear })
      .onEnter((type?: RouteType, progress?: number) => {

      }) // 进场过程中会逐帧触发onEnter回调,入参为动效的归一化进度(0% -- 100%)
    PageTransitionExit({ duration: 0, curve: Curve.Ease })
      .onExit((type?: RouteType, progress?: number) => {
      }) // 退场过程中会逐帧触发onExit回调,入参为动效的归一化进度(0% -- 100%)
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.

2.Index页面

import window from '@ohos.window';
import router from '@ohos.router';

interface Data {
  data: Resource[];
}

enum Direction {
  None,
  Left,
  Right,
}

@Entry
@Component
struct Index {
  private swiperController: SwiperController = new SwiperController();
  @State imageNames: Resource[] = []
  @StorageLink('currentIndex') currentIndex: number = 0
  @State screenWidth: number = 0;
  @State op: number = 0

  aboutToAppear() {
    const data = (router.getParams() as Data)
    this.imageNames = data.data
    window.getLastWindow(getContext(this)).then(currentWindow => {

      let property = currentWindow.getWindowProperties();
      this.screenWidth = property.windowRect.width;
    })
  }

  build() {
    Stack({ alignContent: Alignment.Center }) {
      Swiper(this.swiperController) {
        ForEach(this.imageNames, (name: Resource, index: number) => {
          Column() {
            ImageComponent({
              image: name,
              viewWidth: this.screenWidth,
              isCurrent: this.currentIndex === index,
              onNeedGoNext: (dire: Direction) => {
                if (dire === Direction.Right) {
                  this.swiperController.showNext()
                } else if (dire === Direction.Left) {
                  this.swiperController.showPrevious()
                }
              }
            }).zIndex(index == this.currentIndex ? 2 : 1)
          }.width('100%')
          .height('100%')
          .justifyContent(FlexAlign.Center)
        })
      }
      .index(this.currentIndex)
      .indicator(false)
      .disableSwipe(true)
      .itemSpace(10)
      .onChange((index: number) => {
        this.currentIndex = index
      })
    }.width('100%').height('100%')
    .backgroundColor(`rgba(0,0,0,${this.op})`)
  }
  pageTransition() {
PageTransitionEnter({ duration: 200, curve: Curve.Linear })
.onEnter((type?: RouteType, progress?: number) => {
if (progress) {
this.op = progress
}

}) // 进场过程中会逐帧触发onEnter回调,入参为动效的归一化进度(0% -- 100
@Component
struct ImageComponent {
private image: Resource = $r('app.media.icon')
private preGeometryScale: number = 1
@State geometryScale: number = 1
private preOffsetX: number = 0
private preOffsetY: number = 0
@State geometryOffsetX: number = 0
@State geometryOffsetY: number = 0
@State imageWidth: number = 0
@State imageHeight: number = 0
@Prop viewWidth: number = 0
@Prop isCurrent: boolean = false
private dire: Direction = Direction.None
private goNext: boolean = true
private pinching: boolean = false
private onNeedGoNext: (dire: Direction) => void = () => {
}

  reset(): Promise<void> | undefined {
    this.preGeometryScale = 1
    this.preOffsetX = 0
    this.preOffsetY = 0
    this.dire = Direction.None
    this.goNext = true
    if (this.geometryScale === 1) return
    return new Promise<void>(res => {
      animateTo({ duration: 200, onFinish: res }, () => {
        this.geometryScale = 1
        this.geometryOffsetX = 0
        this.geometryOffsetY = 0
      })
    })
  }

  build() {
    Column() {
      Image(this.image)
        .onComplete((e) => {
          this.imageWidth = (e?.width || 0)
          this.imageHeight = (e?.height || 0)
        })
        .objectFit(ImageFit.Cover)
        .width(this.imageWidth + 'px')
        .height(this.imageHeight + 'px')
        .scale({
          x: this.geometryScale,
          y: this.geometryScale
        })
        .offset({
          x: this.geometryOffsetX,
          y: this.geometryOffsetY
        })
        .focusable(true)
        .objectFit(ImageFit.Cover)
        .autoResize(false)
        .sharedTransition('sharedImage' + this.image.id, {
          duration: 200,
          curve: Curve.Linear,
          zIndex: this.isCurrent ? 10 : -10
        })
    }
    .clip(true)
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
    .hitTestBehavior(HitTestMode.Default)
    .parallelGesture( // 在组件上绑定二指触发的捏合手势
      GestureGroup(GestureMode.Parallel,
        PinchGesture({ fingers: 2 })
          .onActionStart((event: GestureEvent) => {
            this.pinching = true
            this.goNext = false
          })// 当捏合手势触发时,可以通过回调函数获取缩放比例,从而修改组件的缩放比例
          .onActionUpdate((event: GestureEvent) => {
            const s = this.preGeometryScale * event.scale;
            this.geometryScale = Math.max(0.6, Math.min(2, s))
          })
          .onActionEnd(async () => {
            this.preGeometryScale = this.geometryScale
            if (this.preGeometryScale < 1) {
              await this.reset()
            }
            this.pinching = false
          }),
        PanGesture()
          .onActionStart((event?: GestureEvent) => {
          })
          .onActionUpdate((event?: GestureEvent) => {
            let offsetX = this.preOffsetX + (event?.offsetX || 0)
            let offsetY = this.preOffsetY + (event?.offsetY || 0)
            if (((this.imageWidth * this.geometryScale - this.viewWidth) / 2 - Math.abs(vp2px(offsetX))) <= 0) {
              if (!this.pinching) {
                this.dire = offsetX < 0 ? Direction.Right : Direction.Left
              }
              return;
            }
            this.goNext = false
            this.geometryOffsetX = offsetX
            this.geometryOffsetY = offsetY
          })
          .onActionEnd((event?: GestureEvent) => {
            if ((this.dire !== Direction.None)) {
              if (this.goNext) {
                this.onNeedGoNext(this.dire)
                this.reset()
              }
              this.goNext = true
            }
            this.preOffsetX = this.geometryOffsetX
            this.preOffsetY = this.geometryOffsetY
          }),
      )
    )
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.
  • 153.
  • 154.
  • 155.
  • 156.
  • 157.
  • 158.
  • 159.
  • 160.
  • 161.
  • 162.
  • 163.
  • 164.
  • 165.
  • 166.
  • 167.
  • 168.
  • 169.
  • 170.
  • 171.
  • 172.
  • 173.
  • 174.
  • 175.
  • 176.
  • 177.
  • 178.
  • 179.
  • 180.
  • 181.
  • 182.
  • 183.
  • 184.
  • 185.
  • 186.
  • 187.
  • 188.
分享
微博
QQ
微信
回复
2025-01-09 17:49:03
相关问题
HarmonyOS 点击图片放大缩小
839浏览 • 1回复 待解决
如何保存http网络图片本地
985浏览 • 1回复 待解决
HarmonyOS Image组件网络图片不显示
1430浏览 • 1回复 待解决
Image组件如何加载网络图片
3637浏览 • 1回复 待解决
HarmonyOS Image组件网络图片缓存
1068浏览 • 1回复 待解决
HarmonyOS Image组件无法显示网络图片
2342浏览 • 1回复 待解决
HarmonyOS 请求网络图片
1143浏览 • 1回复 待解决
HarmonyOS 组件放大缩小demo
684浏览 • 1回复 待解决
HarmonyOS 获取网络图片高度
636浏览 • 1回复 待解决
HarmonyOS Image加载网络图片
737浏览 • 1回复 待解决
HarmonyOS 网络图片加载控件
755浏览 • 1回复 待解决
HarmonyOS 相机预览是否支持放大缩小
673浏览 • 1回复 待解决
Swiper轮播放大缩小动效实践
2401浏览 • 1回复 待解决
HarmonyOS 如何压缩本地图片
814浏览 • 1回复 待解决