Странное поведение uitableview в iOS11. Ячейки прокручиваются вверх с помощью анимации навигации push
недавно я перенес некоторый код на новый iOS 11 beta 5 SDK.
теперь я получаю очень запутанное поведение от UITableView. Сам tableview не настолько причудлив. У меня есть пользовательские ячейки, но в большинстве случаев это только для их высоты.
когда я нажимаю контроллер вида с tableview, я получаю дополнительную анимацию, где ячейки "прокручиваются" (или, возможно, весь фрейм tableview изменен) и вниз по анимации навигации push/pop. Пожалуйста, смотрите gif:
Я вручную создать tableview
на loadView
метод и настройка ограничений автоматической компоновки должны быть равны лидирующему, трейлинговому, верхнему, нижнему супервизору tableview. Супервизор-это корневой вид контроллера вида.
контроллер просмотра, нажимающий код, очень стандартен:self.navigationController?.pushViewController(notifVC, animated: true)
тот же код обеспечивает нормальное поведение на iOS 10.
не могли бы вы мне точку в направлении того, что не так?
EDIT: я сделал очень простой контроллер tableview, и я могу воспроизвести то же поведение там. Код:
class VerySimpleTableViewController : UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 4
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = String(indexPath.row)
cell.accessoryType = .disclosureIndicator
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let vc = VerySimpleTableViewController.init(style: .grouped)
self.navigationController?.pushViewController(vc, animated: true)
}
}
EDIT 2: я смог сузить проблему до моей настройки UINavigationBar. У меня есть такая настройка:
rootNavController.navigationBar.setBackgroundImage(createFilledImage(withColor: .white, size: 1), for: .default)
здесь createFilledImage
создает квадратное изображение с заданным размером и цветом.
если я прокомментирую эту строку, я вернусь к нормальному поведению.
Я был бы признателен за любые мысли по этому вопросу.
10 ответов
это связано с UIScrollView's
(UITableView является подклассом UIScrollview) новая contentInsetAdjustmentBehavior
свойство, которое имеет значение .automatic
по умолчанию.
вы можете переопределить это поведение следующим фрагментом в viewDidLoad любых затронутых контроллеров:
tableView.contentInsetAdjustmentBehavior = .never
https://developer.apple.com/documentation/uikit/uiscrollview/2902261-contentinsetadjustmentbehavior
В дополнение к ответу Мэгги по
С
if (@available(iOS 11.0, *)) {
scrollViewForView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}
эта проблема была вызвана ошибкой в iOS 11, где
safeAreaInsets
of представление контроллера вида было установлено неправильно во время навигации переход, который должен быть исправлен в iOS 11.2. УстановкаcontentInsetAdjustmentBehavior
to.never
не лучшее решение потому что это, вероятно, будет иметь другие нежелательные побочные эффекты. Если у вас используйте обходной путь, который вы должны обязательно удалить для версий iOS >= 11.2-упомянуто smileyborg (инженер-программист в Apple)
вы можете редактировать это поведение сразу во всем приложении, используя NSProxy, например, didFinishLaunchingWithOptions:
if (@available(iOS 11.0, *)) {
[UIScrollView appearance].contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}
Это больше похоже на баг, чем планировалось. Это происходит, когда панель навигации не является полупрозрачной или когда задано фоновое изображение.
Если вы просто установите contentInsetAdjustmentBehavior в .никогда, вставки контента не будут установлены правильно на iPhone X, например, контент будет идти в нижнюю область, под полосами прокрутки.
необходимо сделать две вещи:
1. предотвращение scrollView анимации на push / pop
2. удерживать.автоматическое поведение, потому что это необходимо для iPhone X. Без этого, например, в портрете, контент будет идти ниже нижней полосы прокрутки.
новое простое решение: в XIB: просто добавьте новый UIView поверх вашего основного вида с верхним, ведущим и конечным для просмотра и высоты, установленной в 0. Вам не нужно подключать его к другим подвидам или чему-либо еще.
старое решение:
Примечание: Если вы используете UIScrollView в ландшафтном режиме, он по-прежнему не устанавливает горизонтальные вставки правильно(Еще одна ошибка?), поэтому вы должны закрепить ведущий/трейлинг scrollView в safeAreaInsets В IB.
примечание 2: Решение ниже также имеет проблему, что если tableView прокручивается вниз, и вы нажимаете контроллер и поп назад, он больше не будет внизу.
override func viewDidLoad()
{
super.viewDidLoad()
// This parts gets rid of animation when pushing
if #available(iOS 11, *)
{
self.tableView.contentInsetAdjustmentBehavior = .never
}
}
override func viewDidDisappear(_ animated: Bool)
{
super.viewDidDisappear(animated)
// This parts gets rid of animation when popping
if #available(iOS 11, *)
{
self.tableView.contentInsetAdjustmentBehavior = .never
}
}
override func viewDidAppear(_ animated: Bool)
{
super.viewDidAppear(animated)
// This parts sets correct behaviour(insets are correct on iPhone X)
if #available(iOS 11, *)
{
self.tableView.contentInsetAdjustmentBehavior = .automatic
}
}
Я могу воспроизвести ошибку для iOS 11.1, но кажется, что ошибка исправлена с iOS 11.2. См.http://openradar.appspot.com/34465226
кроме того, если вы используете панель вкладок, нижняя вставка содержимого представления коллекции будет равна нулю. Для этого поместите ниже код в viewDidAppear:
if #available(iOS 11, *) {
tableView.contentInset = self.collectionView.safeAreaInsets
}
вот как мне удалось решить эту проблему все еще позволяя iOS 11 автоматически устанавливать вставки. Я использую UITableViewController
.
- выберите "расширить края под верхними барами" и "расширить края под непрозрачными барами" в контроллере вида в раскадровке (или программно). Вставки безопасной области предотвратят ваш взгляд от идти под верхней панелью.
- Проверьте кнопку "вставки в безопасную область"на виде таблицы в раскадровке. (или
tableView.insetsContentViewsToSafeArea = true
) - это может быть не обязательно, но это то, что я сделал. - установите поведение настройки вставки содержимого в "прокручиваемые оси "(или
tableView.contentInsetAdjustmentBehavior = .scrollableAxes
) -.always
может также работать, но я не стал проверять.
еще одна вещь, чтобы попробовать, если все остальное терпит неудачу:
переопределить viewSafeAreaInsetsDidChange
UIViewController
метод, чтобы получить представление таблицы, чтобы принудительно установить вставки вида прокрутки в безопасные области. Это в сочетании с "никогда" в Мэгги по ответ.
- (void)viewSafeAreaInsetsDidChange {
[super viewSafeAreaInsetsDidChange];
self.tableView.contentInset = self.view.safeAreaInsets;
}
Примечание: self.tableView
и self.view
должно быть то же самое для UITableViewController
в моем случае это сработало (поместите его в viewDidLoad):
self.navigationController.navigationBar.translucent = YES;
пожалуйста убеждайтесь вместе с вышеуказанным кодом, добавьте дополнительный код следующим образом. Это решило проблему
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) // print(thisUISBTV.adjustedContentInset)
}