#ios #uibarbuttonitem #uipopovercontroller
#iOS #элемент uibarbuttonitem #uipopovercontroller
Вопрос:
Я заметил в проекте, что расположение всплывающего окна над элементом кнопки правой панели по какой-то причине смещено вправо. Я попытался вместо этого использовать UIButton для пользовательского представления, а затем представить всплывающее окно с помощью этой кнопки, но всплывающее окно, похоже, игнорирует showFromRect, если я действительно предоставляю ему значение ‘centered’.
Код, лежащий в основе этого, довольно прост:
- (void)viewDidLoad {
[super viewDidLoad];
UIBarButtonItem *button = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"share"] style:UIBarButtonItemStylePlain target:self action:@selector(shareTap:)];
self.navigationItem.rightBarButtonItem = button;
}
- (void)shareTap:(UIBarButtonItem *)button {
self.popover = [[UIPopoverController alloc] initWithContentViewController:[[UIViewController alloc] init]];
[self.popover presentPopoverFromBarButtonItem:button permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
}
Теперь, если я переключусь на использование внутренней кнопки, как уже упоминалось, я вижу аналогичное поведение (обратите внимание на изменение цвета, чтобы отображалось изображение).
Код для этого по-прежнему довольно прост:
- (void)viewDidLoad {
[super viewDidLoad];
UIButton *innerButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 22, 22)];
[innerButton setImage:[UIImage imageNamed:@"share"] forState:UIControlStateNormal];
[innerButton addTarget:self action:@selector(shareTap:) forControlEvents:UIControlEventTouchUpInside];
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:innerButton];;
}
- (void)shareTap:(UIButton *)button {
self.popover = [[UIPopoverController alloc] initWithContentViewController:[[UIViewController alloc] init]];
// CGRect bottomCenter = CGRectMake(button.frame.size.width / 2, button.frame.size.height, 1, 1);
CGRect bottomCenter = CGRectMake(2, button.frame.size.height, 1, 1);
[self.popover presentPopoverFromRect:bottomCenter inView:button permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
}
Обратите внимание, что вместо фактического центра я использовал произвольное значение 2. Если я использую 1 или 0, всплывающее окно выравнивается по левому краю. Все, что больше единицы, снова выравнивается по правому краю.
Я немного поискал в поисках похожего вопроса, но, похоже, не могу найти никого с такой же проблемой. Любая идея о том, что вызывает это или как этого избежать, была бы высоко оценена. Единственное, о чем я смог догадаться, это то, что из-за его близости к краю Apple делает некоторые позиционирующие вуду, чтобы заставить его быть там, где они этого хотят. Проблема в том, что кнопка в правом верхнем углу выглядит как довольно стандартное выпадающее положение.
Редактировать: я подтвердил, что такое же поведение происходит при длительном нажатии на значок «Новое сообщение» в приложении «Родная почта».
Редактировать 2: я смог подтвердить Apple, что это проблема. В одной из более поздних версий (я не могу вспомнить, какой, я думаю, одной из 9-х) они сделали так, чтобы вы могли установить это вручную. Я полагаю, что поведение по умолчанию по-прежнему неверно (я не пробовал это какое-то время), но вы можете использовать метод смещения CGRect, чтобы заставить его работать правильно, если вы так склонны.
Комментарии:
1. Попробуйте этот UIBarButtonItem *button = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:цель действия UIBarButtonSystemItem:self action:@selector (Общий доступ:)];
2. Не могли бы вы объяснить немного больше? Использование системного элемента само по себе не исправляет размещение кнопки, и в моем редактировании я упомянул, что приложения по умолчанию также демонстрируют проблему (Почта), которые предположительно используют системные значки.
Ответ №1:
Вот один из способов сделать это: вместо того, чтобы использовать UIBarButtonSystemItem
, используйте UIBarButtonItem
с пользовательским представлением. Просто перетащите UIButton
в UINavigationBar
, чтобы получить UIBarButtonItem
со встроенным UIButton
, который отображается как UIBarButtonItem
пользовательский вид.
@IBAction func didTapActionButton(_ sender: Any) {
if let vc = self.storyboard?.instantiateViewController(withIdentifier: "myPopover") {
vc.modalPresentationStyle = .popover
guard let innerView = actionButton.customView else {
// Unexpected missing custom view
return
}
vc.popoverPresentationController?.sourceView = navigationController?.navigationBar
vc.popoverPresentationController?.sourceRect = innerView.frame
self.present(vc, animated: true, completion: nil)
}
}
Комментарии:
1. Я думаю, вы могли заметить, что это исправлено после iOS 9. Я упоминал в начале своего поста, что даже UIButton не работал, но позже (при редактировании) Apple обновила его, чтобы вы могли исправить позиционирование с помощью UIButton.
2. У меня была проблема со смещением стрелки всплывающего окна, которую вы описали изначально в проекте на iOS 10, и это было для меня исправлением — я предполагаю, что вы говорите, что этот метод не будет работать на iOS 9, где присутствовала ошибка. Я этого не пробовал.
Ответ №2:
Вы должны указать рамку кнопки панели, из которой должно быть представлено всплывающее окно.
Следующий код представляет UIAlertController
как всплывающее окно из кнопки панели.
@IBOutlet weak var playerRightBarButton: UIBarButtonItem!
extension UIBarButtonItem {
var frame: CGRect? {
guard let view = self.value(forKey: "view") as? UIView else {
return nil
}
return view.frame
}
}
let alert = UIAlertController(title: "", message: "Sample PopOver",
preferredStyle: .actionSheet)
if alert.responds(to: #selector(getter: popoverPresentationController)) {
alert.popoverPresentationController?.sourceView = self.view
alert.popoverPresentationController?.barButtonItem = playerRightBarButton
alert.popoverPresentationController?.permittedArrowDirections = .up
if let frame = playerRightBarButton.frame {
alert.popoverPresentationController?.sourceRect = frame
}
}
self.present(alert, animated: true, completion: nil)
Комментарии:
1. Я не совсем уверен, но я не думаю, что это связано с моим вопросом. Как это влияет на размещение стрелки? Какой «фрейм» вы имеете в виду для настройки? Вы говорите о добавлении этого метода расширения в класс UIBarButtonItem?
2. Расширение предоставляет вам рамку кнопки. Когда мы устанавливаем фрейм, из которого необходимо представить всплывающее окно, он соответствующим образом центрируется. Я привел пример AlertController, представляющего собой всплывающее окно в iPad.