【每日学点鸿蒙知识】路由打开半屏、自定义Grid、手势等

发布于:2025-02-11 ⋅ 阅读:(64) ⋅ 点赞:(0)

1、如何通过路由的方式打开半屏?

统一使用组件导航(Navigation)的形式去操作,文章里面参考页面显示类型NavDestinationMode.DIALOG:组件导航

2、有没有Grid onItemDragStart时间设置替代方案、以及多列Grid Item实现通用示例?

Grid设置拖动时onItemDragStart默认时间是170毫秒,目前无法设置onItemDragStart的时间,可以通过自定义Grid,设置长按手势LongPressGesture中的duration时长,来实现控制GridItem拖拽的长按触发时间功能。

import { curves } from '@kit.ArkUI';

@Entry
@Component
struct Page {
  // 元素数组
  @State numbers: number[] = []
  // row 设置网格列数
  private str: string = ''
  @State row: number = 4
  // 元素数组中最后一个元素的索引
  @State lastIndex: number = 0;
  @State dragItem: number = -1
  @State scaleItem: number = -1
  @State item: number = -1
  private dragRefOffsetx: number = 0
  private dragRefOffsety: number = 0
  @State offsetX: number = 0
  @State offsetY: number = 0
  private FIX_VP_X: number = 108
  private FIX_VP_Y: number = 120

  aboutToAppear() {
    for (let i = 1; i <= 110; i++) {
      this.numbers.push(i)
    }
    this.lastIndex = this.numbers.length - 1

    // 多列
    for (let i = 0; i < this.row; i++) {
      this.str = this.str + '1fr '
    }
  }

  itemMove(index: number, newIndex: number): void {
    if (!this.isDraggable(newIndex)) {
      return
    }
    let tmp = this.numbers.splice(index, 1)
    this.numbers.splice(newIndex, 0, tmp[0])
  }

  // 向下滑
  down(index: number): void {
    // 指定固定GridItem不响应事件
    if (!this.isDraggable(index + this.row)) {
      return
    }
    this.offsetY -= this.FIX_VP_Y
    this.dragRefOffsety += this.FIX_VP_Y
    // 多列
    this.itemMove(index, index + this.row)
  }

  // 向下滑(右下角为空)
  down2(index: number): void {
    if (!this.isDraggable(index + 3)) {
      return
    }
    this.offsetY -= this.FIX_VP_Y
    this.dragRefOffsety += this.FIX_VP_Y
    this.itemMove(index, index + 3)
  }

  // 向上滑
  up(index: number): void {
    if (!this.isDraggable(index - this.row)) {
      return
    }
    this.offsetY += this.FIX_VP_Y
    this.dragRefOffsety -= this.FIX_VP_Y
    this.itemMove(index, index - this.row)
  }

  // 向左滑
  left(index: number): void {
    if (!this.isDraggable(index - 1)) {
      return
    }
    this.offsetX += this.FIX_VP_X
    this.dragRefOffsetx -= this.FIX_VP_X
    this.itemMove(index, index - 1)
  }

  // 向右滑
  right(index: number): void {
    if (!this.isDraggable(index + 1)) {
      return
    }
    this.offsetX -= this.FIX_VP_X
    this.dragRefOffsetx += this.FIX_VP_X
    this.itemMove(index, index + 1)
  }

  // 向右下滑
  lowerRight(index: number): void {
    if (!this.isDraggable(index + this.row + 1)) {
      return
    }
    this.offsetX -= this.FIX_VP_X
    this.dragRefOffsetx += this.FIX_VP_X
    this.offsetY -= this.FIX_VP_Y
    this.dragRefOffsety += this.FIX_VP_Y
    this.itemMove(index, index + this.row + 1)
  }

  // 向右上滑
  upperRight(index: number): void {
    if (!this.isDraggable(index - (this.row - 1))) {
      return
    }
    this.offsetX -= this.FIX_VP_X
    this.dragRefOffsetx += this.FIX_VP_X
    this.offsetY += this.FIX_VP_Y
    this.dragRefOffsety -= this.FIX_VP_Y
    this.itemMove(index, index - (this.row - 1))
  }

  // 向左下滑
  lowerLeft(index: number): void {
    if (!this.isDraggable(index + (this.row - 1))) {
      return
    }
    this.offsetX += this.FIX_VP_X
    this.dragRefOffsetx -= this.FIX_VP_X
    this.offsetY -= this.FIX_VP_Y
    this.dragRefOffsety += this.FIX_VP_Y
    this.itemMove(index, index + (this.row - 1))
  }

  // 向左上滑
  upperLeft(index: number): void {
    if (!this.isDraggable(index - (this.row + 1))) {
      return
    }
    this.offsetX += this.FIX_VP_X
    this.dragRefOffsetx -= this.FIX_VP_X
    this.offsetY += this.FIX_VP_Y
    this.dragRefOffsety -= this.FIX_VP_Y
    this.itemMove(index, index - (this.row + 1))
  }

  // 通过元素的索引,控制对应元素是否能移动排序
  isDraggable(index: number): boolean {
    return index > -1 //恒成立,所有元素均可移动排序
    //return index > 1 //一号二号元素固定,不可移动排序
  }

  build() {
    Column() {
      Grid() {
        ForEach(this.numbers, (item: number) => {
          GridItem() {
            Text(item + '')
              .fontSize(16)
              .width('100%')
              .textAlign(TextAlign.Center)
              .height(100)
              .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 })
          }
          .onAreaChange((oldVal, newVal) => {
            // 多列
            this.FIX_VP_X = Math.round(newVal.width as number)
            this.FIX_VP_Y = Math.round(newVal.height as number)
          })
          // 指定固定GridItem不响应事件
          .hitTestBehavior(this.isDraggable(this.numbers.indexOf(item)) ? HitTestMode.Default : HitTestMode.None)
          .scale({ x: this.scaleItem == item ? 1.05 : 1, y: this.scaleItem == item ? 1.05 : 1 })
          .zIndex(this.dragItem == item ? 1 : 0)
          .translate(this.dragItem == item ? { x: this.offsetX, y: this.offsetY } : { x: 0, y: 0 })
          .padding(10)
          .gesture(
            // 以下组合手势为顺序识别,当长按手势事件未正常触发时则不会触发拖动手势事件
            GestureGroup(GestureMode.Sequence,
              LongPressGesture({ repeat: true, duration: 50 })//控制触发拖动的长按事件的时间,默认500毫秒,设置小于0为默认值,这里设置为50毫秒
                .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.dragRefOffsetx = 0
                  this.dragRefOffsety = 0
                })
                .onActionUpdate((event: GestureEvent) => {
                  this.offsetY = event.offsetY - this.dragRefOffsety
                  this.offsetX = event.offsetX - this.dragRefOffsetx

                  animateTo({ curve: curves.interpolatingSpring(0, 1, 400, 38) }, () => {
                    let index = this.numbers.indexOf(this.dragItem)
                    //  44  宽度一半  减间距
                    if (this.offsetY >= this.FIX_VP_Y / 2 &&
                      (this.offsetX <= this.FIX_VP_X / 2 && this.offsetX >= -this.FIX_VP_X / 2)
                      && (index + this.row <= this.lastIndex)) {
                      // 向下滑
                      this.down(index)
                    } else if (this.offsetY <= -this.FIX_VP_Y / 2 &&
                      (this.offsetX <= this.FIX_VP_X / 2 && this.offsetX >= -this.FIX_VP_X / 2)
                      && index - this.row >= 0) {
                      // 向上滑
                      this.up(index)
                    } else if (this.offsetX >= this.FIX_VP_X / 2 &&
                      (this.offsetY <= this.FIX_VP_Y / 2 && this.offsetY >= -this.FIX_VP_Y / 2)
                      && !(((index - (this.row - 1)) % this.row == 0) || index == this.lastIndex)) {
                      // ) {
                      // 向右滑
                      this.right(index)
                    } else if (this.offsetX <= -this.FIX_VP_X / 2 &&
                      (this.offsetY <= this.FIX_VP_Y / 2 && this.offsetY >= -this.FIX_VP_Y / 2)
                      && !(index % this.row == 0)) {
                      // 向左滑
                      this.left(index)
                    } else if (this.offsetX >= this.FIX_VP_X / 2 && this.offsetY >= this.FIX_VP_Y / 2
                      && ((index + this.row + 1 <= this.lastIndex && !((index - (this.row - 1)) % this.row == 0)) ||
                        !((index - (this.row - 1)) % this.row == 0))) {
                      // 向右下滑
                      this.lowerRight(index)
                    } else if (this.offsetX >= this.FIX_VP_X / 2 && this.offsetY <= -this.FIX_VP_Y / 2
                      && !((index - this.row < 0) || ((index - (this.row - 1)) % this.row == 0))) {
                      // 向右上滑
                      this.upperRight(index)
                    } else if (this.offsetX <= -this.FIX_VP_X / 2 && this.offsetY >= this.FIX_VP_Y / 2
                      && (!(index % this.row == 0) && (index + (this.row - 1) <= this.lastIndex))) {
                      // 向左下滑
                      this.lowerLeft(index)
                    } else if (this.offsetX <= -this.FIX_VP_X / 2 && this.offsetY <= -this.FIX_VP_Y / 2
                      && !((index <= this.row - 1) || (index % this.row == 0))) {
                      // 向左上滑
                      this.upperLeft(index)
                    } else if (this.offsetX >= this.FIX_VP_X / 2 && this.offsetY >= this.FIX_VP_Y / 2
                      && (index == this.lastIndex)) {
                      // 向右下滑(右下角为空)
                      this.down2(index)
                    }
                  })
                })
                .onActionEnd(() => {
                  animateTo({ curve: curves.interpolatingSpring(0, 1, 400, 38) }, () => {
                    this.dragItem = -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
                })
                animateTo({
                  curve: curves.interpolatingSpring(14, 1, 170, 17)
                }, () => {
                  this.scaleItem = -1
                })
              })
          )
        }, (item: number) => item.toString())
      }
      .width('90%')
      .editMode(true)
      .scrollBar(BarState.Off)
      // 多列
      .columnsTemplate(this.str)
    }.width('100%').height('100%').backgroundColor('#0D182431').padding({ top: 5 })
  }
}

3、list、scroll、swipper、web等嵌套使用时存在滑动冲突问题。例如在List中嵌套一个横向滑动的swipe,swipe嵌套一个web,设置手势优先时,web无法和list进行联动交互。

问题原因可能是List组件嵌套Web组件产生了滑动冲突,这里可以使用触摸测试控制来规避此种情况

参考文档:多层级手势事件

4、如何禁止自定义弹窗点击空白处关闭功能?

设置自定义弹框的autoCancel为false,禁止点击空白处关闭弹框。
参考文档:@ohos.promptAction (弹窗)

5、基础手势单击和双击,如何只识别双击而不识别单击?

使用组合手势GestureGroup的互斥识别模式。双击事件需放在单击事件前面,互斥识别是按排列顺序来识别,如果单击事件放前面则只会识别到单击事件。参考文档:组合手势

@Entry
@Component
struct TapGestureExample {
  build() {
    Column() {
      Text('Click twice').fontSize(28)
        .gesture(GestureGroup(GestureMode.Exclusive,
          // 注意双击放在前面
          TapGesture({ count: 2 })
            .onAction((event?: GestureEvent) => {
              console.log('TapGesture 2')
            }),
          TapGesture({ count: 1 })
            .onAction((event?: GestureEvent) => {
              console.log('TapGesture 1')
            })
        )
        )
    }
  }
}

网站公告

今日签到

点亮在社区的每一天
去签到