Zum Inhalt springen

Drag to Adjust List Order, Tab Rebound, Custom Pop-up This, State Variable Modifier Enumeration

[Daily HarmonyOS Next Knowledge] Drag to Adjust List Order, Tab Rebound, Custom Pop-up This, State Variable Modifier Enumeration

1. HarmonyOS function implementation (drag to adjust list order)?

Refer to:

import curves from '@ohos.curves';
import Curves from '@ohos.curves'

@Entry
@Component
struct ListItemExample {
  @State private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
  @State dragItem: number = -1
  @State scaleItem: number = -1
  @State neighborItem: number = -1
  @State neighborScale: number = -1
  private dragRefOffset: number = 0
  @State offsetX: number = 0
  @State offsetY: number = 0
  private ITEM_INTV: number = 120
  scaleSelect(item: number): number {
    if (this.scaleItem == item) {
      return 1.05
    } else if (this.neighborItem == item) {
      return this.neighborScale
    } else {
      return 1
    }
  }
  itemMove(index: number, newIndex: number): void {
    let tmp = this.arr.splice(index, 1)
    this.arr.splice(newIndex, 0, tmp[0])
  }
  build() {
    Stack() {
      List({ space: 20, initialIndex: 0 }) {
        ForEach(this.arr, (item: number) => {
          ListItem() {
            Text('' + item)
              .width('100%')
              .height(100)
              .fontSize(16)
              .textAlign(TextAlign.Center)
              .borderRadius(10)
              .backgroundColor(0xFFFFFF)
              .shadow(this.scaleItem == item ? { radius: 70, color: '#15000000', offsetX: 0, offsetY: 0 } :
                { radius: 0, color: '#15000000', offsetX: 0, offsetY: 0 })
              .animation({ curve: Curve.Sharp, duration: 300 })
          }
          .margin({ left: 12, right: 12 })
          .scale({ x: this.scaleSelect(item), y: this.scaleSelect(item) })
          .zIndex(this.dragItem == item ? 1 : 0)
          .translate(this.dragItem == item ? { y: this.offsetY } : { y: 0 })
          .gesture(
            // The following combined gestures are recognized in sequence; drag gestures will not be triggered if long-press gestures do not fire normally
            GestureGroup(GestureMode.Sequence,
              LongPressGesture({ repeat: true })
                .onAction((event?: GestureEvent) => {
                  animateTo({ curve: Curve.Friction, duration: 300 }, () => {
                    this.scaleItem = item
                  })
                })
                .onActionEnd(() => {
                  animateTo({ curve: Curve.Friction, duration: 300 }, () => {
                    this.scaleItem = -1
                  })
                }),
              PanGesture({ fingers: 1, direction: null, distance: 0 })
                .onActionStart(() => {
                  this.dragItem = item
                  this.dragRefOffset = 0
                })
                .onActionUpdate((event: GestureEvent) => {
                  this.offsetY = event.offsetY - this.dragRefOffset
                  // console.log('Y:' + this.offsetY.toString())
                  this.neighborItem = -1
                  let index = this.arr.indexOf(item)
                  let curveValue = Curves.initCurve(Curve.Sharp)
                  let value: number = 0
                  // Calculate scaling of adjacent items based on displacement
                  if (this.offsetY < 0) {
                    value = curveValue.interpolate(-this.offsetY / this.ITEM_INTV)
                    this.neighborItem = this.arr[index-1]
                    this.neighborScale = 1 - value / 20;
                    console.log('neighborScale:' + this.neighborScale.toString())
                  } else if (this.offsetY > 0) {
                    value = curveValue.interpolate(this.offsetY / this.ITEM_INTV)
                    this.neighborItem = this.arr[index+1]
                    this.neighborScale = 1 - value / 20;
                  }
                  // Swap order based on displacement
                  if (this.offsetY > this.ITEM_INTV / 2) {
                    animateTo({ curve: curves.interpolatingSpring(0, 1, 400, 38) }, () => {
                      this.offsetY -= this.ITEM_INTV
                      this.dragRefOffset += this.ITEM_INTV
                      this.itemMove(index, index + 1)
                    })
                  } else if (this.offsetY < -this.ITEM_INTV / 2) {
                    animateTo({ curve: curves.interpolatingSpring(0, 1, 400, 38) }, () => {
                      this.offsetY += this.ITEM_INTV
                      this.dragRefOffset -= this.ITEM_INTV
                      this.itemMove(index, index - 1)
                    })
                  }
                })
                .onActionEnd((event: GestureEvent) => {
                  animateTo({ curve: curves.interpolatingSpring(0, 1, 400, 38) }, () => {
                    this.dragItem = -1
                    this.neighborItem = -1
                  })
                  animateTo({
                    curve: curves.interpolatingSpring(14, 1, 170, 17), delay: 150
                  }, () => {
                    this.scaleItem = -1
                  })
                })
            )
              .onCancel(() => {
                animateTo({ curve: curves.interpolatingSpring(0, 1, 400, 38) }, () => {
                  this.dragItem = -1
                  this.neighborItem = -1
                })
                animateTo({
                  curve: curves.interpolatingSpring(14, 1, 170, 17), delay: 150
                }, () => {
                  this.scaleItem = -1
                })
              })
          )
        }, (item: number) => item.toString())
      }
    }.width('100%').height('100%').backgroundColor(0xDCDCDC).padding({ top: 5 })
  }}

2. Can the rebound effect be disabled when the HarmonyOS tab component slides to the last index?

When the tab component slides to the last index, can the rebound effect be disabled?

Restrict edge tab scrolling by adding gestures to TabContent. Reference solution:

  • Add .gesture(PanGesture(new PanGestureOptions({ direction: PanDirection.Right }))) to the leftmost TabContent to restrict built-in right swiping.
  • Add .gesture(PanGesture(new PanGestureOptions({ direction: PanDirection.Left }))) to the rightmost TabContent to restrict built-in left swiping.
    Reference demo:
@Entry
@Component
struct TabsExample {
  private controller: TabsController = new TabsController();

  build() {
    Column() {
      Tabs({ barPosition: BarPosition.Start, controller: this.controller }) {
        TabContent() {
          Column()
            .width('100%')
            .height('100%')
            .backgroundColor(Color.Green)
        }
        .tabBar('green')
        .gesture(PanGesture(new PanGestureOptions({ direction: PanDirection.Right })))

        TabContent() {
          Column()
            .width('100%')
            .height('100%')
            .backgroundColor(Color.Blue)
        }
        .tabBar('blue')
        .gesture(PanGesture(new PanGestureOptions({ direction: PanDirection.Left })))

        // ...

      }
      .barMode(BarMode.Scrollable)
      .barWidth('100%')
      .barHeight(60)
      .width('100%')
      .height('100%')
      .backgroundColor(0xF5F5F5)
    }
  }
}

3. Can a HarmonyOS custom pop-up not be bound to this?

Try making the pop-up global to avoid using this.

Custom pop-ups do not need to be bound to this.

4. Can @State not modify enums in HarmonyOS?

Does @State fail to modify enums? Modifying an enum throws an error:

[nodict][page_router_manager.cpp(LoadPage)-(100000:100000:scope)] Update RootComponent Failed or LoadNamedRouter Failed

In ArkTS, using the declare keyword to modify classes is not supported. This means creating a class with declare in a struct page may cause issues, including @State-modified enum errors, for the following reasons:

  1. declare keyword not supported: ArkTS does not allow defining classes with declare, as this keyword is for declaring variables/types, not defining classes. Using declare to define a class in a struct page causes compilation errors.
  2. @State-modified enum error: The declare-modified class violates ArkTS specifications, triggering compilation errors that affect dependent code, including @State-modified enums.

5. How to implement cross-page loading in HarmonyOS?

Implement via a splash page during page transitions, replacing the splash page with the target page using router.replaceUrl, e.g.:

@Entry
@Component
export struct LoadingPage {
  @Prop flag: boolean;

  build() {
    Row() {
      LoadingProgress().color(Color.White).width(50).height(50)
    }
    .height(this.flag ? '100%' : 0)
    .width('100%')
    .position({ x: 0, y: 0 })
    .backgroundColor('#4D000000')
    .justifyContent(FlexAlign.Center)
  }
}

Refer to replaceUrl documentation: https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-router-V5

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert