Swift 4中Popover颜色修改求助:箭头颜色无法更改
解决Swift 4中UIPopover箭头颜色无法自定义的问题
我之前也碰到过Swift 4里UIPopover箭头颜色改不了的问题——默认API确实没提供直接修改箭头颜色的入口,只能调整按钮或popover内容区的背景色,箭头那块始终会残留白色区域。后来发现必须自定义UIPopoverBackgroundView子类才能彻底解决这个问题,下面是具体的实现方案:
步骤1:创建自定义Popover背景视图类
这个类会负责绘制统一颜色的背景和箭头,替代系统默认的背景视图:
import UIKit class CustomPopoverBackgroundView: UIPopoverBackgroundView { // 定义箭头的基础尺寸,可根据需求调整 static let arrowHeight: CGFloat = 12.0 static let arrowBase: CGFloat = 24.0 // 重写系统要求的箭头方向和偏移量属性 private var _arrowDirection: UIPopoverArrowDirection = .up private var _arrowOffset: CGFloat = 0.0 override var arrowDirection: UIPopoverArrowDirection { get { return _arrowDirection } set { _arrowDirection = newValue setNeedsLayout() } } override var arrowOffset: CGFloat { get { return _arrowOffset } set { _arrowOffset = newValue setNeedsLayout() } } override class var arrowHeight: CGFloat { return CustomPopoverBackgroundView.arrowHeight } override class var arrowBase: CGFloat { return CustomPopoverBackgroundView.arrowBase } // 用于绘制背景和箭头的视图/图层 private let backgroundView = UIView() private let arrowLayer = CAShapeLayer() override init(frame: CGRect) { super.init(frame: frame) setupSubviews() } required init?(coder: NSCoder) { super.init(coder: coder) setupSubviews() } private func setupSubviews() { // 设置你想要的统一颜色(替换成你的目标颜色) let customColor = UIColor.systemBlue backgroundView.backgroundColor = customColor arrowLayer.fillColor = customColor.cgColor addSubview(backgroundView) layer.addSublayer(arrowLayer) } override func layoutSubviews() { super.layoutSubviews() // 调整背景视图的位置,给箭头留出空间 let edgeInsets: UIEdgeInsets switch arrowDirection { case .up: edgeInsets = UIEdgeInsets(top: Self.arrowHeight, left: 0, bottom: 0, right: 0) case .down: edgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: Self.arrowHeight, right: 0) case .left: edgeInsets = UIEdgeInsets(top: 0, left: Self.arrowHeight, bottom: 0, right: 0) case .right: edgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: Self.arrowHeight) default: edgeInsets = .zero } backgroundView.frame = bounds.inset(by: edgeInsets) // 绘制箭头路径 let arrowPath = UIBezierPath() let arrowCenterX = bounds.midX + arrowOffset let arrowCenterY = bounds.midY switch arrowDirection { case .up: arrowPath.move(to: CGPoint(x: arrowCenterX, y: 0)) arrowPath.addLine(to: CGPoint(x: arrowCenterX - Self.arrowBase/2, y: Self.arrowHeight)) arrowPath.addLine(to: CGPoint(x: arrowCenterX + Self.arrowBase/2, y: Self.arrowHeight)) case .down: arrowPath.move(to: CGPoint(x: arrowCenterX, y: bounds.height)) arrowPath.addLine(to: CGPoint(x: arrowCenterX - Self.arrowBase/2, y: bounds.height - Self.arrowHeight)) arrowPath.addLine(to: CGPoint(x: arrowCenterX + Self.arrowBase/2, y: bounds.height - Self.arrowHeight)) case .left: arrowPath.move(to: CGPoint(x: 0, y: arrowCenterY)) arrowPath.addLine(to: CGPoint(x: Self.arrowHeight, y: arrowCenterY - Self.arrowBase/2)) arrowPath.addLine(to: CGPoint(x: Self.arrowHeight, y: arrowCenterY + Self.arrowBase/2)) case .right: arrowPath.move(to: CGPoint(x: bounds.width, y: arrowCenterY)) arrowPath.addLine(to: CGPoint(x: bounds.width - Self.arrowHeight, y: arrowCenterY - Self.arrowBase/2)) arrowPath.addLine(to: CGPoint(x: bounds.width - Self.arrowHeight, y: arrowCenterY + Self.arrowBase/2)) default: break } arrowPath.close() arrowLayer.path = arrowPath.cgPath } }
步骤2:在使用Popover时配置自定义背景
在触发popover的代码中,设置popoverPresentationController的popoverBackgroundViewClass为我们刚才创建的类:
@IBAction func showCustomPopover(_ sender: UIButton) { // 初始化你的Popover视图控制器 let popoverVC = YourPopoverContentViewController() popoverVC.modalPresentationStyle = .popover guard let popoverPresenter = popoverVC.popoverPresentationController else { return } popoverPresenter.sourceView = sender popoverPresenter.sourceRect = sender.bounds popoverPresenter.permittedArrowDirections = .up // 设置允许的箭头方向 // 关键:设置自定义背景视图类 popoverPresenter.popoverBackgroundViewClass = CustomPopoverBackgroundView.self // 注意:将popover内容视图的背景色设为透明,避免覆盖自定义背景 popoverVC.view.backgroundColor = .clear present(popoverVC, animated: true, completion: nil) }
额外注意事项
- 如果你需要动态修改颜色,可以给
CustomPopoverBackgroundView添加一个公开的颜色属性,在创建popover时传入目标颜色 - 代码兼容Swift 4及以上版本,无需额外适配
- 若需要支持更多箭头方向,可在
layoutSubviews中补充对应的路径绘制逻辑
内容的提问来源于stack exchange,提问作者Danf
相关产品推荐
相关产品推荐

