Как заставить UIPopoverController удерживать ту же позицию после вращения? - PullRequest
21 голосов
/ 30 января 2012

Я не могу держать поповер на той же позиции на экране после поворота. Есть ли какой-нибудь хороший способ сделать это, потому что просто установка некоторого кадра на поповер работает ужасно после поворота. popover.frame = CGRectMake(someFrame); После поворота поповер выглядит хорошо, только если он находится в центре экрана.

Ответы [ 13 ]

29 голосов
/ 17 апреля 2013

У Apple есть вопросы и ответы именно по этому вопросу.Вы можете найти подробности здесь:

Технические вопросы и ответы QA1694 Обработка поповерных контроллеров во время изменения ориентации

В основном, метод объясняет, что в методе didRotateFromInterfaceOrientation контроллера вашего представления выпредставит всплывающее окно снова следующим образом:

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
    [aPopover presentPopoverFromRect:targetRect.frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}

Для получения дополнительной информации ознакомьтесь с приведенной выше статьей, а также Справочник по классам UIPopoverController :

Если пользователь поворачивает устройство, когда всплывающее окно видно, контроллер всплывающего окна скрывает всплывающее окно и затем показывает его снова в конце поворота.Контроллер всплывающих окон пытается расположить поповер надлежащим образом для вас, но вам, возможно, придется представить его снова или скрыть его в некоторых случаях.Например, при отображении из элемента панели кнопок контроллер поповер автоматически регулирует положение (и, возможно, размер) панели для учета изменений в положении элемента кнопки панели.Тем не менее, если вы удалите элемент панели кнопок во время поворота, или если вы представили поповер из целевого прямоугольника на виде, контроллер поповер не будет пытаться переместить поповер.В этих случаях вы должны вручную скрыть всплывающее окно или снова представить его из соответствующей новой позиции.Вы можете сделать это в didRotateFromInterfaceOrientation: метод контроллера представления, который вы использовали для представления всплывающего окна.

16 голосов
/ 09 октября 2014

Начиная с iOS 8.0.2 willRotateToInterfaceOrientation не будет иметь никакого эффекта . Как упоминал mhrrt, вам нужно использовать метод делегата:

- (void)popoverController:(UIPopoverController *)popoverController willRepositionPopoverToRect:(inout CGRect *)rect inView:(inout UIView *__autoreleasing *)view

Так, например, если вы хотите, чтобы ваш поповер появлялся непосредственно под нажатой кнопкой, вы должны использовать следующий код:

- (void)popoverController:(UIPopoverController *)popoverController willRepositionPopoverToRect:(inout CGRect *)rect inView:(inout UIView *__autoreleasing *)view
{
   CGRect rectInView = [self.theButton convertRect:self.theButton.frame toView:self.view];
   *rect = CGRectMake(CGRectGetMidX(rectInView), CGRectGetMaxY(rectInView), 1, 1);
   *view = self.view;
}
6 голосов
/ 03 февраля 2014

В iOS 7 вы можете использовать - (void)popoverController:(UIPopoverController *)popoverController willRepositionPopoverToRect:(inout CGRect *)rect inView:(inout UIView *__autoreleasing *)view, чтобы изменить представление вашего UIPopoverController об изменении ориентации интерфейса.

См. Документацию UIPopoverControllerDelegate .

5 голосов
/ 30 января 2012

Вы можете сделать это в методе didRotateFromInterfaceOrientation: контроллера представления, который вы использовали для представления всплывающего окна.

Используйте метод setPopoverContentSize:animated: для установки размера всплывающего окна.

2 голосов
/ 25 июля 2017

Для Свифта:

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
}
2 голосов
/ 10 января 2017

UIPopoverController устарела в ios9 в пользу UIPopoverPresentationController , представленного в ios8. (Я прошел этот переход также при переходе от UIActionSheet к UIAlertController.) У вас есть два варианта (пример в obj-C):

A. Реализуйте метод UIViewController ниже (UIKit вызывает этот метод перед изменением размера представления представленного контроллера представления).

- (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. В качестве альтернативы, при настройке UIPopoverPresentationController для представления также установите его делегат. например Ваш представляющий vc может реализовать UIPopoverPresentationControllerDelegate и назначить себя в качестве делегата. Затем реализуйте метод делегата:

- (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;
}
2 голосов
/ 09 февраля 2016

Я пытался просто установить новый прямоугольник (rect.initialize (...)), и он работает.

func popoverPresentationController(popoverPresentationController: UIPopoverPresentationController, willRepositionPopoverToRect rect: UnsafeMutablePointer<CGRect>, inView view: AutoreleasingUnsafeMutablePointer<UIView?>) {

        if popoverPresentationController.presentedViewController.view.tag == Globals.PopoverTempTag
        {
            rect.initialize(getForPopupSourceRect())
        }
    }
1 голос
/ 19 мая 2012

У меня есть похожая проблема, которую я решаю этим

[myPop presentPopoverFromRect:myfield.frame inView:myscrollview permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];

Где myfield - это кадр, из которого вы хотите показать свой поповер, а myscrollview - это контейнерное представление, в котором вы добавляете свой поповер в качестве подпредставления.(в моем случае это мой scrollview, вместо того, чтобы ставить inView:self.view, я использую inView:myscrollview).

0 голосов
/ 28 мая 2019
  1. Инициализация контроллера PopOver

    var popoverContent: PopoverContentViewController?
    
  2. Определение записи для контроллера PopOver

    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. Текущий контроллер PopOver

    self.present (popoverContent, animated: true, завершение: nil)

  4. Напишите ниже метод и назначьте новый размер для popover:

    переопределить функциюviewWillTransition (для размера: CGSize, с координатором: UIViewControllerTransitionCoordinator) {let popover = popoverContent? .popoverPresentationController!popover? .sourceRect = CGRect (x: size.width / 2, y: size.height / 2, ширина: 0, высота: 0)}

0 голосов
/ 12 октября 2018

У меня есть popoverPresentationController, который я представляю в представлении с «поддельной» панелью навигации. Поэтому я не могу прикрепить popoverPresentationController к barButtonItem. Мое всплывающее окно отображается в нужном месте, но не отображается при повороте экрана.

Так что почему-то popoverPresentationController(_ popoverPresentationController: UIPopoverPresentationController, willRepositionPopoverTo rect: UnsafeMutablePointer<CGRect>, in view: AutoreleasingUnsafeMutablePointer<UIView>) мне не звонят.

Чтобы обойти это (iOS 12, Swift 4.2), я добавил ограничения на всплывающее окно в закрытии завершения при вызове подарка. Теперь мое всплывающее окно остается там, где я ожидал бы этого.

                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
                }
            }
        }
...