Дивна придатна поведінка перегляду в iOS11. Клітини прокручуються вгору за допомогою навігаційної анімації


116

Нещодавно я перемістив якийсь код на новий iOS 11 beta 5 SDK.

Зараз я отримую дуже заплутану поведінку від UITableView. Сам настільний вигляд не такий фантазійний. У мене є власні клітини, але здебільшого це лише для їхнього зросту.

Коли я натискаю на контролер перегляду з табличним переглядом, я отримую додаткову анімацію, де клітини "прокручуються вгору" (або, можливо, весь кадр перегляду таблиці) змінюються і вниз вздовж анімації push / pop навігації. Перегляньте gif:

хвилястий перегляд столу

Я вручну створюю tableviewв loadViewметоді та налаштуваннях автоматичні обмеження макета, щоб вони дорівнювали провідному, кінцевому, верхньому, нижньому огляду табличного перегляду. Нагляд - це кореневий вигляд контролера перегляду.

Перегляд натискання коду контролера дуже стандартний: self.navigationController?.pushViewController(notifVC, animated: true)

Цей же код забезпечує нормальну поведінку на iOS 10.

Чи можете ви, будь ласка, вказати мені на те, що не так?

EDIT: Я створив дуже простий контролер настільного перегляду, і я можу відтворити ту саму поведінку. Код:

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створюється квадратне зображення із заданим розміром і кольором.

Якщо я коментую цей рядок, я повертаюся до нормальної поведінки.

Буду вдячний за будь-які думки з цього приводу.


Можливо, це не проблема з налаштуванням панелі навігації. У мене було те саме питання (прийнята відповідь вирішила це) без будь-яких налаштувань. Я думаю, це може бути проблемою з тим, як iOS обробляє табличний перегляд, коли він створюється вручну як підпогляд, замість того, щоб використовувати UITableViewController.
Марк Леонард

2
Я бачу це поведінка тільки тоді , коли я поставив navigationBar.isTranslucentв falseіншому випадку він працює відмінно.
b_ray

5
Здається, це помилка в iOS11 GM, будь ласка, озвучте цей звіт про помилку, щоб ця проблема отримала певну увагу від Apple: openradar.appspot.com/34465226
b_ray

1
Здається, ця проблема виправлена ​​в iOS 11.2 beta. Я б не налаштовував contentInsetAdjustmentBehavior ніколи, тому що це порушує перегляд прокрутки iPhone X, не надаючи прокладки в нижній частині екрана. Внизу перегляду вмісту знаходиться під домашньою "кнопкою" iPhone X.
batu

Відповіді:


150

Це пов'язано з UIScrollView's (UITableView - підкласом UIScrollview) нового contentInsetAdjustmentBehaviorвластивості, яке встановлено .automaticза замовчуванням.

Ви можете змінити цю поведінку за допомогою наступного фрагмента у viewDidLoad будь-яких порушених контролерів:

    tableView.contentInsetAdjustmentBehavior = .never

https://developer.apple.com/documentation/uikit/uiscrollview/2902261-contentinsetadjustmentbevior


2
цей коментар до визначення UIScrollViewContentInsetAdjustmentBehavior.automatic говорить: "... для зворотної сумісності також буде налаштовано верхній і нижній вмістInset, коли огляд прокрутки належить контролеру перегляду з автоматичноAdjustsScrollViewInsets = ТАК всередині контролера навігації, незалежно від того, чи буде прокрутка перегляд можна прокручувати ". Моя теорія полягає в тому, що на вміст панелі навігації впливає встановлення фонового зображення, яке потім динамічно коригується.
Maggy Hillen

8
Ви також можете це зробити з раскадровкой. Інспектор розмірів -> Вміст вмісту -> Встановити "Ніколи".
Woongbi Kim

4
Якщо ваш вміст поширюється за панеллю вкладок, відключення tableView.contentInsetAdjustmentBehaviorможе порушити вставки
kean

4
Крім того, просто відключивши це, розташуйте індикатор прокрутки позаду (верхньої штучки) на iPhone X у краєвиді. Весь сенс такої поведінки полягає в налаштуванні області вмісту прокрутки, щоб вони були помітні на екранах, не прямокутних. Я думаю, що ми можемо бачити це лише на iPhone X Sim.
PhoneyDeveloper

8
Ця проблема була викликана помилкою в iOS 11, коли SafeAreaInsets подання контролера перегляду встановлено неправильно під час навігаційного переходу, що має бути виправлено в iOS 11.2. Установка contentInsetAdjustmentBehaviorдля .neverне великий обхідного шляху , тому що він, ймовірно , є і інші небажані побічні ефекти. Якщо ви все ж використовуєте обхідне рішення, ви повинні видалити його для версій iOS> = 11.2.
усміхборг

23

Окрім відповіді магі

ЗАВДАННЯ-С

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

Ця проблема була викликана помилкою в iOS 11, коли safeAreaInsetsпід час навігаційного переходу неправильно встановлено подання контролера перегляду, яке слід виправити в iOS 11.2. Установка contentInsetAdjustmentBehaviorдля .neverне великий обхідного шляху , тому що він, ймовірно , є і інші небажані побічні ефекти. Якщо ви все ж використовуєте обхідне рішення, ви повинні видалити його для версій iOS> = 11.2

- згаданий smileyborg (інженер програмного забезпечення в Apple)


6

Ви можете відредагувати цю поведінку одразу протягом програми, використовуючи NSProxy, наприклад, didFinishLaunchingWithOptions:

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

1
Контролер Ця система буде перерва, як і UIImagePickerController
Galway

6

Ось як мені вдалося виправити цю проблему , все ще дозволяючи 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


Спробував майже все на цій темі, і це працювало на мене. TableViewVC, вбудований у TabBarVC. Дякую!
Джош

3

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

Якщо ви просто встановили вміст contentInsetAdjustmentBehavior. Коли-небудь, вставки вмісту не будуть встановлені правильно на iPhone X, наприклад, вміст піде в нижню область, під смугами прокрутки.

Необхідно зробити дві речі:
1. не допустити анімації scrollView під натисканням / попом
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
    }
}

Що таке parentView?
PhoneyDeveloper

Основний вигляд вашого контролера перегляду, я оновив відповідь. Дякую.
El Horrible

Коли я використовую UITableViewController, tableView є поданням контролера перегляду. Також вставки повинні бути різними при обертанні пристрою. Я хочу коригування. Мені просто не подобається анімація, коли вперше з'являється tableView.
PhoneyDeveloper

У вашому випадку, оскільки UITableView - це вигляд контролера, він повинен мати safeAreaInsets.bottom = 34 (портрет), тому ви можете просто встановити tableView.contentInset = tableView.safeAreaInsets.
Ель Жахливий

Це не працює для мене. У viewDidLoad усі вставки нульові. Якщо я спробую використати цей код у viewWillLayoutSubviews, індикатор прокрутки дійсно вставляється, але сам tableView стає здатний прокручуватися горизонтально. Якщо я просто дивлюся на вставки в viewWillLayoutSubviews, не вимикаючи коригування, нижня коригуванаContentInset стає 21, і це все, що, здається, зміниться.
PhoneyDeveloper


2

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

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

Це одне вирішило мою проблему !! Дякую. Витратили занадто багато годин на це питання!
Мурат Ясар

2

Крім того, якщо ви використовуєте панель вкладок, нижня частина вставки вмісту подання колекції буде нульовою. Для цього поставте нижче код у viewDidAppear:

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

2

У моєму випадку це спрацювало (помістіть його у viewDidLoad):

self.navigationController.navigationBar.translucent = YES;

1

Видалення зайвого простору вгорі collectionViewабоtableView

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

Наведений вище код collectionViewабо tableViewпереходить під панель навігації.
Нижче коду перешкоджає перегляду колекції переходити під навігацію

    self.edgesForExtendedLayout = UIRectEdge.bottom

але я люблю використовувати нижче логіку та код для UICollectionView

Значення вставки краю застосовуються до прямокутника для зменшення або розширення області, представленої цим прямокутником. Зазвичай крайові вставки використовуються під час макета перегляду для зміни кадру зображення. Позитивні значення приводять (або скорочують) кадр на вказану кількість. Негативні значення спричинюють (або розширюють) кадр на вказану кількість.

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

Найкращий спосіб для UICollectionView

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

0

Видалити цей код працює для мене

self.edgesForExtendedLayout = UIRectEdgeNone

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

Я використовував UISearchController зі спеціальними результатами контролерів, які мають подання таблиці. Натискання нового контролера на контролер результатів змусило перегляд таблиці перейти до пошуку.

Перелічений вище код повністю усунув проблему

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.