开天辟地 HarmonyOS(鸿蒙) - 输入: 触摸类输入

源码 https://github.com/webabcd/HarmonyDemo
作者 webabcd

开天辟地 HarmonyOS(鸿蒙) - 输入: 触摸类输入

示例如下:

pages\input\TouchDemo.ets

/*
 * 触摸类输入
 * 点击事件,触摸事件,拖拽事件,事件冒泡,事件透传
 */

import { TitleBar } from '../TitleBar';
import { unifiedDataChannel, uniformTypeDescriptor } from '@kit.ArkData';

@Entry
@Component
struct TouchDemo {

  build() {
    Column() {
      TitleBar()
      Tabs() {
        TabContent() { MySample1() }.tabBar('点击事件').align(Alignment.Top)
        TabContent() { MySample2() }.tabBar('触摸事件').align(Alignment.Top)
        TabContent() { MySample3() }.tabBar('拖拽事件').align(Alignment.Top)
        TabContent() { MySample4() }.tabBar('事件冒泡').align(Alignment.Top)
        TabContent() { MySample5() }.tabBar('事件透传').align(Alignment.Top)
      }
      .scrollable(true)
      .barMode(BarMode.Scrollable)
      .layoutWeight(1)
    }
  }
}

@Component
struct MySample1 {

  @State message: string = ""

  build() {
    Column({ space: 10 }) {

      Text(this.message)

      /*
       * onClick() - 点击事件,当按下并抬起后触发(回调参数是一个 ClickEvent 对象)
       *   x, y - 点击位置相对于组件左上角的坐标
       *   windowX, windowY - 点击位置相对于窗口的坐标
       *   displayX, displayY - 点击位置相对于屏幕的坐标
       *   timestamp - 事件触发时,距系统启动时的时间戳
       *   target.area - 触发了事件的组件的显示区域(一个 Area 对象)
       *     width, height - 尺寸
       *     position - 区域的左上角相对于父容器的左上角的位置
       *     globalPosition - 区域的左上角相对于页面的左上角的位置
       */
      Button('click me').onClick((event: ClickEvent) => {
        this.message = "onClick\n"
        this.message += `x:${event.x}\n`
        this.message += `y:${event.y}\n`
        this.message += `windowX:${event.windowX}\n`
        this.message += `windowY:${event.windowY}\n`
        this.message += `displayX:${event.displayX}\n`
        this.message += `displayY:${event.displayY}\n`
        this.message += `timestamp:${event.timestamp}\n`
        this.message += `target area width:${event.target.area.width}\n`
        this.message += `target area height:${event.target.area.height}\n`
        this.message += `target area position:${JSON.stringify(event.target.area.position)}\n`
        this.message += `target area globalPosition:${JSON.stringify(event.target.area.globalPosition)}\n`
      })
    }
  }
}

@Component
struct MySample2 {

  @State message: string = ""

  build() {
    Column({ space: 10 }) {

      Text(this.message)

      /*
       * onTouch() - 触摸事件,当按下或滑动或抬起时触发(回调参数是一个 TouchEvent 对象)
       *   type - 触摸的类型(TouchEvent 枚举)
       *     Down, Up, Move
       *   touches - 当前全部的触摸点的信息(一个 TouchObject 对象数组)
       *   changedTouches - 当前发生变化的触摸点的信息(一个 TouchObject 对象数组)
       *
       * TouchObject - 触摸点信息
       *   x, y - 触摸点的位置相对于组件左上角的坐标
       *   windowX, windowY - 触摸点的位置相对于窗口的坐标
       *   displayX, displayY - 触摸点的位置相对于屏幕的坐标
       *   timestamp - 事件触发时,距系统启动时的时间戳
       *   target.area - 触发了事件的组件的显示区域(一个 Area 对象)
       *     width, height - 尺寸
       *     position - 区域的左上角相对于父容器的左上角的位置
       *     globalPosition - 区域的左上角相对于页面的左上角的位置
       */
      Button('click me').onTouch((event: TouchEvent) => {
        let touches = event.touches
        let changedTouches = event.changedTouches

        this.message = "onTouch\n"
        this.message += `type:${TouchType[event.type]}\n`
        this.message += `x:${touches[0].x}\n`
        this.message += `y:${touches[0].y}\n`
        this.message += `windowX:${touches[0].windowX}\n`
        this.message += `windowY:${touches[0].windowY}\n`
        this.message += `displayX:${touches[0].displayX}\n`
        this.message += `displayY:${touches[0].displayY}\n`
        this.message += `timestamp:${event.timestamp}\n`
        this.message += `target area width:${event.target.area.width}\n`
        this.message += `target area height:${event.target.area.height}\n`
        this.message += `target area position:${JSON.stringify(event.target.area.position)}\n`
        this.message += `target area globalPosition:${JSON.stringify(event.target.area.globalPosition)}\n`
      })
    }
  }
}

@Component
struct MySample3 {

  @State message: string = ""
  @State targetText: string = ""
  @State targetImage: string = ""

  build() {
    Column({space:10}) {

      Text(this.message)

      /*
       * draggable() - 是否支持按下后的拖拽操作(注:设置为 true 后,还必须要监听 onDragStart() 事件,才能支持拖拽操作)
       * allowDrop() - 当拖拽组件落入当前组件时,指定允许传递的数据类型(一个 UniformDataType 枚举数组)
       *   PLAIN_TEXT, IMAGE, 等
       *
       * onDragStart() - 拖拽开始时的回调(当长按时间大于 500 毫秒,且拖拽距离大于 10vp 时触发回调)
       * onPreDrag() - 拖拽发起前的回调
       * onDragEnd() - 拖拽完成后的回调
       *
       * onDrop() - 当拖拽组件在当前组件释放时的回调
       * onDragEnter(), onDragMove(), onDragLeave() - 当拖拽组件进入当前组件,在当前组件上移动,离开当前组件时的回调(当监听了 onDrop() 时才会生效)
       */

      Text('text').border({ color: Color.Black, width: 1 })
        .width('100%')
        .height(100)
        .draggable(true)
        .onDragStart((event: DragEvent) => {
          this.message = `onDragStart`
          // 设置 PlainText 类型的拖拽数据
          let data: unifiedDataChannel.PlainText = new unifiedDataChannel.PlainText();
          data.textContent = 'textContent';
          event.setData(new unifiedDataChannel.UnifiedData(data));
        })
        .onPreDrag((status: PreDragStatus) => {
          this.message = `onPreDrag:${status}`
        })
        .onDragEnd((event: DragEvent) => {
          // 通过 event.getResult() 获取 drop 的结果(即在 onDrop() 中通过 event.setResult() 设置的结果)
          this.message = `onDragEnd:${DragResult[event.getResult()]}`
        })
      Text(this.targetText).border({ color: Color.Black, width: 1 })
        .width('100%')
        .height(100)
        .allowDrop([uniformTypeDescriptor.UniformDataType.PLAIN_TEXT])
        .onDrop((event: DragEvent) => {
          let data: UnifiedData = event.getData();
          if (!data) {
            return;
          }
          let records: Array<unifiedDataChannel.UnifiedRecord> = data.getRecords();
          if (!records || records.length <= 0) {
            return;
          }

          // 获取 PlainText 类型的拖拽数据
          let plainText: unifiedDataChannel.PlainText = records[0] as unifiedDataChannel.PlainText;
          this.targetText = plainText.textContent;

          // 设置 drop 的结果
          event.setResult(DragResult.DRAG_SUCCESSFUL);
        })
        .onDragEnter((event: DragEvent) => {
          this.message = `onDragEnter`
        })
        .onDragMove((event: DragEvent) => {
          this.message = `onDragMove`
        })
        .onDragLeave((event: DragEvent) => {
          this.message = `onDragLeave`
        })

      Image($r('app.media.app_icon')).width(100).height(100)
        .draggable(true)
        .onDragEnd((event: DragEvent) => {
          // 通过 event.getResult() 获取 drop 的结果(即在 onDrop() 中通过 event.setResult() 设置的结果)
          this.message = `onDragEnd:${DragResult[event.getResult()]}`
        })
      Image(this.targetImage).width(100).height(100).border({ color: Color.Black, width: 1 })
        .allowDrop([uniformTypeDescriptor.UniformDataType.IMAGE])
        .onDrop((event: DragEvent) => {
          let data: UnifiedData = event.getData();
          if (!data) {
            return;
          }
          let records: Array<unifiedDataChannel.UnifiedRecord> = data.getRecords();
          if (!records || records.length <= 0) {
            return;
          }

          // 获取拖拽的图片的地址
          this.targetImage = (records[0] as unifiedDataChannel.Image).imageUri;

          // 设置 drop 的结果
          event.setResult(DragResult.DRAG_SUCCESSFUL);
        })
    }
  }
}

@Component
struct MySample4 {

  @State message: string = ""

  build() {
    Column({space:10}) {

      Text(this.message)

      /*
       * 父子组件场景下
       * onTouch() 事件默认是支持冒泡的,如果不需要冒泡则调用 event.stopPropagation() 即可
       */

      Column() {
        Column() {
          Column() {

          }
          .width(100).height(100).backgroundColor(Color.Red)
          .onTouch(() => {
            this.message += "r"
          })
        }
        .width(200).height(200).backgroundColor(Color.Green)
        .onTouch(() => {
          this.message += "g"
        })
      }
      .width(300).height(300).backgroundColor(Color.Blue)
      .onTouch(() => {
        this.message += "b"
      })

      Column() {
        Column() {
          Column() {

          }
          .width(100).height(100).backgroundColor(Color.Red)
          .onTouch((event: TouchEvent) => {
            event.stopPropagation()
            this.message += "r"
          })
        }
        .width(200).height(200).backgroundColor(Color.Green)
        .onTouch((event: TouchEvent) => {
          event.stopPropagation()
          this.message += "g"
        })
      }
      .width(300).height(300).backgroundColor(Color.Blue)
      .onTouch((event: TouchEvent) => {
        event.stopPropagation()
        this.message += "b"
      })
    }
  }
}

@Component
struct MySample5 {

  @State message: string = ""

  build() {
    Column({space:10}) {

      Text(this.message)

      /*
       * 兄弟组件场景下
       * onTouch() 事件默认是不支持透传的,如果需要透传则调用 hitTestBehavior(HitTestMode.Transparent) 即可
       */

      Stack() {
        Column().width(300).height(300).backgroundColor(Color.Blue)
          .onTouch(() => {
            this.message += "b"
          })
        Column().width(200).height(200).backgroundColor(Color.Green)
          .onTouch(() => {
            this.message += "g"
          })
        Column().width(100).height(100).backgroundColor(Color.Red)
          .onTouch(() => {
            this.message += "r"
          })
      }
      .width(300).height(300)

      Stack() {
        Column().width(300).height(300).backgroundColor(Color.Blue)
          .onTouch(() => {
            this.message += "b"
          })
          .hitTestBehavior(HitTestMode.Transparent)
        Column().width(200).height(200).backgroundColor(Color.Green)
          .onTouch(() => {
            this.message += "g"
          })
          .hitTestBehavior(HitTestMode.Transparent)
        Column().width(100).height(100).backgroundColor(Color.Red)
          .onTouch(() => {
            this.message += "r"
          })
          .hitTestBehavior(HitTestMode.Transparent)
      }
      .width(300).height(300)
    }
  }
}

源码 https://github.com/webabcd/HarmonyDemo
作者 webabcd

posted @ 2025-03-07 15:21  webabcd  阅读(62)  评论(0)    收藏  举报