HarmonyOS 鸿蒙Next:Stack里面包裹PhotoPickerComponent组件,然后再在其上覆盖一层Row(或其他组件),导致PhotoPickerComponent组件触摸事件被拦截

发布于 1周前 作者 zlyuanteng 来自 鸿蒙OS

HarmonyOS 鸿蒙Next:Stack里面包裹PhotoPickerComponent组件,然后再在其上覆盖一层Row(或其他组件),导致PhotoPickerComponent组件触摸事件被拦截

Stack里面包裹PhotoPickerComponent组件,然后再PhotoPickerComponent组件上面盖一层Row(或者其他组件),那么PhotoPickerComponent组件的触摸事件被拦截了。

即使Row组件已经设置了属性 hitTestBehavior(HitTestMode.None) 或者 hitTestBehavior(HitTestMode.Transparent) 也不行。

如下图所示:
cke_2140.png

此时 PhotoPickerComponent组件 无法响应触摸事件。

把Row组件的hitTestBehavior换成HitTestMode.Transparent 也不行,如下图所示:

cke_5853.png

其他代码都不动,把 PhotoPickerComponent 组件换成其他的组件(如Text),那么Text组件是可以响应触摸的。如下图所示:

cke_27988.png

所以,PhotoPickerComponent组件是不是和其他组件相比有什么特殊的地方,导致被Stack包裹后,在上面放一层组件,导致PhotoPickerComponent组件无法响应触摸。但是把PhotoPickerComponent组件换成其他别的组件就没这个问题,求解答?????


更多关于HarmonyOS 鸿蒙Next:Stack里面包裹PhotoPickerComponent组件,然后再在其上覆盖一层Row(或其他组件),导致PhotoPickerComponent组件触摸事件被拦截的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html

9 回复
点击失效是因为组件被遮住了,按下面的加上背景色和zIndex就能看出来原因了
Row().width("100%")
            .backgroundColor('#ffcdb4b5')
            .height("100%")
            .hitTestBehavior(HitTestMode.None)
            .zIndex(-999)<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>

更多关于HarmonyOS 鸿蒙Next:Stack里面包裹PhotoPickerComponent组件,然后再在其上覆盖一层Row(或其他组件),导致PhotoPickerComponent组件触摸事件被拦截的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


楼主可以提供下能复现问题的demo

// xxx.ets import { PhotoPickerComponent, PickerController, PickerOptions, DataType, BaseItemInfo, ItemInfo, PhotoBrowserInfo, AnimatorParams, MaxSelected, ItemType, ClickType, PickerOrientation, SelectMode, PickerColorMode, ReminderMode, MaxCountType, PhotoBrowserRange, PhotoBrowserUIElement, ItemsDeletedCallback, ExceedMaxSelectedCallback, CurrentAlbumDeletedCallback } from ‘@ohos.file.PhotoPickerComponent’; import photoAccessHelper from ‘@ohos.file.photoAccessHelper’;

@Entry @Component struct PickerDemo { pickerOptions: PickerOptions = new PickerOptions(); @State pickerController: PickerController = new PickerController(); @State selectUris: Array<string> = new Array<string>(); @State currentUri: string = ‘’; @State isBrowserShow: boolean = false; private selectedItemsDeletedCallback: ItemsDeletedCallback = (baseItemInfos: Array<BaseItemInfo>) => this.onSelectedItemsDeleted(baseItemInfos); private exceedMaxSeletedCallback: ExceedMaxSelectedCallback = (exceedMaxCountType: MaxCountType) => this.onExceedMaxSelected(exceedMaxCountType); private currentAlbumDeletedCallback: CurrentAlbumDeletedCallback = () => this.onCurrentAlbumDeleted();

aboutToAppear() { this.pickerOptions.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_VIDEO_TYPE; this.pickerOptions.maxSelectNumber = 5; this.pickerOptions.isSearchSupported = false; this.pickerOptions.isPhotoTakingSupported = false; this.pickerOptions.photoBrowserCheckboxPosition = [0.5, 0.5]; // 其他属性… }

private onSelect(uri: string): void { // 添加 if (uri) { this.selectUris.push(uri); } }

private onDeselect(uri: string): void { // 移除 if (uri) { this.selectUris = this.selectUris.filter((item: string) => { return item != uri; }) } }

private onItemClicked(itemInfo: ItemInfo, clickType: ClickType): boolean { if (!itemInfo) { return false; } let type: ItemType | undefined = itemInfo.itemType; let uri: string | undefined = itemInfo.uri; if (type === ItemType.CAMERA) { // 点击相机item return true; // 返回true则拉起系统相机,若应用需要自行处理则返回false。 } else { if (clickType === ClickType.SELECTED) { // 应用做自己的业务处理 if (uri) { this.selectUris.push(uri); this.pickerOptions.preselectedUris = […this.selectUris]; } return true; // 返回true则勾选,否则则不响应勾选。 } else { if (uri) { this.selectUris = this.selectUris.filter((item: string) => { return item != uri; }); this.pickerOptions.preselectedUris = […this.selectUris]; } } return true; } }

private onEnterPhotoBrowser(photoBrowserInfo: PhotoBrowserInfo): boolean { // 进入大图的回调 this.isBrowserShow = true; return true; }

private onExitPhotoBrowser(photoBrowserInfo: PhotoBrowserInfo): boolean { // 退出大图的回调 this.isBrowserShow = false; return true; }

private onPickerControllerReady(): void { // 接收到该回调后,便可通过pickerController相关接口向picker发送数据,在此之前不生效。 let elements: number[] = [PhotoBrowserUIElement.BACK_BUTTON]; this.pickerController.setPhotoBrowserUIElementVisibility(elements, false); // 设置大图页不显示返回按钮 }

private onPhotoBrowserChanged(browserItemInfo: BaseItemInfo): boolean { // 大图左右滑动的回调 this.currentUri = browserItemInfo.uri ?? ‘’; return true; }

private onSelectedItemsDeleted(baseItemInfos: Array<BaseItemInfo>): void { // 已勾选图片被删除时的回调 }

private onExceedMaxSelected(exceedMaxCountType: MaxCountType): void { // 超过最大选择数量再次点击时的回调 }

private onCurrentAlbumDeleted(): void { // 当前相册被删除时的回调 }

build() { Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { Column() { if (this.isBrowserShow) { // 这里模拟应用自己的大图返回按钮 Row() { Button(“退出大图”).width(‘33%’).height(‘8%’).onClick(() => { this.pickerController.exitPhotoBrowser(); }) }.margin({ bottom: 20 }) }

    Stack(){
      Row() {
        PhotoPickerComponent({
          pickerOptions: this.pickerOptions,
          // onSelect: (uri: string): void =&gt; this.onSelect(uri),
          // onDeselect: (uri: string): void =&gt; this.onDeselect(uri),
          onItemClicked: (itemInfo: ItemInfo, clickType: ClickType): boolean =&gt; this.onItemClicked(itemInfo,
            clickType), // 该接口可替代上面两个接口
          onEnterPhotoBrowser: (photoBrowserInfo: PhotoBrowserInfo): boolean =&gt; this.onEnterPhotoBrowser(photoBrowserInfo),
          onExitPhotoBrowser: (photoBrowserInfo: PhotoBrowserInfo): boolean =&gt; this.onExitPhotoBrowser(photoBrowserInfo),
          onPickerControllerReady: (): void =&gt; this.onPickerControllerReady(),
          onPhotoBrowserChanged: (browserItemInfo: BaseItemInfo): boolean =&gt; this.onPhotoBrowserChanged(browserItemInfo),
          onSelectedItemsDeleted: this.selectedItemsDeletedCallback,
          onExceedMaxSelected: this.exceedMaxSeletedCallback,
          onCurrentAlbumDeleted: this.currentAlbumDeletedCallback,
          pickerController: this.pickerController,
        }).height('60%').width('100%')
      }

Row().width(“100%”) .height(“100%”) .hitTestBehavior(HitTestMode.None)

    }
    // 这里模拟应用侧底部的选择栏
    if (this.isBrowserShow) {
      Row() {
        ForEach(this.selectUris, (uri: string) =&gt; {
          if (uri === this.currentUri) {
            Image(uri)
              .height('10%')
              .width('10%')
              .onClick(() =&gt; {
              })
              .borderWidth(1)
              .borderColor('red')
          } else {
            Image(uri).height('10%').width('10%').onClick(() =&gt; {
              this.pickerController.setData(DataType.SET_SELECTED_URIS, this.selectUris);
              this.pickerController.setPhotoBrowserItem(uri, PhotoBrowserRange.ALL);
            })
          }
        }, (uri: string) =&gt; JSON.stringify(uri))
      }
    } else {
      Button('预览').width('33%').height('5%').onClick(() =&gt; {
        if (this.selectUris.length &gt; 0) {
          this.pickerController.setPhotoBrowserItem(this.selectUris[0], PhotoBrowserRange.SELECTED_ONLY);
        }
      })
    }
  }
}

} }

升级HarmonyOS后,发现手机的游戏性能也有了显著提升。

使用以下demo未出现楼主描述的情况,官方文档的示例,在PhotoPickerComponent外面加了Stack和Row

https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V13/ohos-file-photopickercomponent-V13#示例

// xxx.ets
import {
  PhotoPickerComponent,
  PickerController,
  PickerOptions,
  DataType,
  BaseItemInfo,
  ItemInfo,
  PhotoBrowserInfo,
  AnimatorParams,
  MaxSelected,
  ItemType,
  ClickType,
  PickerOrientation,
  SelectMode,
  PickerColorMode,
  ReminderMode,
  MaxCountType,
  PhotoBrowserRange,
  PhotoBrowserUIElement,
  ItemsDeletedCallback,
  ExceedMaxSelectedCallback,
  CurrentAlbumDeletedCallback
} from '@ohos.file.PhotoPickerComponent';
import photoAccessHelper from '@ohos.file.photoAccessHelper';

@Entry @Component struct PickerDemo { pickerOptions: PickerOptions = new PickerOptions(); @State pickerController: PickerController = new PickerController(); @State selectUris: Array<string> = new Array<string>(); @State currentUri: string = ‘’; @State isBrowserShow: boolean = false; private selectedItemsDeletedCallback: ItemsDeletedCallback = (baseItemInfos: Array<BaseItemInfo>) => this.onSelectedItemsDeleted(baseItemInfos); private exceedMaxSeletedCallback: ExceedMaxSelectedCallback = (exceedMaxCountType: MaxCountType) => this.onExceedMaxSelected(exceedMaxCountType); private currentAlbumDeletedCallback: CurrentAlbumDeletedCallback = () => this.onCurrentAlbumDeleted();

aboutToAppear() { this.pickerOptions.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_VIDEO_TYPE; this.pickerOptions.maxSelectNumber = 5; this.pickerOptions.isSearchSupported = false; this.pickerOptions.isPhotoTakingSupported = false; this.pickerOptions.photoBrowserCheckboxPosition = [0.5, 0.5]; // 其他属性… }

private onSelect(uri: string): void { // 添加 if (uri) { this.selectUris.push(uri); } }

private onDeselect(uri: string): void { // 移除 if (uri) { this.selectUris = this.selectUris.filter((item: string) => { return item != uri; }) } }

private onItemClicked(itemInfo: ItemInfo, clickType: ClickType): boolean { if (!itemInfo) { return false; } let type: ItemType | undefined = itemInfo.itemType; let uri: string | undefined = itemInfo.uri; if (type === ItemType.CAMERA) { // 点击相机item return true; // 返回true则拉起系统相机,若应用需要自行处理则返回false。 } else { if (clickType === ClickType.SELECTED) { // 应用做自己的业务处理 if (uri) { this.selectUris.push(uri); this.pickerOptions.preselectedUris = […this.selectUris]; } return true; // 返回true则勾选,否则则不响应勾选。 } else { if (uri) { this.selectUris = this.selectUris.filter((item: string) => { return item != uri; }); this.pickerOptions.preselectedUris = […this.selectUris]; } } return true; } }

private onEnterPhotoBrowser(photoBrowserInfo: PhotoBrowserInfo): boolean { // 进入大图的回调 this.isBrowserShow = true; return true; }

private onExitPhotoBrowser(photoBrowserInfo: PhotoBrowserInfo): boolean { // 退出大图的回调 this.isBrowserShow = false; return true; }

private onPickerControllerReady(): void { // 接收到该回调后,便可通过pickerController相关接口向picker发送数据,在此之前不生效。 let elements: number[] = [PhotoBrowserUIElement.BACK_BUTTON]; this.pickerController.setPhotoBrowserUIElementVisibility(elements, false); // 设置大图页不显示返回按钮 }

private onPhotoBrowserChanged(browserItemInfo: BaseItemInfo): boolean { // 大图左右滑动的回调 this.currentUri = browserItemInfo.uri ?? ‘’; return true; }

private onSelectedItemsDeleted(baseItemInfos: Array<BaseItemInfo>): void { // 已勾选图片被删除时的回调 }

private onExceedMaxSelected(exceedMaxCountType: MaxCountType): void { // 超过最大选择数量再次点击时的回调 }

private onCurrentAlbumDeleted(): void { // 当前相册被删除时的回调 }

build() { Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { Column() { if (this.isBrowserShow) { // 这里模拟应用自己的大图返回按钮 Row() { Button(“退出大图”).width(‘33%’).height(‘8%’).onClick(() => { this.pickerController.exitPhotoBrowser(); }) }.margin({ bottom: 20 }) }

    Stack(){
      Row() {
        PhotoPickerComponent({
          pickerOptions: <span class="hljs-keyword">this</span>.pickerOptions,
          <span class="hljs-comment">// onSelect: (uri: string): void =&gt; this.onSelect(uri),</span>
          <span class="hljs-comment">// onDeselect: (uri: string): void =&gt; this.onDeselect(uri),</span>
          onItemClicked: (itemInfo: ItemInfo, clickType: ClickType): boolean =&gt; <span class="hljs-keyword">this</span>.onItemClicked(itemInfo,
            clickType), <span class="hljs-comment">// 该接口可替代上面两个接口</span>
          onEnterPhotoBrowser: (photoBrowserInfo: PhotoBrowserInfo): boolean =&gt; <span class="hljs-keyword">this</span>.onEnterPhotoBrowser(photoBrowserInfo),
          onExitPhotoBrowser: (photoBrowserInfo: PhotoBrowserInfo): boolean =&gt; <span class="hljs-keyword">this</span>.onExitPhotoBrowser(photoBrowserInfo),
          onPickerControllerReady: (): <span class="hljs-keyword">void</span> =&gt; <span class="hljs-keyword">this</span>.onPickerControllerReady(),
          onPhotoBrowserChanged: (browserItemInfo: BaseItemInfo): boolean =&gt; <span class="hljs-keyword">this</span>.onPhotoBrowserChanged(browserItemInfo),
          onSelectedItemsDeleted: <span class="hljs-keyword">this</span>.selectedItemsDeletedCallback,
          onExceedMaxSelected: <span class="hljs-keyword">this</span>.exceedMaxSeletedCallback,
          onCurrentAlbumDeleted: <span class="hljs-keyword">this</span>.currentAlbumDeletedCallback,
          pickerController: <span class="hljs-keyword">this</span>.pickerController,
        }).height(<span class="hljs-string">'60%'</span>).width(<span class="hljs-string">'100%'</span>)
      }
    }
    <span class="hljs-comment">// 这里模拟应用侧底部的选择栏</span>
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.isBrowserShow) {
      Row() {
        ForEach(<span class="hljs-keyword">this</span>.selectUris, (uri: string) =&gt; {
          <span class="hljs-keyword">if</span> (uri === <span class="hljs-keyword">this</span>.currentUri) {
            Image(uri)
              .height(<span class="hljs-string">'10%'</span>)
              .width(<span class="hljs-string">'10%'</span>)
              .onClick(() =&gt; {
              })
              .borderWidth(<span class="hljs-number">1</span>)
              .borderColor(<span class="hljs-string">'red'</span>)
          } <span class="hljs-keyword">else</span> {
            Image(uri).height(<span class="hljs-string">'10%'</span>).width(<span class="hljs-string">'10%'</span>).onClick(() =&gt; {
              <span class="hljs-keyword">this</span>.pickerController.setData(DataType.SET_SELECTED_URIS, <span class="hljs-keyword">this</span>.selectUris);
              <span class="hljs-keyword">this</span>.pickerController.setPhotoBrowserItem(uri, PhotoBrowserRange.ALL);
            })
          }
        }, (uri: string) =&gt; <span class="hljs-built_in">JSON</span>.stringify(uri))
      }
    } <span class="hljs-keyword">else</span> {
      Button(<span class="hljs-string">'预览'</span>).width(<span class="hljs-string">'33%'</span>).height(<span class="hljs-string">'5%'</span>).onClick(() =&gt; {
        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.selectUris.length &gt; <span class="hljs-number">0</span>) {
          <span class="hljs-keyword">this</span>.pickerController.setPhotoBrowserItem(<span class="hljs-keyword">this</span>.selectUris[<span class="hljs-number">0</span>], PhotoBrowserRange.SELECTED_ONLY);
        }
      })
    }
  }
}

} }<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>

Stack(){ Row() { PhotoPickerComponent({ pickerOptions: this.pickerOptions, // onSelect: (uri: string): void => this.onSelect(uri), // onDeselect: (uri: string): void => this.onDeselect(uri), onItemClicked: (itemInfo: ItemInfo, clickType: ClickType): boolean => this.onItemClicked(itemInfo, clickType), // 该接口可替代上面两个接口 onEnterPhotoBrowser: (photoBrowserInfo: PhotoBrowserInfo): boolean => this.onEnterPhotoBrowser(photoBrowserInfo), onExitPhotoBrowser: (photoBrowserInfo: PhotoBrowserInfo): boolean => this.onExitPhotoBrowser(photoBrowserInfo), onPickerControllerReady: (): void => this.onPickerControllerReady(), onPhotoBrowserChanged: (browserItemInfo: BaseItemInfo): boolean => this.onPhotoBrowserChanged(browserItemInfo), onSelectedItemsDeleted: this.selectedItemsDeletedCallback, onExceedMaxSelected: this.exceedMaxSeletedCallback, onCurrentAlbumDeleted: this.currentAlbumDeletedCallback, pickerController: this.pickerController, }).height(‘60%’).width(‘100%’) }

  Row().width("100%")
    .height("100%")
}

你在Stack里面加个充满父布局的Row试试,这样就复现了

Stack(){ Row() { PhotoPickerComponent({ pickerOptions: this.pickerOptions, // onSelect: (uri: string): void => this.onSelect(uri), // onDeselect: (uri: string): void => this.onDeselect(uri), onItemClicked: (itemInfo: ItemInfo, clickType: ClickType): boolean => this.onItemClicked(itemInfo, clickType), // 该接口可替代上面两个接口 onEnterPhotoBrowser: (photoBrowserInfo: PhotoBrowserInfo): boolean => this.onEnterPhotoBrowser(photoBrowserInfo), onExitPhotoBrowser: (photoBrowserInfo: PhotoBrowserInfo): boolean => this.onExitPhotoBrowser(photoBrowserInfo), onPickerControllerReady: (): void => this.onPickerControllerReady(), onPhotoBrowserChanged: (browserItemInfo: BaseItemInfo): boolean => this.onPhotoBrowserChanged(browserItemInfo), onSelectedItemsDeleted: this.selectedItemsDeletedCallback, onExceedMaxSelected: this.exceedMaxSeletedCallback, onCurrentAlbumDeleted: this.currentAlbumDeletedCallback, pickerController: this.pickerController, }).height(‘60%’).width(‘100%’) }

  Row().width("100%")
    .height("100%")
    .hitTestBehavior(HitTestMode.None)
}

即使给新加的Row 设置了 hitTestBehavior(HitTestMode.None) ,PhotoPickerComponent依然无法获取到焦点

PhotoPickerComponent依然无法获取到触摸事件

在HarmonyOS鸿蒙Next中,如果要在Stack组件中包裹一个PhotoPickerComponent组件,并且在其上覆盖一层Row(或其他组件),同时确保PhotoPickerComponent组件的触摸事件不被拦截,你可以使用事件穿透机制。在鸿蒙系统中,可以使用consume属性来控制事件是否继续向下传递。

以下是一个简单的示例代码,展示了如何在Stack中设置PhotoPickerComponent和Row,同时确保PhotoPickerComponent的触摸事件不被Row拦截:

<Stack>
    <!-- PhotoPickerComponent 组件 -->
    <PhotoPickerComponent
        id="$+id:photoPicker"
        width="match_parent"
        height="match_parent"
        />

    <!-- 覆盖在PhotoPickerComponent上的Row组件 -->
    <Row
        width="match_parent"
        height="wrap_content"
        alignment="center"
        orientation="horizontal"
        consume="false"  <!-- 设置事件不消费,允许事件穿透 -->
        >
        <!-- Row中的其他子组件,例如Button -->
        <Button
            id="$+id:button1"
            text="Button 1"
            width="wrap_content"
            height="wrap_content"
            />
        <Button
            id="$+id:button2"
            text="Button 2"
            width="wrap_content"
            height="wrap_content"
            />
    </Row>
</Stack>

在这个示例中,Row组件的consume属性被设置为false,这意味着当触摸事件发生在Row上时,事件不会在此处被消费,而是会继续向下传递到PhotoPickerComponent。这样,用户可以正常地与PhotoPickerComponent进行交互,即使它被Row组件覆盖。

请注意,consume属性的行为可能因组件类型和具体实现而有所不同,因此在实际应用中,你可能需要根据具体情况进行调整。

如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html

回到顶部