How to make UIPopoverController keep same position after rotating?

前端 未结 13 1122
粉色の甜心
粉色の甜心 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:47

    For Swift:

    func popoverPresentationController(_ popoverPresentationController: UIPopoverPresentationController, willRepositionPopoverTo rect: UnsafeMutablePointer<CGRect>, in view: AutoreleasingUnsafeMutablePointer<UIView>)
    {
        rect.pointee = CGRect(x: self.view.frame.size.width, y: 0, width: 1, height: 1) // Set new rect here
    }
    
    0 讨论(0)
  • 2021-01-30 18:48

    I have popoverPresentationController that I present on a view that has a "fake" nav bar. So I can't attach the popoverPresentationController to a barButtonItem. My popup appears in the right place but does not when the screen rotates.

    So for some reason popoverPresentationController(_ popoverPresentationController: UIPopoverPresentationController, willRepositionPopoverTo rect: UnsafeMutablePointer<CGRect>, in view: AutoreleasingUnsafeMutablePointer<UIView>) does not get called for me.

    To work around this (iOS 12, Swift 4.2) I added constraints to the popup in the completion closure when calling present. Now my popup stays where I would expect it too.

                    present(viewController, animated: true) { [weak self] in
                DDLogDebug(String(describing: viewController.view.frame))
                if let containerView = viewController.popoverPresentationController?.containerView,
                let presentedView = viewController.popoverPresentationController?.presentedView,
                let imageView = self?.headerView.settingsButton {
                    withExtendedLifetime(self) {
                        let deltaY:CGFloat = presentedView.frame.origin.y - imageView.frame.maxY
                        let topConstraint = NSLayoutConstraint.init(item: presentedView, attribute: .top, relatedBy: .equal, toItem: imageView.imageView, attribute: .bottom, multiplier: 1, constant: deltaY)
                        topConstraint?.priority = UILayoutPriority(rawValue: 999)
                        topConstraint?.isActive = true
                        let heightContraint = NSLayoutConstraint.init(item: presentedView, attribute: .height, relatedBy: .equal, toItem: containerView, attribute: .height, multiplier: 0.75, constant: -deltaY)
                        heightContraint?.isActive = true
                        let leftConstraint = NSLayoutConstraint.init(item: presentedView, attribute: .left, relatedBy: .equal, toItem: containerView, attribute: .left, multiplier: 1, constant: presentedView.frame.origin.x)
                        leftConstraint.isActive = true
                        let widthConstraint = NSLayoutConstraint.init(item: presentedView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: presentedView.frame.width)
                        widthConstraint.isActive = true
                        presentedView.translatesAutoresizingMaskIntoConstraints = false
                    }
                }
            }
    
    0 讨论(0)
  • 2021-01-30 18:51
    1. Initialize PopOver Controller

      var popoverContent: PopoverContentViewController?
      
    2. Write Defination for PopOver Controller

      popoverContent = self.storyboard?.instantiateViewController(withIdentifier: "PopoverContentViewController") as? PopoverContentViewController
      popoverContent?.modalPresentationStyle = .popover
      let popover = popoverContent?.popoverPresentationController!
      popover?.delegate = self
      popoverContent?.preQuestionInfoPopUpViewDelegateObject = self
      popover?.permittedArrowDirections = UIPopoverArrowDirection()
      popover?.sourceView = self.view
      popover?.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 330, height: 330)
      
    3. Present PopOver Controller

      self.present(popoverContent, animated: true, completion:nil)

    4. Write below method and assign new size to popover:

      override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { let popover = popoverContent?.popoverPresentationController! popover?.sourceRect = CGRect(x: size.width/2, y: size.height/2, width: 0, height: 0) }

    0 讨论(0)
  • 2021-01-30 18:55

    Swift 3:

        class MyClass: UIViewController, UIPopoverPresentationControllerDelegate {
    
    
            ...
    
            var popover:UIPopoverPresentationController?
    
            ...
    
            // Where you want to set the popover...
            popover = YourViewController?.popoverPresentationController
            popover?.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0)
            popover?.delegate = self
    
            ...
    
            // override didRotate...
            override func didRotate(from fromInterfaceOrientation: UIInterfaceOrientation) {
              popover?.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0)
            }
    
    }
    
    0 讨论(0)
  • 2021-01-30 18:58

    UIPopoverController was deprecated in ios9 in favor of UIPopoverPresentationController introduced in ios8. (I went through this transition also when going from UIActionSheet to UIAlertController.) You have two choices (example in obj-C):

    A. Implement the UIViewController method below (UIKit calls this method before changing the size of a presented view controller’s view).

    - (void)viewWillTransitionToSize:(CGSize)size
               withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
            [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
            [coordinator animateAlongsideTransition:nil
                                         completion:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
                                             // Fix up popover placement if necessary, *after* the transition.
                                             // Be careful here if a subclass also overrides this method.
                                             if (self.presentedViewController) {
                                                 UIPopoverPresentationController *presentationController =
                                                         [self.presentedViewController popoverPresentationController];
                                                 UIView *selectedView = /** YOUR VIEW */;
                                                 presentationController.sourceView = selectedView.superview;
                                                 presentationController.sourceRect = selectedView.frame;
                                             }
                                         }];
        }
    

    B. Alternatively, when configuring your UIPopoverPresentationController to present, also set its delegate. e.g. your presenting vc can implement UIPopoverPresentationControllerDelegate and assign itself as the delegate. Then implement the delegate method:

    - (void)popoverPresentationController:(UIPopoverPresentationController *)popoverPresentationController
              willRepositionPopoverToRect:(inout CGRect *)rect
                                   inView:(inout UIView * _Nonnull *)view {
        UIView *selectedView = /** YOUR VIEW */;
        // Update where the arrow pops out of in the view you selected.
        *view = selectedView;
        *rect = selectedView.bounds;
    }
    
    0 讨论(0)
  • 2021-01-30 18:58

    I've tried just to set new rect (rect.initialize(...)) and it works.

    func popoverPresentationController(popoverPresentationController: UIPopoverPresentationController, willRepositionPopoverToRect rect: UnsafeMutablePointer<CGRect>, inView view: AutoreleasingUnsafeMutablePointer<UIView?>) {
    
            if popoverPresentationController.presentedViewController.view.tag == Globals.PopoverTempTag
            {
                rect.initialize(getForPopupSourceRect())
            }
        }
    
    0 讨论(0)
提交回复
热议问题