ArkUI 组合手势:一个动作不够时,再考虑组合

举报
蓝瘦的蜕变 发表于 2026/10/20 18:01:45 2026/10/20
【摘要】 今天我们用 GestureGroup 做两个轻量例子:顺序组合和并行组合。 组合手势不是越多越专业。它只是告诉系统:这些手势之间到底是先后关系,还是可以一起参与识别。能用一个手势解决,就不要硬组合。 参考文档: https://developer.huawei.com/consumer/cn/doc/harmonyos

ArkUI 组合手势:一个动作不够时,再考虑组合

今天我们用 GestureGroup 做两个轻量例子:顺序组合和并行组合。

组合手势不是越多越专业。它只是告诉系统:这些手势之间到底是先后关系,还是可以一起参与识别。能用一个手势解决,就不要硬组合。

参考文档:

  • https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-interaction-development-guide-overview

Sequence:先后顺序很重要

GestureGroup(
  GestureMode.Sequence,
  LongPressGesture({ repeat: false, duration: 500 }),
  PanGesture({ fingers: 1, distance: 5 })
)

这个例子要求先长按,再拖动。它适合“先激活,再移动”的场景,比如长按后移动一个卡片。

Parallel:两个手势都能参与

GestureGroup(
  GestureMode.Parallel,
  TapGesture({ count: 1 }),
  PanGesture({ fingers: 1, distance: 5 })
)

并行组合适合点击和拖动都可能有效的区域。Demo 里点击会记录一次点击,拖动会记录位移。

先别急着处理冲突

这篇只讲组合思路,不讲父子组件争抢手势,也不讲滚动列表里的拖动冲突。那些问题更接近真实业务,但放在下一轮更合适。

你有没有写过“长按后才能拖动”的交互?如果写过,最容易卡的是手势顺序,还是拖动后的落点处理?

完整示例代码

文件位置:entry/src/main/ets/pages/arkUI/interaction/ArkUICombinedGestureDemo.ets

@Entry
@Component
struct ArkUICombinedGestureDemo {
  @State sequenceText: string = '先长按,再拖动'
  @State parallelText: string = '点击或拖动都可以试试'
  @State sequenceX: number = 0
  @State parallelX: number = 0

  private showTip(message: string): void {
    this.getUIContext().getPromptAction().showToast({
      message: message,
      duration: 1200,
      bottom: 120
    })
  }

  @Builder
  sectionTitle(title: string, desc: string) {
    Column({ space: 6 }) {
      Text(title)
        .fontSize(19)
        .fontWeight(FontWeight.Bold)
        .fontColor('#111827')
      Text(desc)
        .fontSize(13)
        .fontColor('#6B7280')
        .lineHeight(20)
    }
    .width('100%')
    .alignItems(HorizontalAlign.Start)
  }

  @Builder
  gestureBox(title: string, desc: string, color: string) {
    Column({ space: 10 }) {
      Text(title)
        .fontSize(18)
        .fontWeight(FontWeight.Bold)
        .fontColor('#FFFFFF')
      Text(desc)
        .fontSize(13)
        .fontColor('#E5E7EB')
        .lineHeight(20)
    }
    .width('100%')
    .padding(16)
    .borderRadius(14)
    .backgroundColor(color)
    .alignItems(HorizontalAlign.Start)
  }

  build() {
    Scroll() {
      Column({ space: 22 }) {
        Column({ space: 8 }) {
          Text('ArkUI 组合手势')
            .fontSize(28)
            .fontWeight(FontWeight.Bold)
            .fontColor('#111827')
          Text('一个动作不够时,再考虑组合')
            .fontSize(16)
            .fontColor('#4B5563')
          Text('组合手势不是越多越好。只有当一个动作需要前置条件,或者多个动作需要一起识别时,再把它们组合起来。')
            .fontSize(14)
            .fontColor('#6B7280')
            .lineHeight(22)
        }
        .width('100%')
        .alignItems(HorizontalAlign.Start)

        this.sectionTitle('Sequence:先后顺序很重要', '这里要求先长按,再拖动。适合“先激活,再移动”的交互。')
        Column() {
          this.gestureBox('顺序组合', '长按卡片后继续拖动,松手后回到原位。', '#7C3AED')
          Text(this.sequenceText)
            .fontSize(13)
            .fontColor('#FFFFFF')
            .lineHeight(20)
            .padding(10)
            .borderRadius(10)
            .backgroundColor('#00000033')
            .width('100%')
        }
        .width('100%')
        .translate({ x: this.sequenceX, y: 0 })
        .gesture(
          GestureGroup(
            GestureMode.Sequence,
            LongPressGesture({ repeat: false, duration: 500 })
              .onAction(() => {
                this.sequenceText = '长按已激活,现在可以拖动'
                this.showTip('顺序手势已激活')
              }),
            PanGesture({ fingers: 1, distance: 5 })
              .onActionUpdate((event: GestureEvent) => {
                this.sequenceX = event.offsetX
                this.sequenceText = `顺序拖动中:x ${Math.round(event.offsetX)}`
              })
              .onActionEnd(() => {
                this.sequenceX = 0
                this.sequenceText = '顺序组合结束:先长按再拖动'
                this.showTip('顺序组合结束')
              })
          )
        )

        this.sectionTitle('Parallel:两个手势都能参与', '并行组合适合点击和拖动都可能有效的轻量场景。')
        Column() {
          this.gestureBox('并行组合', '点一下会记录点击,拖动会记录位移。', '#0F766E')
          Text(this.parallelText)
            .fontSize(13)
            .fontColor('#FFFFFF')
            .lineHeight(20)
            .padding(10)
            .borderRadius(10)
            .backgroundColor('#00000033')
            .width('100%')
        }
        .width('100%')
        .translate({ x: this.parallelX, y: 0 })
        .gesture(
          GestureGroup(
            GestureMode.Parallel,
            TapGesture({ count: 1 })
              .onAction(() => {
                this.parallelText = '并行组合里触发了一次点击'
                this.showTip('并行点击触发')
              }),
            PanGesture({ fingers: 1, distance: 5 })
              .onActionUpdate((event: GestureEvent) => {
                this.parallelX = event.offsetX
                this.parallelText = `并行拖动中:x ${Math.round(event.offsetX)}`
              })
              .onActionEnd(() => {
                this.parallelX = 0
                this.parallelText = '并行组合里的拖动结束'
                this.showTip('并行拖动结束')
              })
          )
        )

        this.sectionTitle('先克制一点', '这一页只讲组合思路。手势冲突、多层级事件和统一拖拽放到下一轮。')
        Text('如果一个普通点击就能解决,就不要一上来组合三四个手势。组合越多,用户越难猜页面到底想让他做什么。')
          .fontSize(14)
          .fontColor('#4B5563')
          .lineHeight(22)
          .padding(16)
          .borderRadius(14)
          .backgroundColor('#FFFFFF')
          .border({ width: 1, color: '#E5E7EB' })
          .width('100%')
      }
      .width('100%')
      .padding(24)
      .alignItems(HorizontalAlign.Start)
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F8FAFC')
  }
}
【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。