tvOS平台双击遥控器确认键触发两次视图控制器转场问题求助
Hey there, let's fix that annoying double-segue issue on tvOS! Your iOS solution using a segueInProgress flag is a solid foundation, but tvOS has unique quirks with remote input handling and focus states that can cause duplicate segue triggers even with that check. Here's how to adapt your code for tvOS:
Core Adaptation: Track Segue State with Navigation Delegate + Transition Coordinator
The key is to ensure we only toggle the segueInProgress flag when we're certain the transition has started and fully completed. tvOS animations can have slight delays, so relying solely on shouldPerformSegue might not catch rapid double-taps.
Here's the updated code:
class ViewController: UIViewController, UINavigationControllerDelegate { // Initialize to false (no optional needed here for cleaner checks) var segueInProgress = false override func viewDidLoad() { super.viewDidLoad() navigationController?.delegate = self } override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool { // Block any new segues while one is in progress return !segueInProgress } // Mark the segue as in progress when the transition starts func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) { if animated && viewController != self { segueInProgress = true } } // Safely reset the flag ONLY after the transition animation completes func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) { navigationController.transitionCoordinator?.animate(alongsideTransition: nil) { [weak self] _ in self?.segueInProgress = false } } }
Why This Works for tvOS:
- The
transitionCoordinatorensures we don't reset the flag until the entire navigation animation finishes, which prevents premature re-enabling that could let a second tap slip through. - The navigation delegate methods reliably track when we're leaving the current view controller, so we don't have to guess when the segue starts.
Bonus: Add Guard Checks to IBActions (If You're Triggering Segues Manually)
If you're using an IBAction tied to the remote's Enter button to trigger the segue, add an extra check there to block duplicate calls:
@IBAction func triggerNextScreen(_ sender: Any) { guard !segueInProgress else { return } performSegue(withIdentifier: "YourSegueIdentifier", sender: sender) }
Extra Protection: Disable the Trigger Control During Transition
tvOS can sometimes keep focus on the button that triggered the segue even during the transition. To prevent accidental re-taps, temporarily disable the control until the transition finishes:
Update the navigation delegate methods like this:
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) { if animated && viewController != self { segueInProgress = true // Replace with your actual trigger control (e.g., UIButton, UICollectionViewCell) if let triggerButton = view.viewWithTag(100) as? UIButton { triggerButton.isEnabled = false } } } func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) { navigationController.transitionCoordinator?.animate(alongsideTransition: nil) { [weak self] _ in guard let self = self else { return } self.segueInProgress = false if let triggerButton = self.view.viewWithTag(100) as? UIButton { triggerButton.isEnabled = true } } }
These combined steps should eliminate the double-segue issue on tvOS by accounting for the platform's unique input and animation behavior.
内容的提问来源于stack exchange,提问作者Severyn Katolyk

