可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I'm using a storyboard segue that presents a view controller as popover. The seque has a custom UIView
as its anchor. On pre-iOS9 the popover would correctly point to the centre-bottom of the custom UIView
(presented below the UIView). On iOS9 it points to the top-left corner of the UIView
.
I did try to trace all selector calls to the custom UIView
to find out if there is anything I may need to implement in my custom UIView
to provide the 'hotspot' for the popover but couldn't find anything
Any ideas..? Thanks
Thanks to @Igor Camilo his reply - in case it's useful to some, this is how I fixed this in my code:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
UIPopoverPresentationController* possiblePopOver = segue.destinationViewController.popoverPresentationController;
if (possiblePopOver != nil) {
//
// iOS9 -- ensure correct sourceRect
//
possiblePopOver.sourceRect = possiblePopOver.sourceView.bounds;
}
...
}
Example: 'Short' button triggers a popover, the popover points to the top-left corner of 'Sort' control
回答1:
I had the exact same problem. I just resolved it by setting sourceRect in prepareForSegue:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
switch segue.identifier {
case "Popover Identifier"?:
if #available(iOS 9.0, *) {
segue.destinationViewController?.popoverPresentationController?.sourceRect = anchorView.bounds
}
default:
break
}
}
回答2:
Had the same issue but my app has a multitude of pop-over so I created a centralized function for the fix (but still had to use it on every view controller that had pop overs).
// Fix for IOS 9 pop-over arrow anchor bug
// ---------------------------------------
// - IOS9 points pop-over arrows on the top left corner of the anchor view
// - It seems that the popover controller's sourceRect is not being set
// so, if it is empty CGRect(0,0,0,0), we simply set it to the source view's bounds
// which produces the same result as the IOS8 behaviour.
// - This method is to be called in the prepareForSegue method override of all
// view controllers that use a PopOver segue
//
// example use:
//
// override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
// {
// fixIOS9PopOverAnchor(segue)
// }
//
extension UIViewController
{
func fixIOS9PopOverAnchor(segue:UIStoryboardSegue?)
{
guard #available(iOS 9.0, *) else { return }
if let popOver = segue?.destinationViewController.popoverPresentationController,
let anchor = popOver.sourceView
where popOver.sourceRect == CGRect()
&& segue!.sourceViewController === self
{ popOver.sourceRect = anchor.bounds }
}
}
回答3:
Here's an example of Igor Camilo's snippet in Objective-C.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// If the sender is a UIView, we might have to correct the sourceRect of
// a potential popover being presented due to an iOS 9 bug. See:
// https://openradar.appspot.com/22095792 and http://stackoverflow.com/a/32698841/368674
if ([sender isKindOfClass:UIView.class]) {
// Fetch the destination view controller
UIViewController *destinationViewController = [segue destinationViewController];
// If there is indeed a UIPopoverPresentationController involved
if ([destinationViewController respondsToSelector:@selector(popoverPresentationController)]) {
// Fetch the popover presentation controller
UIPopoverPresentationController *popoverPresentationController =
destinationViewController.popoverPresentationController;
// Set the correct sourceRect given the sender's bounds
popoverPresentationController.sourceRect = ((UIView *)sender).bounds;
}
}
}
回答4:
Here's my solution, inside prepareForSegue
:
segue.destinationViewController.popoverPresentationController?.sourceRect = CGRectMake(anchorView.frame.size.width/2, anchorView.frame.size.height, 0, 0)
This will move the pointer to the bottom middle of the anchor view
回答5:
I also encountered this problem but now it works when I added this to my PrepareForSegue function. Given that my Segue ID contains string Popover
if ([[segue identifier] containsString:@"Popover"]) {
[segue destinationViewController].popoverPresentationController.sourceRect = self.navigationItem.titleView.bounds;
}
回答6:
If you reference your popover UIViewController
in your main UIViewController
you can adjust the sourceRect
property to offset the popover. For example, given popover popoverVC
you can do something like so:
float xOffset = 10.0;
float yOffset = 5.0;
popoverVC.popoverPresentationController.sourceRect = CGMakeRect(xOffset, yOffset, 0.0, 0.0);
回答7:
Try to set width and height anchor of your source rect (UIView or UIBarButtonItem ) and set it to active .Set it when you are initialising your UIView or UIBarButtonItem.
UIBarButtonItem
[[youruibarbuttonitem.customView.widthAnchor constraintEqualToConstant:youruibarbuttonitem.customView.bounds.size.width] setActive:YES];
[[youruibarbuttonitem.customView.heightAnchor constraintEqualToConstant:youruibarbuttonitem.customView.bounds.size.height] setActive:YES];
UIView
[[uiview.widthAnchor constraintEqualToConstant:uiview.bounds.size.width] setActive:YES];
[[uiview.heightAnchor constraintEqualToConstant:uiview.bounds.size.height] setActive:YES];
回答8:
A bit of a more updated answer for Swift 3! Pardon all the casting
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "popSegue" {
let popoverViewController = segue.destination
popoverViewController.popoverPresentationController?.delegate = self
segue.destination.popoverPresentationController?.sourceRect = ((sender as? UIButton)?.bounds)!
}
}
回答9:
just to update to an actual example with working code for any UIView
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
switch segue.identifier {
case "PopoverSegueId"?:
if #available(iOS 9.0, *) {
segue.destination.popoverPresentationController?.sourceRect = (segue.destination.popoverPresentationController?.sourceView?.bounds)!
}
default:
break
}
}