You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI PhotosPicker仅响应长按,点击无响应问题求助

问题:PhotosPicker点击无响应,仅长按可用(嵌入Hero导航缩放转场视图)

核心现象与已尝试操作

  • 正常点击PhotosPicker几乎无法唤起选择器UI,仅长按能稳定触发
  • Picker嵌入在通过HeroView的导航缩放转场呈现的视图中,怀疑转场手势干扰了默认点击行为
  • 已尝试:设置.allowsHitTesting(true)、添加高优先级手势,控制台能识别点击事件,但Picker仍不弹出

关联错误信息

  • 添加图片时出现:[ERROR] Could not create a bookmark: NSError: Cocoa 4097 'connection to service named com.apple.FileProvider'
  • 长按Picker时出现:<0x10210a280> Gesture: System gesture gate timed out

最小复现代码

import SwiftUI
import PhotosUI
import SwiftData

// Dummy Model Definitions
@Model
class Bus {
    var id: UUID = UUID()
    var date: Date = Date()
    //More stuff
    var images: [BusImage] = []
}

@Model
class BusImage {
    var id: UUID = UUID()
    var data: Data
    var bus: Bus?
    
    init(data: Data, bus: Bus? = nil) {
        self.data = data
        self.bus = bus
    }
}

struct HeroView: View {
    let bus: Bus
    @Binding var selectedBus: Bus?
    @Namespace private var ns

    var body: some View {
        NavigationLink(destination: CreateReportDetailsView(bus: bus, selectedBus: $selectedBus)
                        .navigationTransition(.zoom(sourceID: bus, in: ns))) {
            Text("Create Report")
                .padding()
                .background(Color.blue)
                .foregroundColor(.white)
                .cornerRadius(8)
        }
        .simultaneousGesture(TapGesture().onEnded {
            print("HeroView tap recognized.")
        })
    }
}

// CreateReportDetailsView that contains a TabView and a PhotoPickerView.
struct CreateReportDetailsView: View {
    let bus: Bus
    @Binding var selectedBus: Bus?
    @State private var selectedTabIndex: Int = 0

    var body: some View {
        VStack {
            TabView(selection: $selectedTabIndex) {
                BusPageView(bus: bus)
                    .tag(0)
                Text("page")
                    .tag(1)
            }
            .tabViewStyle(.page)
        }
        .navigationTitle(selectedTabIndex == 0 ? "Bus Info" : "Issues")
    }
}

// BusInfoPageView that embeds my PhotoPickerView.
struct BusPageView: View {
    let bus: Bus
    @State private var photosPickerItems: [PhotosPickerItem] = []
    
    var body: some View {
        VStack {
            // Other Bus info content here...
            PhotoPickerView(photosPickerItems: $photosPickerItems, bus: bus)
                .padding()
        }
    }
}

// PhotoPickerView with a high-priority tap gesture.
struct PhotoPickerView: View {
    @Binding var photosPickerItems: [PhotosPickerItem]
    let bus: Bus
    @Environment(\.modelContext) private var modelContext

    var body: some View {
        VStack {
            PhotosPicker("Select Photos", selection: $photosPickerItems, maxSelectionCount: 2, selectionBehavior: .ordered)
                .frame(width: 120, height: 120)
                .buttonStyle(.borderless)
                .background(Color(.systemFill))
                .clipShape(RoundedRectangle(cornerRadius: 20))
                .contentShape(RoundedRectangle(cornerRadius: 20))
                .simultaneousGesture(
                    TapGesture().onEnded {
                        print("Tap gesture recognized on PhotosPicker")
                    }
                )
        }
        .onChange(of: photosPickerItems) { _, _ in
            Task {
                for item in photosPickerItems {
                    if let data = try? await item.loadTransferable(type: Data.self) {
                        let newImage = BusImage(data: data, bus: bus)
                        bus.images.append(newImage)
                    }
                }
                photosPickerItems = []
                do {
                    try modelContext.save()
                } catch {
                    print("Error saving model: \(error.localizedDescription)")
                }
            }
        }
    }
}

解决方案

1. 验证导航转场是否为问题根源

临时替换Hero缩放转场为默认导航样式,确认Picker点击是否恢复正常:

// 修改HeroView中的NavigationLink
NavigationLink(destination: CreateReportDetailsView(bus: bus, selectedBus: $selectedBus)) {
    Text("Create Report")
        .padding()
        .background(Color.blue)
        .foregroundColor(.white)
        .cornerRadius(8)
}

如果替换后Picker点击正常,说明缩放转场的手势处理确实干扰了Picker的点击响应。

2. 修复手势冲突的具体方案

方案A:延迟启用Picker交互

等待转场完全完成后,再允许Picker接收点击事件:

struct BusPageView: View {
    let bus: Bus
    @State private var photosPickerItems: [PhotosPickerItem] = []
    @State private var isTransitionCompleted = false

    var body: some View {
        VStack {
            PhotoPickerView(photosPickerItems: $photosPickerItems, bus: bus)
                .padding()
                .allowsHitTesting(isTransitionCompleted)
        }
        .onAppear {
            // 延迟0.3秒确保转场结束
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
                isTransitionCompleted = true
            }
        }
    }
}

方案B:移除Picker上的额外手势

你添加的.simultaneousGesture(TapGesture())会和Picker内置系统手势冲突,直接移除该代码块:

// 修改PhotoPickerView中的PhotosPicker部分
PhotosPicker("Select Photos", selection: $photosPickerItems, maxSelectionCount: 2, selectionBehavior: .ordered)
    .frame(width: 120, height: 120)
    .buttonStyle(.borderless)
    .background(Color(.systemFill))
    .clipShape(RoundedRectangle(cornerRadius: 20))
    .contentShape(RoundedRectangle(cornerRadius: 20))
// 移除.simultaneousGesture(...)代码

方案C:调整转场手势优先级

将HeroView中的手势改为低优先级,避免抢占Picker的点击事件:

struct HeroView: View {
    let bus: Bus
    @Binding var selectedBus: Bus?
    @Namespace private var ns

    var body: some View {
        NavigationLink(destination: CreateReportDetailsView(bus: bus, selectedBus: $selectedBus)
                        .navigationTransition(.zoom(sourceID: bus, in: ns))) {
            Text("Create Report")
                .padding()
                .background(Color.blue)
                .foregroundColor(.white)
                .cornerRadius(8)
        }
        .highPriorityGesture(
            TapGesture().onEnded {
                print("HeroView tap recognized.")
            }, including: .subviews
        )
    }
}

3. 解决书签创建错误

Cocoa 4097错误属于FileProvider服务连接问题,可通过以下方式修复:

  • 确保Info.plist中已添加NSPhotoLibraryUsageDescription权限描述
  • 重启模拟器/设备,清理App缓存
  • 调整照片处理逻辑,等待数据加载保存完成后再清空选择项:
.onChange(of: photosPickerItems) { oldValue, newValue in
    Task {
        guard !newValue.isEmpty else { return }
        for item in newValue {
            if let data = try? await item.loadTransferable(type: Data.self) {
                let newImage = BusImage(data: data, bus: bus)
                bus.images.append(newImage)
            }
        }
        // 保存完成后再清空选择项
        do {
            try modelContext.save()
            photosPickerItems = []
        } catch {
            print("Error saving model: \(error.localizedDescription)")
        }
    }
}

内容的提问来源于stack exchange,提问作者Space Time

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 22:33:15