iOS水果详情页背景动画致返回按钮与下滑关闭失效问题
问题描述
我开发了一款展示水果列表的iOS应用,点击任意水果会弹出详情页,显示该水果的全部信息与营养成分。当选中的水果含糖量超过10时,详情页背景需在红色与白色之间循环切换动画。目前遇到的问题是:这类带背景动画的详情页,其返回按钮(Tilbake)和下滑关闭页面的功能均失效,疑似有图层阻挡了屏幕交互,该如何解决?
问题分析
你的问题核心在于背景动画默认禁用了用户交互,同时当前的动画实现逻辑存在冗余嵌套:
- UIView的
animate方法默认会在动画期间将视图的userInteractionEnabled设为false,导致整个页面无法响应触摸操作 - 你在第一个动画的completion回调里又启动了另一个重复动画,这种嵌套会持续占用动画队列,进一步加剧交互阻塞
解决方案
1. 修复动画逻辑,添加允许交互的选项
不需要嵌套两个重复动画,只需要一次动画设置.repeat和.autoreverse,同时加上.allowsUserInteraction选项,让动画运行时不阻止用户交互。
2. 优化动画实现
直接在单次动画中完成红白循环,避免不必要的嵌套:
func animatedBackground(){ UIView.animate(withDuration: 1.0, delay: 0.0, options: [.repeat, .autoreverse, .allowsUserInteraction], animations: { self.view.backgroundColor = .red }, completion: nil) }
3. 额外检查项
- 确认返回按钮
dismissButton的约束正确,确保它在屏幕可见区域内 - 检查所有子视图,有没有意外设置
userInteractionEnabled = false或者层级覆盖了按钮(当前代码里的标签默认不可交互,不会影响) - 如果是用present方式弹出详情页,下滑关闭需要确保呈现方式支持该交互(比如设置
modalPresentationStyle = .pageSheet)
修改后的完整代码
import UIKit class FruitDetailVC: UIViewController{ var fruit: Fruit? var safeArea: UILayoutGuide! let nameLabel = UILabel() let genusLabel = UILabel() let familyLabel = UILabel() let orderLabel = UILabel() let idLabel = UILabel() let carbLabel = UILabel() let proteinLabel = UILabel() let fatLabel = UILabel() let caloriesLabel = UILabel() let sugarLabel = UILabel() let dividerLabel = UILabel() let sugarWarningLabel = UILabel() let dismissButton = UIButton() override func viewDidLoad() { super.viewDidLoad() setupdata() setupLabel() setupDismissButton() safeArea = view.layoutMarginsGuide view.backgroundColor = .white // 替换强制解包为可选绑定,避免崩溃 if let sugar = fruit?.nutritions.sugar, sugar > 10 { sugarWarningLabel.text = "This contains over 10 of sugar!!!" animatedBackground() } } func animatedBackground(){ // 修复动画逻辑,添加允许交互选项 UIView.animate(withDuration: 1.0, delay: 0.0, options: [.repeat, .autoreverse, .allowsUserInteraction], animations: { self.view.backgroundColor = .red }, completion: nil) } func setupLabel(){ view.addSubview(nameLabel) view.addSubview(genusLabel) view.addSubview(familyLabel) view.addSubview(orderLabel) view.addSubview(idLabel) view.addSubview(carbLabel) view.addSubview(proteinLabel) view.addSubview(fatLabel) view.addSubview(caloriesLabel) view.addSubview(sugarLabel) view.addSubview(dividerLabel) view.addSubview(sugarWarningLabel) // 水果基础信息 nameLabel.translatesAutoresizingMaskIntoConstraints = false nameLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true nameLabel.topAnchor.constraint(equalTo: view.topAnchor).isActive = true nameLabel.font = UIFont(name: "Verdana-Bold", size: 16) genusLabel.translatesAutoresizingMaskIntoConstraints = false genusLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true genusLabel.topAnchor.constraint(equalTo: nameLabel.bottomAnchor).isActive = true genusLabel.font = UIFont(name: "Verdana", size: 14) familyLabel.translatesAutoresizingMaskIntoConstraints = false familyLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true familyLabel.topAnchor.constraint(equalTo: genusLabel.bottomAnchor).isActive = true familyLabel.font = UIFont(name: "Verdana", size: 14) orderLabel.translatesAutoresizingMaskIntoConstraints = false orderLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true orderLabel.topAnchor.constraint(equalTo: familyLabel.bottomAnchor).isActive = true orderLabel.font = UIFont(name: "Verdana", size: 14) idLabel.translatesAutoresizingMaskIntoConstraints = false idLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true idLabel.topAnchor.constraint(equalTo: orderLabel.bottomAnchor).isActive = true idLabel.font = UIFont(name: "Verdana", size: 14) // 营养信息分隔线 dividerLabel.translatesAutoresizingMaskIntoConstraints = false dividerLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true dividerLabel.topAnchor.constraint(equalTo: idLabel.bottomAnchor).isActive = true dividerLabel.font = UIFont(name: "Verdana-Bold", size: 16) // 营养信息 carbLabel.translatesAutoresizingMaskIntoConstraints = false carbLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true carbLabel.topAnchor.constraint(equalTo: dividerLabel.bottomAnchor).isActive = true carbLabel.font = UIFont(name: "Verdana", size: 14) proteinLabel.translatesAutoresizingMaskIntoConstraints = false proteinLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true proteinLabel.topAnchor.constraint(equalTo: carbLabel.bottomAnchor).isActive = true proteinLabel.font = UIFont(name: "Verdana", size: 14) fatLabel.translatesAutoresizingMaskIntoConstraints = false fatLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true fatLabel.topAnchor.constraint(equalTo: proteinLabel.bottomAnchor).isActive = true fatLabel.font = UIFont(name: "Verdana", size: 14) sugarLabel.translatesAutoresizingMaskIntoConstraints = false sugarLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true sugarLabel.topAnchor.constraint(equalTo: fatLabel.bottomAnchor).isActive = true sugarLabel.font = UIFont(name: "Verdana", size: 14) sugarWarningLabel.translatesAutoresizingMaskIntoConstraints = false sugarWarningLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true sugarWarningLabel.topAnchor.constraint(equalTo: sugarLabel.bottomAnchor).isActive = true sugarWarningLabel.font = UIFont(name: "Verdana-Bold", size: 14) } func setupdata(){ if let fruit = fruit{ nameLabel.text = fruit.name genusLabel.text = "Genus : \(fruit.genus)" familyLabel.text = "Family : \(fruit.family)" orderLabel.text = "Order : \(fruit.order)" dividerLabel.text = "Nutritional value" let id = fruit.id let idString = String(id) idLabel.text = "ID : \(idString)" let carbs = fruit.nutritions.carbohydrates let carbString = String(carbs) carbLabel.text = "Carbohydrates : \(carbString)" let protein = fruit.nutritions.protein let proteinString = String(protein) proteinLabel.text = "Proteins : \(proteinString)" let fat = fruit.nutritions.fat let fatString = String(fat) fatLabel.text = "Fat : \(fatString)" let calories = fruit.nutritions.calories let calorieString = String(calories) caloriesLabel.text = "Calories : \(calorieString)" // 修复原代码文字错误 let sugar = fruit.nutritions.sugar let sugarString = String(sugar) sugarLabel.text = "Sugar : \(sugarString)" } } func setupDismissButton(){ view.addSubview(dismissButton) dismissButton.translatesAutoresizingMaskIntoConstraints = false dismissButton.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -50).isActive = true dismissButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true dismissButton.setTitle("Tilbake",for: .normal) dismissButton.setTitleColor(UIColor.black, for: .normal) dismissButton.addTarget(self, action: #selector(dismissAction), for: .touchUpInside) } @objc func dismissAction(){ self.dismiss(animated: true) } }
内容的提问来源于stack exchange,提问作者Jonathan S.
相关产品推荐
相关产品推荐

