在HarmonyOS NEXT开发中滑动下一页效果应该如何做?

在HarmonyOS NEXT开发中滑动下一页效果应该如何做?

阅读 592
avatarAI BotBETA

在HarmonyOS NEXT开发中,要实现滑动下一页效果,你可以使用PageSlider组件。这是一个专门用于页面切换的组件,支持左右滑动切换页面。以下是一个简单的示例代码,展示了如何使用PageSlider来实现滑动下一页的效果:

### 示例代码

**XML布局文件(例如:`ability_main.xml`)**

<DirectionalLayout

xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:width="match_parent"
ohos:height="match_parent"
ohos:orientation="vertical">

<PageSlider
    ohos:id="$+id:page_slider"
    ohos:width="match_parent"
    ohos:height="match_parent"
    ohos:page_count="3"  <!-- 设置页面总数 -->
    ohos:orientation="horizontal"/>

</DirectionalLayout>


**Java代码(例如:`MainAbilitySlice.java`)**

package com.example.myapplication.slice;

import ohos.aafwk.ability.AbilitySlice;
import ohos.agp.components.Component;
import ohos.agp.components.PageSlider;
import ohos.agp.components.Text;

public class MainAbilitySlice extends AbilitySlice {

@Override
public void onStart(Intent intent) {
    super.onStart(intent);
    super.setUIContent(ResourceTable.Layout_ability_main);

    PageSlider pageSlider = (PageSlider) findComponentById(ResourceTable.Id_page_slider);

    // 动态添加页面内容
    for (int i = 0; i < 3; i++) {
        DirectionalLayout layout = new DirectionalLayout(this);
        layout.setLayoutConfig(
            new Component.LayoutConfig(
                Component.LayoutConfig.MATCH_PARENT,
                Component.LayoutConfig.MATCH_PARENT
            )
        );
        layout.setOrientation(Component.VERTICAL);

        Text text = new Text(this);
        text.setText("Page " + (i + 1));
        text.setTextSize(50);
        layout.addComponent(text);

        pageSlider.addPage(layout);
    }
}

@Override
public void onActive() {
    super.onActive();
}

@Override
public void onInactive() {
    super.onInactive();
}

}


### 解释

1. **XML布局文件**:
   - 使用`DirectionalLayout`作为根布局。
   - `PageSlider`组件用于实现页面滑动效果,通过`ohos:page_count`属性设置总页数,`ohos:orientation`属性设置滑动方向(水平或垂直)。

2. **Java代码**:
   - 在`MainAbilitySlice`的`onStart`方法中,通过`findComponentById`获取`PageSlider`组件。
   - 动态创建页面内容(例如:`DirectionalLayout`和`Text`),并将其添加到`PageSlider`中。
1 个回答

参考代码:

@Entry 
@Component 
struct NovelPage { 
  @Provide('fontSize') @Watch('onFontSizeChange') fontSize: number = Constants.INIT_FONT_SIZE; 
  @Provide('bgColorIndex') @Watch('onBgColorChanged') bgColorIndex: BGColorType = BGColorType.WHITE; 
  @Provide('bgColor') bgColor: string = BG_COLOR_ARRAY[BGColorType.WHITE]; 
  @Provide('offsetX') offsetX: number = 0 
  @Provide('offsetY') offsetY: number = 0; 
  @Provide('screenH') screenH: number = 0; 
  @Provide('screenW') screenW: number = 0; 
  @Provide('sumRow') sumRow: number = 0; 
  @Provide('rowWord') rowWord: number = 0; 
  @Provide('rotateAngleOne') rotateAngleOne: number = Constants.INIT_ROTATE_ANGLE_ONE; 
  @Provide('rotateAngleTwo') rotateAngleTwo: number = 0.0; 
  @Provide('curPosition') curPosition: number = 0; 
  @Provide('turnStyle') turnStyle: FlipPageType = FlipPageType.SLIDE_FLIP_PAGE; 
  @Provide('currentPageNum') @Watch('onFlush') currentPageNum: number = 1; 
  @Provide('pageWordSum') pageWordSum: number = 0; 
  @Provide('light') light: number = Constants.INIT_SCREEN_LIGHT; 
  @Provide('isSystemLight') isSystemLight: boolean = false; 
  @Provide('rowGap') rowGap: number = Constants.INIT_ROW_GAP; 
  @State currentStartIndex: number = 0; 
  @State isShow: boolean = false; 
  @State isFontChanged: boolean = false; 
 
  aboutToAppear(): void { 
    this.screenW = px2vp(display.getDefaultDisplaySync().width); 
    this.screenH = px2vp(display.getDefaultDisplaySync().height - (AppStorage.get('avoidHeight') as number)); 
    this.sumRow = Math.floor((this.screenH) / (this.fontSize + this.rowGap)); 
    this.rowWord = Math.floor((this.screenW - Constants.SCREEN_MARGIN_LEFT * 2) / this.fontSize); 
    this.simulatePageContent(); 
    this.changeSystemBarStatue(); 
  } 
 
  onFontSizeChange() { 
    this.sumRow = Math.floor((this.screenH) / (this.fontSize + this.rowGap)); 
    this.rowWord = Math.floor((this.screenW - Constants.SCREEN_MARGIN_LEFT * 2) / this.fontSize); 
    let pageWordSum = this.sumRow * this.rowWord; 
 
    if (this.currentStartIndex > pageWordSum) { 
      this.currentPageNum = Math.floor(this.currentStartIndex / (pageWordSum)) + 
        (this.currentStartIndex > 1 && this.currentStartIndex % pageWordSum > 0 ? 2 : 1); 
    } else if (this.currentStartIndex > 0) { 
      this.currentPageNum = 2; 
    } else { 
      Logger.info('currentStartIndex = ' + this.currentStartIndex); 
    } 
    this.isFontChanged = true; 
    this.simulatePageContent(); 
  } 
 
  changeSystemBarStatue(): void { 
    window.getLastWindow(getContext(this), (err, data) => { 
      const errCode = err.code; 
      if (errCode) { 
        return; 
      } 
      let SystemBarProperties: window.SystemBarProperties = { 
        statusBarColor: BG_COLOR_ARRAY[this.bgColorIndex], 
        navigationBarColor: BG_COLOR_ARRAY[this.bgColorIndex], 
        navigationBarContentColor: Constants.TRANSPARENT 
      }; 
      try { 
        data.setWindowSystemBarProperties(SystemBarProperties, (err: BusinessError) => { 
          const errCode: number = err.code; 
          if (errCode) { 
            Logger.error('Failed to set the system bar properties. Cause: ' + JSON.stringify(err)); 
            return; 
          } 
          data.setWindowBackgroundColor(BG_COLOR_ARRAY[this.bgColorIndex]); 
        }); 
      } catch (exception) { 
        Logger.error('Failed to set the system bar properties. Cause: ' + JSON.stringify(exception)); 
      } 
    }); 
  } 
 
  onBgColorChanged() { 
    this.changeSystemBarStatue(); 
  } 
 
  onFlush() { 
    Logger.info('currentPageNum=' + this.currentPageNum + ', isFontChanged=' + this.isFontChanged); 
    if (this.isFontChanged && this.currentPageNum === 1) { 
      this.isFontChanged = false; 
      this.currentStartIndex = 0; 
    } 
  } 
 
  simulatePageContent() { 
    this.offsetY = 0; 
    this.rotateAngleTwo = 0.0; 
    this.rotateAngleOne = Constants.INIT_ROTATE_ANGLE_ONE; 
  } 
 
  private clickAnimateTo(isLeft: Boolean) { 
    if (this.turnStyle === FlipPageType.SLIDE_FLIP_PAGE) { 
      animateTo({ 
        duration: Constants.SLIDE_DURATION, 
        curve: Curve.EaseOut, 
        onFinish: () => { 
          if (this.offsetX > 0) { 
            this.currentPageNum > 0 ? this.currentPageNum - 1 : this.currentPageNum; 
            this.currentStartIndex -= this.sumRow * this.rowWord; 
          } 
          if (this.offsetX < 0) { 
            this.currentPageNum += 1; 
            this.currentStartIndex += this.sumRow * this.rowWord; 
          } 
          Logger.info(this.currentStartIndex.toString()); 
          this.offsetX = 0; 
          this.simulatePageContent(); 
        } 
      }, () => { 
        if (isLeft) { 
          this.offsetX = this.screenW; 
        } else { 
          this.offsetX = -this.screenW; 
        } 
      }) 
    } 
  } 
 
  build() { 
    Row() { 
 
      if (this.turnStyle === FlipPageType.SLIDE_FLIP_PAGE) { 
        SlideFlipView({ 
          currentStartIndex: this.currentStartIndex 
        }) 
      } 
 
    } 
 
    .width(Constants.FULL_PERCENT) 
    .height(Constants.FULL_PERCENT) 
    .bindSheet( 
      $$this.isShow, 
      this.myBuilder(), 
      { 
        height: SheetSize.FIT_CONTENT, 
        detents: [Constants.SHEET_HEIGHT, Constants.SHEET_HEIGHT + 1], 
        showClose: true, 
        dragBar: true, 
        title: { title: Constants.SHEET_TITLE }, 
        backgroundColor: Constants.SHEET_BACKGROUND_COLOR 
      } 
    ) 
    .backgroundColor(this.bgColor) 
  } 
 
  @Builder 
  myBuilder() { 
 
 
  } 
} 
 
@Component 
export default struct Reader { 
  @Consume('bgColor') @Watch('onPageChange') bgColor: string; 
  @Consume('fontSize') @Watch('onPageChange') fontSize: number; 
  @Consume('turnStyle') turnStyle: FlipPageType; 
  @Consume('screenW') screenW: number; 
  @Consume('screenH') screenH: number; 
  @Consume('rowGap') rowGap: number; 
  @Consume('sumRow') sumRow: number 
  @Consume('rowWord') rowWord: number; 
  @Prop @Watch('onPageChange') startIndex: number = 0; 
  private settings: RenderingContextSettings = new RenderingContextSettings(true); 
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings); 
  private wordWidth: number = 0; 
  private wordHeight: number = 0; 
 
  aboutToAppear(): void { 
    this.drawText(this.startIndex); 
  } 
 
  onPageChange() { 
    this.drawText(this.startIndex); 
  } 
 
  drawText(startIndex: number) { 
    this.wordWidth = this.fontSize; 
    this.wordHeight = this.fontSize; 
    this.context.fillStyle = this.bgColor; 
    this.context.fillRect(0, 0, this.screenW, this.screenH); 
    this.context.fillStyle = Color.Black; 
    this.context.font = vp2px(this.fontSize) + Constants.CANVAS_FONT_SET; 
    if (startIndex < 0) { 
      startIndex = 0; 
    } 
 
    let gap = ((this.screenW - Constants.SCREEN_MARGIN_LEFT * 2) - this.wordWidth * this.rowWord) / (this.rowWord - 1); 
    let realRowGap = (this.screenH - this.sumRow * (this.wordHeight + this.rowGap)) / (this.sumRow - 1); 
    let currentX = Constants.SCREEN_MARGIN_LEFT; 
    let currentY = this.wordHeight; 
    for (let i = startIndex;; i++) { 
      if (currentX + this.wordWidth > this.screenW - (Constants.SCREEN_MARGIN_LEFT - 1)) { 
        currentX = Constants.SCREEN_MARGIN_LEFT; 
        currentY = currentY + this.rowGap + this.wordHeight + realRowGap; 
        if (currentY > this.screenH) { 
          break; 
        } 
      } 
      this.context.fillText(Constants.TEXT.charAt(i % Constants.TEXT.length), currentX, currentY); 
      currentX += this.wordWidth + gap; 
    } 
  } 
 
  build() { 
    Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Start, justifyContent: FlexAlign.Start }) { 
      Column() { 
        Canvas(this.context) 
          .width(Constants.FULL_PERCENT) 
          .height(Constants.FULL_PERCENT) 
          .onReady(() => { 
            this.drawText(this.startIndex); 
          }) 
      } 
      .width(Constants.FULL_PERCENT) 
    } 
    .height(Constants.FULL_PERCENT) 
  } 
} 
 
@Component 
export struct SlideFlipView { 
  @Consume('offsetX') offsetX: number; 
  @Consume('sumRow') sumRow: number; 
  @Consume('rowWord') rowWord: number; 
  @Consume('screenW') screenW: number; 
  @Consume('currentPageNum') currentPageNum: number; 
  @Link currentStartIndex: number; 
  private isFirst: boolean = false; 
 
  build() { 
    Stack() { 
      Reader({ startIndex: this.currentStartIndex + this.sumRow * this.rowWord }) 
        .translate({ x: this.offsetX >= 0 ? this.screenW : this.screenW + this.offsetX, y: 0, z: 0 }) 
 
      Reader({ startIndex: this.currentStartIndex }) 
        .translate({ x: this.offsetX, y: 0, z: 0 }) 
        .width(this.screenW) 
 
      Reader({ startIndex: this.currentStartIndex - this.sumRow * this.rowWord }) 
        .translate({ x: this.offsetX >= 0 ? -this.screenW + this.offsetX : -this.screenW, y: 0, z: 0 }) 
    } 
    .gesture( 
      PanGesture() 
        .onActionUpdate((event?: GestureEvent) => { 
          if (!event) { 
            return; 
          } 
          if (this.currentPageNum <= 1 && event.offsetX > 0) { 
            this.isFirst = true; 
            return; 
          } 
 
          this.offsetX = event.offsetX; 
        }) 
        .onActionEnd(() => { 
          animateTo({ 
            duration: Constants.FLIP_DURATION, 
            curve: Curve.EaseOut, 
            onFinish: () => { 
              if (this.offsetX > 0) { 
                this.currentPageNum -= 1; 
                if (this.currentStartIndex !== 0) { 
                  this.currentStartIndex -= this.sumRow * this.rowWord; 
                } 
              } 
              if (this.offsetX < 0) { 
                this.currentPageNum += 1; 
                this.currentStartIndex += this.sumRow * this.rowWord; 
              } 
              if (this.isFirst) { 
                promptAction.showToast({ 
                  message: Constants.MSG_FLIP_OVER, 
                  duration: Constants.PROMPT_DURATION 
                }); 
                this.isFirst = false; 
              } 
              this.offsetX = 0; 
            } 
          }, () => { 
            if (this.offsetX > 0) { 
              this.offsetX = this.screenW; 
            } 
            if (this.offsetX < 0) { 
              this.offsetX = -this.screenW; 
            } 
          }) 
        }) 
    ) 
  } 
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进