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

SwiftUI添加拖拽手势后搜索栏无法唤起键盘的解决方法

问题:拖拽手势导致搜索栏无法唤起键盘

主视图底部通过Overlay添加了TabView,点击标签页会打开后方的自定义模态视图(示例中为SearchExploreModalView)。但为标签项添加拖拽手势后,视图内的搜索栏点击无法唤起键盘。

复现代码

import SwiftUI
import Foundation
import Combine

struct ContentView: View {
    var body: some View {
        VStack {
            SimpleDataView()
        }
        .overlay(alignment: .bottom) {
            BottomTabView()
        }
    }
}

struct SimpleDataView: View {
    var body: some View {
        VStack {
            Text("Map will be displayed over here").background(Color.gray).frame(maxWidth: .infinity, maxHeight: .infinity)
            Spacer()
        }
        .background(Color.gray)
        .ignoresSafeArea()
    }
}

struct BottomTabView: View {
    @State private var defaultHandleColor = Color.secondary
    @State private var activeHandleColor = Color.primary
    @State private var sliderHandleHeight: CGFloat = 15.0
    @State private var radius: CGFloat = 16
    
    /// The latest recorded drag gesture value.
    @State var latestDragGesture: DragGesture.Value?
    @State private var maximumHeight: CGFloat = .infinity
    @State private var isPanelExpanding: Bool = false
    @State private var handleColor = Color.secondary

    
    @State var selection: Int = 1
    var body: some View {
        TabView(selection: $selection) {
            Group {
                ZStack {
                    SearchExploreModalView()
                }.tabItem {
                    Label("Explore", systemImage: "magnifyingglass")
                    Text("Explore")
                }
                .tag(1)
                .gesture(drag)
            }
        }
        .background(Color(red: 0.98, green: 0.98, blue: 0.98).opacity(0.94))
        .onAppear {
            let appearance = UITabBarAppearance()
            UITabBar.appearance().scrollEdgeAppearance = appearance
        }
    }
    
    var drag: some Gesture {
        DragGesture(minimumDistance: 0, coordinateSpace: .global)
            .onChanged {
                let deltaY = $0.location.y - (latestDragGesture?.location.y ?? $0.location.y)
                let proposedHeight = 250.0 + (-1 * deltaY)
                self.isPanelExpanding = proposedHeight >= 250.0 ? true : false
                handleColor = activeHandleColor
                latestDragGesture = $0
            }
            .onEnded { _ in
                // On Ended logic
            }
    }
}

struct SearchExploreModalView: View {
    @State private var searchText = ""
    let searchTextPublisher = PassthroughSubject<String, Never>()

    var body: some View {
        VStack {
            NavigationView {
                List {
                    // For loop iterating overdata
                }
                .searchable(
                    text: $searchText,
                    placement: .navigationBarDrawer(displayMode: .always),
                    prompt: "Search"
                )
                .onChange(of: searchText) { newText in
                    searchTextPublisher.send(newText) /// Publishes when a search term is changed. This is used to debounce the search.
                }
            }
            Spacer()
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(Color.gray)
    }
}

解决方案

问题根源

设置minimumDistance: 0的DragGesture会捕获所有触摸事件,包括搜索栏的点击操作,导致搜索栏无法接收到点击信号,无法唤起键盘。

修复方法:调整拖拽手势的最小触发距离

将DragGesture的minimumDistance从0改为一个较小的正值(比如5),这样只有当用户的触摸移动超过这个距离时才会触发拖拽手势,点击事件会正常传递给搜索栏。

修改后的拖拽手势代码:

var drag: some Gesture {
    DragGesture(minimumDistance: 5, coordinateSpace: .global) // 修改minimumDistance
        .onChanged {
            let deltaY = $0.location.y - (latestDragGesture?.location.y ?? $0.location.y)
            let proposedHeight = 250.0 + (-1 * deltaY)
            self.isPanelExpanding = proposedHeight >= 250.0 ? true : false
            handleColor = activeHandleColor
            latestDragGesture = $0
        }
        .onEnded { _ in
            // On Ended logic
        }
}

替代方案:使用手势优先级控制

如果需要保留minimumDistance: 0,可以通过highPriorityGesture确保搜索栏的交互优先:

// 在SearchExploreModalView的NavigationView上添加高优先级点击手势
NavigationView {
    List {
        // For loop iterating overdata
    }
    .searchable(
        text: $searchText,
        placement: .navigationBarDrawer(displayMode: .always),
        prompt: "Search"
    )
    .onChange(of: searchText) { newText in
        searchTextPublisher.send(newText)
    }
}
.highPriorityGesture(TapGesture().onEnded {
    // 空实现,确保点击事件被搜索栏接收
})

不过这种方法不如调整minimumDistance简洁有效,推荐优先使用第一种方案。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 16:55:21