it-roy-ru.com

Странное поведение uitableview в iOS11. Клетки прокручиваются вверх с навигацией Push анимации

Недавно я перенес код в новый iOS 11 beta 5 SDK.

Теперь я получаю очень запутанное поведение от UITableView. Само представление за столом не так уж и красиво. У меня есть пользовательские ячейки, но в большинстве случаев это только для их роста.

Когда я нажимаю свой контроллер представления с табличным представлением, я получаю дополнительную анимацию, где ячейки "прокручиваются" (или, возможно, изменяется весь кадр табличного представления) и вниз вдоль анимации навигации Push/Pop. Пожалуйста, смотрите GIF:

wavy tableview

Я вручную создаю tableview в методе loadView и настраиваю автоматические ограничения макета, чтобы они равнялись ведущему, конечному, верхнему, нижнему суперпредставлению табличного представления. Суперпредставление является корневым представлением контроллера представления.

Просмотр кода push-контроллера очень стандартен: self.navigationController?.pushViewController(notifVC, animated: true)

Этот же код обеспечивает нормальное поведение на iOS 10.

Не могли бы вы указать мне, что не так?

Правка: я сделал очень простой контроллер таблицы и я могу воспроизвести там то же самое поведение. Код:

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)
    }
}

Правка 2: я смог сузить вопрос до моей настройки UINavigationBar. У меня есть настройки как это:

rootNavController.navigationBar.setBackgroundImage(createFilledImage(withColor: .white, size: 1), for: .default)

где createFilledImage создает квадратное изображение с заданным размером и цветом.

Если я закомментирую эту строку, я вернусь к нормальному поведению.

Буду признателен за любые мысли по этому вопросу.

115
iur

Это связано с UIScrollView's (UITableView является подклассом UIScrollview) new contentInsetAdjustmentBehavior свойство, которое по умолчанию установлено в .automatic.

Вы можете переопределить это поведение с помощью следующего фрагмента в viewDidLoad любых задействованных контроллеров:

    tableView.contentInsetAdjustmentBehavior = .never

https://developer.Apple.com/documentation/uikit/uiscrollview/2902261-contentinsetadjustmentbehavior

143
Maggy Hillen

В дополнение к ответу Мэгги

Objective-C

if (@available(iOS 11.0, *)) {
    scrollViewForView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}

Эта проблема была вызвана ошибкой в ​​iOS 11, когда safeAreaInsets представления контроллера представления были установлены неправильно во время перехода навигации, что должно быть исправлено в iOS 11.2. Установка contentInsetAdjustmentBehavior в .never не очень хороший обходной путь, потому что он, вероятно, будет иметь другие нежелательные побочные эффекты. Если вы используете обходной путь, вы должны обязательно удалить его для версий iOS> = 11.2

- упомянуто smileyborg (разработчик программного обеспечения в Apple)

21
Lal Krishna

Вы можете редактировать это поведение сразу во всем приложении, используя NSProxy, например, didFinishLaunchingWithOptions:

if (@available(iOS 11.0, *)) {
      [UIScrollView appearance].contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
} 
7
BigDanceMouse

Вот как мне удалось решить эту проблему , в то же время позволяя iOS 11 автоматически устанавливать вставки . Я использую UITableViewController.

  • Выберите "Расширить края под верхними панелями" и "Расширить края под непрозрачными панелями" в контроллере представления в раскадровке (или программно ). Вставки в безопасном месте не позволят вашему взгляду попасть под верхнюю планку.
  • Проверьте кнопку "Вставки в безопасную область" в представлении таблицы в раскадровке. (или tableView.insetsContentViewsToSafeArea = true) - Это может быть не нужно, но это то, что я сделал.
  • Установите для параметра настройки вставки содержимого значение "Прокручиваемые оси" (или tableView.contentInsetAdjustmentBehavior = .scrollableAxes) - .always также может работать, но я не тестировал.

Еще одна вещь, чтобы попробовать, если ничего не помогает:

Переопределите метод viewSafeAreaInsetsDidChangeUIViewController, чтобы заставить табличное представление принудительно установить вставки представления прокрутки в вставки безопасной области. Это связано с установкой "Никогда" в ответе Мэгги.

- (void)viewSafeAreaInsetsDidChange {
    [super viewSafeAreaInsetsDidChange];
    self.tableView.contentInset = self.view.safeAreaInsets;
}

Примечание: self.tableView и self.view должны быть одинаковыми для UITableViewController

4
Santa Claus

Это больше похоже на ошибку, чем намеченное поведение. Это происходит, когда панель навигации не является полупрозрачной или когда задано фоновое изображение.

Если вы просто установите для свойства contentInsetAdjustmentBehavior значение .never, вставки содержимого не будут правильно установлены на 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
    }
}
3
El Horrible

Также, если вы используете панель вкладок, нижняя вставка содержимого представления коллекции будет нулевой. Для этого поместите код ниже в viewDidAppear:

if #available(iOS 11, *) {
    tableView.contentInset = self.collectionView.safeAreaInsets
}
2
hasankose

пожалуйста, убедитесь, что наряду с кодом выше, добавьте дополнительный код следующим образом. Это решило проблему

override func viewDidLayoutSubviews() { 
     super.viewDidLayoutSubviews() 
     tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) // print(thisUISBTV.adjustedContentInset) 
}
2
Basavaraj Kalaghatagi

Я могу воспроизвести ошибку для iOS 11.1, но, похоже, ошибка исправлена ​​с iOS 11.2. Смотрите http://openradar.appspot.com/34465226

2
Linda

В моем случае это сработало (поместите его в viewDidLoad):

self.navigationController.navigationBar.translucent = YES;
1
nemissm

Удалить этот код работает для меня

self.edgesForExtendedLayout = UIRectEdgeNone
0
weiminghuaa
  if #available(iOS 11, *) {
        self.edgesForExtendedLayout = UIRectEdge.bottom
  }

Я использовал UISearchController с пользовательскими ResultsControllers, который имеет табличное представление. Нажатие нового контроллера на контроллере результатов привело к поиску таблицы.

Код, указанный выше, полностью устранил проблему

0
Vitalii Shvetsov

Удаление лишнего пробела в верхней части collectionView или tableView

    if #available(iOS 11.0, *) {
        collectionView.contentInsetAdjustmentBehavior  = .never
        //tableView.contentInsetAdjustmentBehavior  = .never
    } else {
        automaticallyAdjustsScrollViewInsets = false
    }

Над кодом collectionView или tableView находится под панелью навигации.
Приведенный ниже код не позволяет представлению коллекции переходить под навигацию.

    self.edgesForExtendedLayout = UIRectEdge.bottom

но я люблю использовать ниже логику и код для ICollectionView

Значения вставки края применяются к прямоугольнику, чтобы уменьшить или расширить область, представленную этим прямоугольником. Как правило, вставки Edge используются во время компоновки вида для изменения рамки вида. Положительные значения приводят к вставке (или уменьшению) кадра на указанную величину. Отрицательные значения приводят к смещению (или расширению) кадра на указанную величину.

collectionView.contentInset = UIEdgeInsets(top: -30, left: 0, bottom: 0, right: 0)
//tableView.contentInset = UIEdgeInsets(top: -30, left: 0, bottom: 0, right: 0)

Лучший способ для ICollectionView

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        return UIEdgeInsets(top: -30, left: 0, bottom: 0, right: 0)
}
0
Nazmul Hasan