IOS 8 - UIPopoverPresentationController moving popover

Я ищу эффективный способ переопределить popover с помощью нового диспетчера uipopoverpresentation. Я успешно представил popover, и теперь я хочу переместить его, не отпуская и не представляя снова. У меня возникли проблемы с использованием функции:

(void)popoverPresentationController:(UIPopoverPresentationController *)popoverPresentationController
      willRepositionPopoverToRect:(inout CGRect *)rect
                           inView:(inout UIView **)view

Я знаю это в начале игры, но у кого-нибудь есть пример того, как сделать это эффективно, я был бы признателен, если бы вы поделились им со мной. Заранее спасибо.

Ответы

Ответ 1

К сожалению, это хакерское решение - единственное решение, которое я нашел:

[vc.popoverPresentationController setSourceRect:newSourceRect];
[vc setPreferredContentSize:CGRectInset(vc.view.frame, -0.01, 0.0).size];

Это временно изменяет размер содержимого представленного представления, заставляя перемещение и стрелку перемещаться. Временное изменение размера не отображается.

Кажется, что это проблема Apple, которую нужно исправить - изменение свойств sourceView или sourceRect UIPopoverPresentationController ничего не делает, когда он уже представляет popover (без этого обходного пути).

Надеюсь, это сработает и для вас!

Ответ 2

Мне повезло, используя containerView?.setNeedsLayout() и containerView?.layoutIfNeeded() после изменения sourceRect объекта popoverPresentationController, например, так:

func movePopoverTo(_ newRect: CGRect) {
    let popover = self.presentedViewController as? MyPopoverViewController {
        popover.popoverPresentationController?.sourceRect = newRect
        popover.popoverPresentationController?.containerView?.setNeedsLayout()
        popover.popoverPresentationController?.containerView?.layoutIfNeeded()
    }
}

И даже чтобы всплывающее окно следовало за ячейкой tableView без необходимости что-либо менять:

class MyTableViewController: UITableViewController {

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "MyPopoverSegue" {
            guard let controller = segue.destination as? MyPopoverViewController else { fatalError("Expected destination controller to be a 'MyPopoverViewController'!") }
            guard let popoverPresentationController = controller.popoverPresentationController else { fatalError("No popoverPresentationController!") }
            guard let rowIndexPath = sender as? IndexPath else { fatalError("Expected sender to be an 'IndexPath'!") }
            guard myData.count > rowIndexPath.row else { fatalError("Index (\(rowIndexPath.row)) Out Of Bounds for array (count: \(myData.count))!") }
            if self.presentedViewController is MyPopoverViewController {
                self.presentedViewController?.dismiss(animated: false)
            }
            popoverPresentationController.sourceView = self.tableView
            popoverPresentationController.sourceRect = self.tableView.rectForRow(at: rowIndexPath)
            popoverPresentationController.passthroughViews = [self.tableView]
            controller.configure(myData[rowIndexPath.row])
        }
        super.prepare(for: segue, sender: sender)
    }
}

// MARK: - UIScrollViewDelegate

extension MyTableViewController {
    override func scrollViewDidScroll(_ scrollView: UIScrollView) {
        if let popover = self.presentedViewController as? MyPopoverViewController {
            popover.popoverPresentationController?.containerView?.setNeedsLayout()
            popover.popoverPresentationController?.containerView?.layoutIfNeeded()
        }
    }
}

Ответ 3

Я использовал тот же метод, что и в другом ответе @Rowan_Jones, однако я не хотел, чтобы размер popover действительно менялся. Даже на долю точки. Я понял, что вы можете установить preferredContentSize несколько раз назад, но визуально размер будет меняться только в соответствии с последним значением.

[vc.popoverPresentationController setSourceRect:newSourceRect];
CGSize finalDesiredSize = CGSizeMake(320, 480);
CGSize tempSize = CGSizeMake(finalDesiredSize.width, finalDesiredSize.height + 1);
[vc setPreferredContentSize:tempSize];
[vc setPreferredContentSize:finalDesiredSize];

Так что даже если finalDesiredSize совпадает с вашим начальным preferredContentSize, это приведет к обновлению popover, даже если размер не изменится.

Ответ 4

Вот пример того, как внедрить popover:

- (void)popoverPresentationController:(UIPopoverPresentationController *)popoverPresentationController willRepositionPopoverToRect:(inout CGRect *)rect     inView:(inout UIView **)view {

     *rect = CGRectMake((CGRectGetWidth((*view).bounds)-2)*0.5f,(CGRectGetHeight((*view).bounds)-2)*0.5f, 2, 2);

Я также использовал этот метод для обеспечения того, чтобы popover переместился в нужное место после перемещения, установив * rect и * view в исходный sourceRect и sourceView.

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

Ответ 5

Я публикую это, потому что у меня недостаточно очков для голосования или комментариев.:) Ответ @turbs отлично работал у меня. Это должен быть принятый ответ.

Настройка * rect для прямоугольника, который вам нужен в методе делегата:

(void)popoverPresentationController:(UIPopoverPresentationController *)popoverPresentationController
    willRepositionPopoverToRect:(inout CGRect *)rect     
        inView:(inout UIView **)view

Ответ 6

iOS 12.3

[vc.popoverPresentationController setSourceRect: newSourceRect]; [vc.popoverPresentationController.containerView setNeedsLayout];