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];