Swift技术实现:弹窗显示时保持TableView可交互
Hey there! I get exactly what you're aiming for—having a popup show up while still letting users scroll through and select cells in your TableView is a great UX touch for many apps. Let me walk you through how to make this work smoothly, depending on whether you're using SwiftUI or UIKit.
The key here is to make sure your popup's non-interactive background doesn't block touches from reaching the List (SwiftUI's equivalent of TableView). Here's how to do it:
Make the popup background pass through touches
Use the.allowsHitTesting(false)modifier on the popup's background layer. This lets any swipes or taps on the background fall straight through to the List below, while keeping the popup's interactive elements (like buttons) fully functional.Example code:
struct InteractivePopupView: View { @State private var showPopup = true var body: some View { // Your TableView equivalent (List) List(0..<50) { index in Text("Row \(index)") .onTapGesture { print("Selected row \(index)") } } .overlay( Group { if showPopup { // Semi-transparent background (non-interactive) Color.black.opacity(0.3) .edgesIgnoringSafeArea(.all) .allowsHitTesting(false) // Critical for touch pass-through // Popup content (fully interactive) VStack(spacing: 16) { Text("My Floating Popup") .font(.headline) Button("Close Popup") { showPopup = false } .padding() .background(Color.blue) .foregroundColor(.white) .cornerRadius(8) } .padding(20) .background(Color.white) .cornerRadius(12) .shadow(radius: 10) } } ) } }With this setup, users can scroll the List, tap to select rows, and interact with the popup's button all at the same time.
In UIKit, we need to control how touch events are handled by the popup view. The goal is to only let interactive subviews (like buttons) consume touches—everything else should pass through to the TableView.
Override hit testing for the popup
Create a custom popup view and override thehitTest(_:with:)method. This method determines which view gets to handle a touch event. We'll make sure that if the touch lands on the popup's non-interactive background, we returnnilso the event goes to the TableView below.Swift example:
class CustomPopupView: UIView { // Your popup's background view (non-interactive) private let backgroundView: UIView = { let view = UIView() view.backgroundColor = UIColor.black.withAlphaComponent(0.3) view.frame = UIScreen.main.bounds return view }() // Your interactive popup content private let contentView: UIView = { let view = UIView() view.backgroundColor = .white view.layer.cornerRadius = 12 view.frame = CGRect(x: 50, y: 200, width: 300, height: 200) // Add a sample button let closeButton = UIButton(type: .system) closeButton.setTitle("Close", for: .normal) closeButton.frame = CGRect(x: 80, y: 120, width: 140, height: 40) view.addSubview(closeButton) return view }() override init(frame: CGRect) { super.init(frame: frame) setupViews() } required init?(coder: NSCoder) { super.init(coder: coder) setupViews() } private func setupViews() { addSubview(backgroundView) addSubview(contentView) } override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { let hitView = super.hitTest(point, with: event) // If the touch is on the background, pass through to underlying views if hitView == backgroundView { return nil } // Otherwise, let the hit view (like the button) handle the touch return hitView } }Now, when you present this popup over your TableView, users can scroll the table and select cells while interacting with the popup's button.
- Always test both interactions: make sure your popup's buttons/text fields work as expected, and that the TableView's scrolling/selection is smooth.
- If your popup has multiple non-interactive areas, adjust the
hitTestlogic to cover all of them (or group them into a single background view for easier handling).
内容的提问来源于stack exchange,提问作者user12564133

