目录

手势卡顿或者不生效

现象描述

地图页面操作手势卡顿或者不生效。

可能原因

  1. 手势遮盖或者手势冲突。

    • 手势遮盖:地图组件的上层存在没有做手势穿透的组件。
    • 手势冲突:以Swiper容器组件中使用地图组件为例,Swiper容器组件和地图组件手势会存在冲突。
  2. 主线程阻塞。

    应用主线程处理大批量逻辑时,存在主线程阻塞,此时进行地图手势操作,手势应答会变慢甚至手势响应失败。

处理步骤

  1. 手势遮盖或者手势冲突。

    • 手势遮盖:参考触摸测试控制做手势穿透。
    • 手势冲突:以Swiper容器组件和地图组件手势存在冲突为例,解决方案参考如下代码:
      import { AsyncCallback, BusinessError } from '@kit.BasicServicesKit';
      import { map, mapCommon, MapComponent } from '@kit.MapKit';
      
      class MyDataSource implements IDataSource {
        private list: number[] = [];
      
        constructor(list: number[]) {
          this.list = list;
        }
      
        // 获取数组长度
        totalCount(): number {
          return this.list.length;
        }
      
        // 根据索引获取数据
        getData(index: number): number {
          return this.list[index];
        }
      
        // 注册数据变化监听器
        registerDataChangeListener(listener: DataChangeListener): void {
        }
      
        // 取消注册数据变化监听器
        unregisterDataChangeListener(listener: DataChangeListener): void {
        }
      }
      
      @Entry
      @Component
      struct SwiperExample {
        private swiperController: SwiperController = new SwiperController();
        private data: MyDataSource = new MyDataSource([]);
        private mapOptions?: mapCommon.MapOptions;
        private callback?: AsyncCallback<map.MapComponentController>;
        private mapController?: map.MapComponentController;
        private mapEventManager?: map.MapEventManager;
        @State mapPositionX: number = 0;
        @State mapPositionY: number = 0;
        @State mapHeight: number = 0;
        @State mapWidth: number = 0;
        @State index: number = 0;
      
        // 判断坐标是否在地图矩形内
        isMap(event: TouchEvent) {
          if (event.changedTouches[0].displayX > this.mapPositionX
            && event.changedTouches[0].displayX < this.mapPositionX + this.mapWidth
            && event.changedTouches[0].displayY > this.mapPositionY
            && event.changedTouches[0].displayY < this.mapPositionY + this.mapHeight) {
            return true;
          }
          return false;
        }
      
        aboutToAppear(): void {
          let list: number[] = [];
          for (let i = 1; i <= 10; i++) {
            list.push(i);
          }
          this.data = new MyDataSource(list);
      
          this.mapOptions = {
            position: {
              target: {
                latitude: 31.98441025,
                longitude: 118.766253
              },
              zoom: 10,
              tilt: 10,
              bearing: 90
            },
            scaleControlsEnabled: true
          }
      
          this.callback = async (err, mapController) => {
            if (!err) {
              this.mapController = mapController;
              this.mapEventManager = this.mapController.getEventManager();
              let callback = () => {
                console.info(`on-mapLoad`);
              };
              this.mapEventManager.on("mapLoad", callback);
            } else {
              console.error(`Failed to initialize the map, code is:${err.code}, message is ${err.message}`);
            }
          }
        }
      
        build() {
          Column({ space: 5 }) {
            Swiper(this.swiperController) {
              LazyForEach(this.data, (item: string) => {
                if (item == "3") {
                  Column() {
                    Text(item.toString())
                      .width('90%')
                      .height(160)
                      .backgroundColor(0xAFEEEE)
                      .textAlign(TextAlign.Center)
                      .fontSize(30)
                    MapComponent({ mapOptions: this.mapOptions, mapCallback: this.callback })
                      // 获取MapComponent的位置和长宽
                      .width('100%')
                      .height('65%')
                      .onAreaChange((_oldValue: Area, newValue: Area) => {
                        try {
                          if (newValue.globalPosition.x !== undefined && newValue.globalPosition.y !== undefined) {
                            this.mapPositionX = Number(newValue.globalPosition.x);
                            this.mapPositionY = Number(newValue.globalPosition.y);
                            this.mapHeight = Number(newValue.height);
                            this.mapWidth = Number(newValue.width);
                          }
                        } catch (error) {
                          let e: BusinessError = error as BusinessError;
                          console.error("onAreaChange error code:" + e.code + "message:" + e.message);
                        }
                      })
                  }.height("100%")
                } else {
                  Text(item.toString())
                    .width('90%')
                    .height(160)
                    .backgroundColor(0xAFEEEE)
                    .textAlign(TextAlign.Center)
                    .fontSize(30)
                }
              }, (item: string) => item)
            }
            // 手势判断 当index为存在地图页面且点击在地图矩形内时为HitTestMode.None(不响应Swiper手势,响应子组件手势)
            .onTouchIntercept((event: TouchEvent) => {
              if (this.index === 2 && this.isMap(event)) {
                return HitTestMode.None;
              }
              return HitTestMode.Transparent;
            })
            .cachedCount(2)
            .index(1)
            .loop(true)
            .itemSpace(0)
            // 设置圆点导航点样式
            .indicator(
              new DotIndicator()
                .itemWidth(15)
                .itemHeight(15)
                .selectedItemWidth(15)
                .selectedItemHeight(15)
                .color(Color.Gray)
                .selectedColor(Color.Blue))
            .displayArrow({
              // 设置导航点箭头样式
              showBackground: true,
              isSidebarMiddle: true,
              backgroundSize: 24,
              backgroundColor: Color.White,
              arrowSize: 18,
              arrowColor: Color.Blue
            }, false)
            .curve(Curve.Linear)
            .onChange((index: number) => {
              this.index = index;
            })
            .onGestureSwipe((index: number, extraInfo: SwiperAnimationEvent) => {
              console.info("index: " + index);
              console.info("current offset: " + extraInfo.currentOffset);
            })
      
            Row({ space: 12 }) {
              Button('showNext')
                .onClick(() => {
                  this.swiperController.showNext();
                })
              Button('showPrevious')
                .onClick(() => {
                  this.swiperController.showPrevious();
                })
            }.margin(5)
          }.width('100%')
          .margin({ top: 5 })
        }
      }
  2. 主线程阻塞。

    请分析应用的业务逻辑,将复杂逻辑放到子线程中处理。