You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PopOverController自定义尺寸与sourceRect对BarButtonItem不生效的问题

问题描述

在导航栏添加系统样式刷新按钮后,点击按钮需要弹出带表视图的Popover控制器,当前实现存在两处异常:

  • 无法正确结合BarButtonItem配置PopoverController的sourceRect,弹出锚点位置偏移
  • 弹出的表视图以全屏形式展示,不符合预先设置的200x200自定义尺寸要求
现有问题实现代码
let button = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.refresh, target: self, action: #selector(displayClassRooms(_:)))
navigationItem.rightBarButtonItem = button

@objc private func displayClassRooms(_ sender: UIBarButtonItem) {
    let popController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ClassRoomVC")
    popController.modalPresentationStyle = UIModalPresentationStyle.popover
    popController.popoverPresentationController?.sourceView = self.view
    popController.popoverPresentationController?.permittedArrowDirections = .up
    popController.popoverPresentationController?.sourceRect = CGRect.init(x: 300, y: 0, width: 50, height: 180 )
    popController.preferredContentSize = CGSize.init(width: 200, height: 200)
    present(popController, animated: true, completion:nil)
}

func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
    return .none
 }
问题场景截图

弹出样式异常的问题场景

根因与修复方案

1. Popover锚点位置配置错误

原来的实现手动硬编码sourceRect的x坐标为300,既没有适配不同设备的导航栏宽度差异,也没有利用系统为UIBarButtonItem提供的自动锚定能力,永远无法精准匹配右侧按钮的位置。
正确配置方式是给popoverPresentationController直接设置barButtonItem属性为触发事件的sender,系统会自动匹配对应的sourceView、sourceRect,不需要手动计算坐标。

2. 弹出控制器被自动适配为全屏

原来的适配方法存在两个问题,完全没有生效:

  • 没有把当前视图控制器绑定为popoverPresentationController的delegate,方法根本不会被系统调用
  • 用的是iOS13之前的旧方法签名,新系统上无法被识别

系统默认在iPhone竖屏环境下,会自动把popover样式转换为全屏modal展示,直接忽略设置的preferredContentSize。修复时需要将当前VC设置为popover的代理,使用新的方法签名返回.none,阻止自动全屏行为。

修复后代码

let button = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.refresh, target: self, action: #selector(displayClassRooms(_:)))
navigationItem.rightBarButtonItem = button

@objc private func displayClassRooms(_ sender: UIBarButtonItem) {
    let popController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ClassRoomVC")
    popController.modalPresentationStyle = .popover
    // 直接绑定barButtonItem作为锚点,自动匹配正确的sourceRect/sourceView
    guard let popPC = popController.popoverPresentationController else { return }
    popPC.barButtonItem = sender
    popPC.permittedArrowDirections = .up
    // 绑定代理阻止自动适配为全屏
    popPC.delegate = self
    popController.preferredContentSize = CGSize(width: 200, height: 200)
    present(popController, animated: true)
}

// 遵循UIPopoverPresentationControllerDelegate协议,返回.none阻止全屏适配
extension YourViewController: UIPopoverPresentationControllerDelegate {
    func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
        return .none
    }
}

内容的提问来源于stack exchange,提问作者konya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.22 21:45:09