实现阅读器翻页效果鸿蒙示例代码 原创

鸿蒙场景化示例代码技术工程师
发布于 2025-2-27 11:19
浏览
0收藏

本文原创发布在华为开发者社区

介绍

本示例基于显式动画、List组件、drawing接口实现了阅读器上下翻页、左右覆盖翻页以及仿真翻页效果。

实现阅读器翻页效果源码地址

效果预览

实现阅读器翻页效果鸿蒙示例代码-鸿蒙开发者社区

使用说明

  1. 进入应用默认为仿真翻页,长按屏幕并滑动可实现翻页效果,点击屏幕中部区域,弹出翻页方式选择栏。
  2. 选择上下翻页,显示上下翻页页面,支持上下滑动翻页。
  3. 选择覆盖翻页,显示覆盖翻页页面。支持左右滑动翻页,以及点击屏幕左右侧后滑动翻页。

实现思路

上下翻页效果

使用List组件实现上下滑动效果,通过添加点击事件,点击屏幕,底部会出现翻页方式选择栏。核心代码如下:

Column() {
      List({ initialIndex: this.currentPageNum - Constants.PAGE_FLIP_PAGE_COUNT }) {
        LazyForEach(this.data, (item: string) => {
          ListItem() {
            Text($r(item))
            ···
          }
        }, (item: string, index: number) => index + JSON.stringify(item))
      }
      .width($r('app.string.pageflip_bottomview_row_text_width'))
      .height($r('app.string.page_flip_full_size'))
      .scrollBar(BarState.Off)
      .cachedCount(Constants.PAGE_FLIP_CACHE_COUNT)
      .onScrollIndex((firstIndex: number) => {
        this.currentPageNum = firstIndex + Constants.PAGE_FLIP_PAGE_COUNT;
      })
    }
    .width($r('app.string.page_flip_full_size'))
    .backgroundColor($r("app.color.page_flip_background_color"))
    .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
    .onClick((event?: ClickEvent) => {
      if (event) {
        if (this.isMenuViewVisible) {
          this.isMenuViewVisible = false;
        } else {
          this.isMenuViewVisible = true;
        }
      }
    })
  • 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.

覆盖翻页效果

使用显式动画animateTo和堆叠容器Stack实现页面覆盖效果,通过触发滑动手势事件PanGesture,左右滑动屏幕或点击屏幕左侧右侧可进行翻页。animateTo中涉及的参数:

  1. duration:动画执行的时长,单位毫秒,项目中固定为300ms。
  2. curve:插值曲线,此处用了EaseOut,表示动画逐渐减速以低速结束。

核心代码如下:

private clickAnimateTo(isClick: boolean, isLeft?: boolean) {
    animateTo({
      duration: Constants.PAGE_FLIP_TO_AST_DURATION,
      curve: Curve.EaseOut,
      onFinish: () => {
        if (this.offsetX > Constants.PAGE_FLIP_RIGHT_FLIP_OFFSETX &&
          this.currentPageNum !== Constants.PAGE_FLIP_PAGE_START) {
          this.currentPageNum -= Constants.PAGE_FLIP_PAGE_COUNT;
        } else if (this.offsetX < Constants.PAGE_FLIP_LEFT_FLIP_OFFSETX &&
          this.currentPageNum !== Constants.PAGE_FLIP_PAGE_END) {
          this.currentPageNum += Constants.PAGE_FLIP_PAGE_COUNT;
        }
        this.offsetX = Constants.PAGE_FLIP_ZERO;
        this.simulatePageContent();
      }
    }, () => {
      if (isClick) {
        if (isLeft) {
          this.offsetX = this.screenW;
        } else {
          this.offsetX = -this.screenW;
        }
      } else {
        if (this.offsetX > Constants.PAGE_FLIP_RIGHT_FLIP_OFFSETX &&
          this.currentPageNum !== Constants.PAGE_FLIP_PAGE_START) {
          this.offsetX = this.screenW;
        } else if (this.offsetX < Constants.PAGE_FLIP_LEFT_FLIP_OFFSETX &&
          this.currentPageNum !== Constants.PAGE_FLIP_PAGE_END) {
          this.offsetX = -this.screenW;
        } else {
          this.offsetX = Constants.PAGE_FLIP_ZERO;
        }
      }
    });
  }
  • 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.

仿真翻页效果

使用@ohos.graphics.drawing接口及NodeContainer组件,实现仿真翻页效果的绘制。根据手指滑动触摸位置,计算仿真页的边缘节点,填充区域后实现。核心代码如下:

NodeContainer(this.myNodeController)
          .onAppear(() => {
            AppStorage.setOrCreate('colorFlag', true);
            this.newRectNode();
          })
          .width(px2vp(this.windowWidth))
          .height(px2vp(this.windowHeight))
          .gesture(
            PanGesture()
              .onActionUpdate((event: GestureEvent) => {
                AppStorage.setOrCreate('drawState', DrawState.DS_MOVING);
                clearInterval(this.timeID);
                for (let i = 0; i < event.fingerList.length; i++) {
                  if (event.fingerList[i] == undefined ||
                    event.fingerList[i].localX < 0 ||
                    event.fingerList[i].localY < 0 ||
                    event.fingerList[i].localX > px2vp(this.windowWidth) ||
                    event.fingerList[i].localY > px2vp(this.windowHeight)) {
                    return;
                  }
                  ···
                  this.newRectNode();
                }
              })
              .onActionEnd(() => {
                  ···
              })
          )
  • 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.

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
分类
已于2025-2-28 14:48:59修改
收藏
回复
举报
回复
    相关推荐