How to make UIPopoverController keep same position after rotating?

前端 未结 13 1143
粉色の甜心
粉色の甜心 2021-01-30 18:21

I can\'t keep popover the same position on the screen after rotation. Is there any good way to do that, because just setting some frame to popover works terrible after rotating.

13条回答
  •  无人共我
    2021-01-30 18:38

    For iOS > 8 John Strickers answer helped but didn't do what I wanted it to do.

    Here's the solution that worked for me. (If you want to download a full sample project it's here: https://github.com/appteur/uipopoverExample)

    I created a property to hold any popover I wanted to present and also added a property to track the sourceRect and another for the view of the button I wanted the popover arrow to point at.

    @property (nonatomic, weak) UIView *activePopoverBtn;
    @property (nonatomic, strong) PopoverViewController *popoverVC;
    @property (nonatomic, assign) CGRect sourceRect; 
    

    The button that triggered my popover is in a UIToolbar. When tapped it runs the following method that creates and launches the popover.

    -(void) buttonAction:(id)sender event:(UIEvent*)event
    {
        NSLog(@"ButtonAction");
    
        // when the button is tapped we want to display a popover, so setup all the variables needed and present it here
    
        // get a reference to which button's view was tapped (this is to get 
        // the frame to update the arrow to later on rotation)
        // since UIBarButtonItems don't have a 'frame' property I found this way is easy
        UIView *buttonView          = [[event.allTouches anyObject] view];
    
        // set our tracker properties for when the orientation changes (handled in the viewWillTransitionToSize method above)
        self.activePopoverBtn       = buttonView;
        self.sourceRect             = buttonView.frame;
    
        // get our size, make it adapt based on our view bounds
        CGSize viewSize             = self.view.bounds.size;
        CGSize contentSize          = CGSizeMake(viewSize.width, viewSize.height - 100.0);
    
        // set our popover view controller property
        self.popoverVC = [[UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]] instantiateViewControllerWithIdentifier:@"PopoverVC"];
    
        // configure using a convenience method (if you have multiple popovers this makes it faster with less code)
        [self setupPopover:self.popoverVC
            withSourceView:buttonView.superview // this will be the toolbar
                sourceRect:self.sourceRect
               contentSize:contentSize];
    
        [self presentViewController:self.popoverVC animated:YES completion:nil];
    
    }
    

    The 'setupPopover:withSourceView:sourceRect:contentSize method is simply a convenience method to set the popoverPresentationController properties if you plan to display multiple popovers and want them configured the same. It's implementation is below.

    // convenience method in case you want to display multiple popovers
    -(void) setupPopover:(UIViewController*)popover withSourceView:(UIView*)sourceView sourceRect:(CGRect)sourceRect contentSize:(CGSize)contentSize
    {
        NSLog(@"\npopoverPresentationController: %@\n", popover.popoverPresentationController);
    
        popover.modalPresentationStyle = UIModalPresentationPopover;
        popover.popoverPresentationController.delegate = self;
        popover.popoverPresentationController.sourceView                = sourceView;
        popover.popoverPresentationController.sourceRect                = sourceRect;
        popover.preferredContentSize                                    = contentSize;
        popover.popoverPresentationController.permittedArrowDirections  = UIPopoverArrowDirectionDown;
        popover.popoverPresentationController.backgroundColor           = [UIColor whiteColor];
    }
    

    For iOS 8 and up the viewWillTransitionToSize:withTransitionCoordinator get's called on the view controller when the device rotates.

    I implemented this method in my presenting view controller class as shown below.

    // called when rotating a device
    - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator
    {
        NSLog(@"viewWillTransitionToSize [%@]", NSStringFromCGSize(size));
    
        // resizes popover to new size and arrow location on orientation change
        [coordinator animateAlongsideTransition:^(id  _Nonnull context)
        {
            if (self.popoverVC)
            {
                // get the new frame of our button (this is our new source rect)
                CGRect viewframe = self.activePopoverBtn ? self.activePopoverBtn.frame : CGRectZero;
    
                // update our popover view controller's sourceRect so the arrow will be pointed in the right place
                self.popoverVC.popoverPresentationController.sourceRect = viewframe;
    
                // update the preferred content size if we want to adapt the size of the popover to fit the new bounds
                self.popoverVC.preferredContentSize = CGSizeMake(self.view.bounds.size.width -20, self.view.bounds.size.height - 100);
            }
    
        } completion:^(id  _Nonnull context) {
            // anything you want to do when the transition completes
        }];
    }
    

提交回复
热议问题