iOS 11下用Swift获取UIBarButtonItem原点与Frame的方法
嘿,这个问题确实有点棘手——毕竟UIBarButtonItem本身并非UIView的子类,直接调用它的frame属性肯定行不通。不过咱们可以通过它背后对应的UI视图来获取所需的坐标和Frame,下面给你几种在iOS 11及以上版本适用的Swift实现方案:
方案一:通过KVC获取内部视图(最直接)
UIBarButtonItem在系统内部是由一个UIView实例来承载的,我们可以通过KVC的方式拿到这个私有视图,进而获取它的Frame:
// 假设你要获取右侧导航栏按钮的Frame if let targetBarButton = navigationItem.rightBarButtonItem, let buttonView = targetBarButton.value(forKey: "view") as? UIView { // 获取按钮在导航栏坐标系中的Frame和原点 let barButtonFrame = buttonView.frame print("按钮在导航栏中的Frame:\(barButtonFrame)") print("原点坐标:(\(barButtonFrame.origin.x), \(barButtonFrame.origin.y))") // 如果需要转换到屏幕坐标系的坐标 let screenFrame = buttonView.convert(buttonView.bounds, to: nil) print("按钮在屏幕中的Frame:\(screenFrame)") }
注意:虽然
"view"这个Key属于系统私有API,但在iOS 11及后续版本中稳定性较好,很多成熟的App也在使用。不过如果苹果后续修改内部实现,这个方法可能会失效,需要留意版本适配。
方案二:遍历导航栏子视图(更安全,无私有API)
如果你不想依赖私有API,可以遍历导航栏的子视图,通过标识(比如tag、标题、视图类型)找到目标按钮对应的视图:
// 提前给目标UIBarButtonItem的视图设置tag,比如创建时: // let customButton = UIButton(type: .system) // customButton.tag = 100 // let barButtonItem = UIBarButtonItem(customView: customButton) // navigationItem.rightBarButtonItem = barButtonItem // 遍历导航栏子视图查找目标 if let navBar = navigationController?.navigationBar { for subview in navBar.subviews { if let barButton = subview as? UIControl, barButton.tag == 100 { let frame = barButton.frame print("按钮Frame:\(frame)") print("原点坐标:(\(frame.origin.x), \(frame.origin.y))") break } } }
这种方法的优势是完全基于公开API,兼容性更强,但需要你提前给目标视图设置可识别的标识,或者通过视图的其他特征(比如标题文本)来匹配。
方案三:自定义UIBarButtonItem时直接获取(最稳妥)
如果你是用customView创建的自定义UIBarButtonItem,那直接访问customView的Frame就可以了,这是最稳妥的方式:
if let customButtonView = navigationItem.rightBarButtonItem?.customView { // 获取在导航栏中的Frame let frameInNavBar = customButtonView.frame print("自定义按钮在导航栏中的Frame:\(frameInNavBar)") // 转换到屏幕坐标系 let screenFrame = customButtonView.convert(customButtonView.bounds, to: nil) print("自定义按钮在屏幕中的Frame:\(screenFrame)") }
内容的提问来源于stack exchange,提问作者Preeti
相关产品推荐
相关产品推荐

