虽然我原则上同意处理此问题的正确方法是滚动您自己的 Popover,但在这种情况下,对于较新版本的操作系统而言,这不是问题。我真的想构建和维护自己的 popover 实现只是为了支持最终将无关紧要的操作系统吗?如果您真的愿意,请考虑网络上的一些免费开源实现。
我个人研究了此处建议的方法,并以此页面为起点提出了自己的方法(谢谢!)。它适用于两种情况(有或没有导航栏),并且在我看来更安全。
我没有向 UIPopoverController 添加方法,而是向我的 UIPopoverBackgroundView 添加了一个例程,以使用 RELATIVE 路由而不是 ABSOLUTE 查找有问题的视图。简而言之,由于代码直接引用了 UIPopoverBackgroundView(self),它可以向上导航(superview)然后向下导航(subviews)。
两种情况下的视图树看起来都是这样的:
使用 UINavigationBar:
没有 UINavigationBar:
我们感兴趣的两个视图是 UILayoutView 和 UIImage 视图,它们在每个图形中都是粗体和下划线的。我们可以使用下面的代码(假设为 ARC)从 UIPopoverBackgroundView 开始获得对这些的引用。我在 UIPopoverBackgroundView 实现中从 layoutSubviews 执行此操作。
// Helper method for traversing child views based solely on class types
UIView* (^__unsafe_unretained __block traverseSubviews)(UIView*, NSArray*) = ^(UIView *root, NSArray* nodeTypes) {
NSString *typeName = [nodeTypes objectAtIndex:0];
for (UIView *subView in root.subviews) {
if ([NSStringFromClass([subView class]) isEqualToString: typeName]) {
if (nodeTypes.count == 1)
return subView;
else
return traverseSubviews(subView, [nodeTypes subarrayWithRange:NSMakeRange(1, nodeTypes.count - 1)]);
}
}
return (UIView*)nil;
};
// Find the subviews of interest, taking into account there could be a navigation bar
UIView *layoutView = traverseSubviews([self superview], @[@"UIView", @"UILayoutContainerView"]);
if (traverseSubviews(layoutView, @[@"UINavigationBar"])) {
layoutView = traverseSubviews(layoutView, @[@"UILayoutContainerView"]);
}
UIView *imageView = traverseSubviews(layoutView, @[@"UIImageView"]);
// Remove the default content appearance
layoutView.layer.cornerRadius = 0;
[imageView removeFromSuperview];
我在这里使用一个块来遍历子视图以保持代码简洁。它以一个视图为起点和一个类名数组。类名数组是我期望的视图类序列,其中索引 0 是索引 1 的父级,索引 1 是索引 2 的父级,依此类推。它返回数组中最后一项表示的视图。