#popover #ios8
#всплывающее окно #ios8
Вопрос:
Я ищу эффективный способ изменить положение всплывающего окна, используя новый uipopoverpresentationcontroller. Я успешно представил всплывающее окно, и теперь я хочу переместить его, не отклоняя и не представляя снова. У меня возникли проблемы с использованием функции:
(void)popoverPresentationController:(UIPopoverPresentationController *)popoverPresentationController
willRepositionPopoverToRect:(inout CGRect *)rect
inView:(inout UIView **)view
Я знаю, что это только начало игры, но у кого-нибудь есть пример того, как сделать это эффективно, я был бы признателен, если бы вы поделились им со мной. Заранее спасибо.
Комментарии:
1. У меня та же проблема. Мне также трудно изменить размер всплывающего окна (похоже, он игнорирует popoverLayoutMargins и popoverContentSize). Я получаю нераспознанный селектор при реализации (void) popoverPresentationController:(UIPopoverPresentationController *)popoverPresentationController willRepositionPopoverToRect:(inout CGRect )rect inView: (inout UIView *)view Я установил делегат в соответствии с документами, по-прежнему безуспешно.
2. Я понял это: установите размер в viewWillAppear
3. Хороший звонок. моя калибровка все еще работает над этим методом делегирования…
4. @mehinger Вы когда-нибудь выясняли, как перемещать uipopoverpresentationcontroller?
5. @Amendale я никогда этого не делал. Сдался и вместо этого использовал пользовательский UIView
Ответ №1:
К сожалению, это хакерское решение — единственное решение, которое я нашел:
[vc.popoverPresentationController setSourceRect:newSourceRect];
[vc setPreferredContentSize:CGRectInset(vc.view.frame, -0.01, 0.0).size];
Это временно изменяет размер содержимого представленного представления, в результате чего всплывающее окно и стрелка будут перемещены. Временное изменение размера не видно.
Похоже, это проблема, которую Apple необходимо исправить — изменение свойств sourceView
or sourceRect
UIPopoverPresentationController
ничего не делает, когда оно уже представляет всплывающее окно (без этого обходного пути).
Надеюсь, это сработает и для вас!
Комментарии:
1. Здесь та же проблема, НО в iOS7 нет probelm!
2. Похоже, что это все еще (2016, iOS 9) единственный способ заставить это работать. Вы можете
preferredContentSize
вернуть его к исходному значению, но сначала вам нужно его изменить, а это невозможноCGSizeZero
.3. Все еще требуется (2017, цель развертывания iOS 9, SDKROOT iOS 11.2, Xcode 9.2).
4. и что еще хуже, в iOS12 они сделали preferredContentSize неизменяемым, поэтому вы даже не сможете использовать этот хак, если захотите.
Ответ №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()
}
}
}
Комментарии:
1. спасибо, setneedslayout и layoutifneeded работали как шарм… вы обладаете хорошими знаниями
Ответ №3:
Я использовал тот же метод, что и в другом ответе @Rowan_Jones, однако я не хотел, чтобы размер всплывающего окна действительно менялся. Даже на доли точки. Я понял, что вы можете установить 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
, это приведет к обновлению всплывающего окна, даже если его размер фактически не изменится.
Ответ №4:
Вот пример того, как повторно ввести всплывающее окно:
- (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);
Я также использовал этот метод, чтобы убедиться, что всплывающее окно переместилось в правильное место после перемещения, установив * rect и * view на исходные sourceRect и sourceView.
В качестве дополнительного примечания я не верю, что этот метод вызывается, когда источник всплывающего окна устанавливается с помощью элемента кнопки панели.
Ответ №5:
Я публикую это, потому что у меня недостаточно баллов для голосования или комментариев. 🙂 Ответ @ turbs сработал для меня отлично. Это должен быть принятый ответ.
Установка *rect на rect, который вам нужен в методе делегирования:
(void)popoverPresentationController:(UIPopoverPresentationController *)popoverPresentationController
willRepositionPopoverToRect:(inout CGRect *)rect
inView:(inout UIView **)view
Ответ №6:
iOS 12.3
[vc.popoverPresentationController устанавливает исходный код:newSourceRect]; [vc.popoverPresentationController.containerView устанавливает необходимый список];