移除箭头后UIPopoverPresentationController动画失效问题求助
移除箭头后UIPopoverPresentationController动画失效问题求助
兄弟,我之前也踩过这个一模一样的坑!当时为了去掉popover的箭头,直接设置了permittedArrowDirections = UIPopoverArrowDirection(rawValue: 0),结果发现popover直接生硬地出现和消失,完全没了原来的平滑展开/收起动画,折腾了好半天才搞懂原因。
问题根源
其实当你把permittedArrowDirections设为无箭头方向时,UIKit会判定这是一个“非标准”的popover配置——它默认的动画逻辑依赖于箭头的锚点来计算展开/收起的过渡效果,一旦没有允许的箭头方向,UIKit就直接跳过了默认动画,变成瞬时显示/隐藏了。
亲测有效的解决方案
我后来用自定义UIPopoverBackgroundView的方法解决了,核心思路是:让UIKit认为这是一个有箭头的标准popover,但把箭头的尺寸设为0,这样既保留动画,又看不到箭头。
具体步骤如下:
- 创建一个自定义的
UIPopoverBackgroundView子类,把箭头的宽高设为0,同时实现所有必要的重写方法:
class NoArrowPopoverBackgroundView: UIPopoverBackgroundView { // 把箭头的宽高设为0,直接隐藏 static let arrowHeight: CGFloat = 0 static let arrowWidth: CGFloat = 0 static let contentInsets = UIEdgeInsets.zero // 随便返回一个箭头方向,让UIKit认为有合法的箭头配置 override var arrowDirection: UIPopoverArrowDirection { get { .up } set {} // 忽略外部设置的箭头方向 } override var arrowOffset: CGFloat { get { 0 } set {} // 忽略箭头偏移 } override init(frame: CGRect) { super.init(frame: frame) backgroundColor = .clear // 或者和你的popover背景色保持一致 } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } // 重写类方法返回箭头尺寸 override class func arrowHeight() -> CGFloat { return arrowHeight } override class func arrowWidth() -> CGFloat { return arrowWidth } override class func contentViewInsets() -> UIEdgeInsets { return contentInsets } override func layoutSubviews() { super.layoutSubviews() // 确保所有子视图(包括潜在的箭头视图)都隐藏 subviews.forEach { $0.isHidden = true } } }
- 在配置popover的时候,不要设置无箭头方向,而是指定任意一个合法的箭头方向,同时把自定义的背景视图类赋值给popover:
// 假设你已经创建了要弹出的popover视图控制器 let popoverVC = YourPopoverContentViewController() popoverVC.modalPresentationStyle = .popover if let popoverPresenter = popoverVC.popoverPresentationController { popoverPresenter.sourceView = yourTriggerView // 你的触发视图 popoverPresenter.sourceRect = yourTriggerView.bounds // 触发区域 // 随便指定一个箭头方向,UIKit需要这个来启用默认动画 popoverPresenter.permittedArrowDirections = .up // 设置自定义的无箭头背景视图 popoverPresenter.popoverBackgroundViewClass = NoArrowPopoverBackgroundView.self } // 弹出popover,动画设为true present(popoverVC, animated: true)
为什么这个方法有效?
因为UIKit会检查permittedArrowDirections是否有合法值,只要有,它就会执行默认的展开/收起动画;而我们的自定义背景视图把箭头的尺寸设为0,同时隐藏了所有箭头相关的视图,最终呈现出来的就是没有箭头但保留动画的popover。
之前你尝试自定义UIPopoverBackgroundView可能没成功,大概率是因为没有正确实现所有必要的重写方法(比如arrowHeight、arrowWidth这些类方法),或者没有设置合法的permittedArrowDirections,导致UIKit还是没有触发默认动画。
内容来源于stack exchange
相关产品推荐
相关产品推荐

