UITableView привязывает строки к низу

У меня есть UITableView, который должен представить новый контент снизу. Вот как ведет себя табличное представление, когда оно заполнено и вы добавляете новые строки с анимацией.

Я начинал его, изменяя contentInset, когда вводятся строки, но затем, когда они меняются, все исчезает, и анимация входа все не так... Моя проблема с этим подходом усугубляется тем фактом, что пользователи могут удалять строки, а строки обновление содержимого, что приводит к их изменению размера (каждая строка имеет собственную высоту, которая изменяется).

Любые рекомендации о том, как сделать так, чтобы строки UITableView всегда появлялись внизу области просмотра UITableView?

8 ответов

Решение

У меня есть решение, которое работает для меня идеально, но оно вызывает двойное мышление, поэтому оно не так просто в теории, как на практике... вроде...

Шаг 1, примените преобразование к табличному виду, вращая его на 180 градусов

tableView.transform = CGAffineTransformMakeRotation(-M_PI);

Шаг 2, поверните необработанную ячейку на 180 градусов в tableView:cellForRowAtIndexPath:

cell.transform = CGAffineTransformMakeRotation(M_PI);

Шаг 3, обратный источник данных. Если вы используете NSMutableArray, вставьте новые объекты в местоположение 0 вместо использования AddObject...

Теперь сложная часть - помнить, что левый - это правый, а правый левый - только на уровне таблицы, так что если вы используете

[tableView insertRowsAtIndexPaths:targetPath withRowAnimation:UITableViewRowAnimationLeft]

теперь это должно быть

[tableView insertRowsAtIndexPaths:targetPath withRowAnimation:UITableViewRowAnimationRight]

и то же самое для удалений и т. д.

В зависимости от того, какое у вас хранилище данных, вам, возможно, придется обращаться с этим в обратном порядке...

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

Принятый метод создает проблемы для моего приложения - полоса прокрутки находится на неправильной стороне, и она искажает разделители ячеек для UITableViewStyleGrouped

Чтобы исправить это, используйте следующее

tableView.transform = CGAffineTransformMakeScale (1,-1);

а также

cell.contentView.transform = CGAffineTransformMakeScale (1,-1);
// if you have an accessory view
cell.accessoryView.transform = CGAffineTransformMakeScale (1,-1); 

Аналогичный подход к ima747, но поворот на 180 градусов также заставляет индикатор прокрутки переходить на противоположную сторону. Вместо этого я перевернул представление таблицы и ее ячейки по вертикали.

self.tableView.transform = CGAffineTransformMakeScale(1, -1); //in viewDidLoad

cell.transform = CGAffineTransformMakeScale(1, -1);//in tableView:cellForRowAtIndexPath:

Создайте заголовок таблицы, который является высотой экрана (в какой бы ориентации вы ни находились). МЕНЬШЕ - высота строк, которые вы хотите видеть. Если строк нет, то заголовок - это полная высота табличного представления. По мере добавления строк одновременно уменьшайте высоту заголовка таблицы на высоту новой строки. Это означает изменение высоты рамки представления, которое вы предоставляете для заголовка таблицы. Смысл в том, чтобы заполнить пространство над строками таблицы, чтобы создать видимость того, что строки входят снизу. Использование заголовка таблицы (или заголовка раздела) сдвигает данные таблицы вниз. Вы можете поместить все, что вам нравится, в представление заголовка, даже если оно будет пустым и прозрачным.

Это должно иметь эффект, который вы ищете, я думаю.

Посмотрите на атрибут tableHeaderView, Вы просто устанавливаете это на представление, которое вы хотите отобразить в заголовке таблицы. Затем вы можете манипулировать им по мере необходимости при добавлении строк. Я не могу вспомнить, насколько сильными должны быть вы, чтобы представление действительно обновлялось в пользовательском интерфейсе. Может быть так просто, как звонить setNeedsDisplay, если что-нибудь.

В качестве альтернативы, посмотрите на методы tableView:viewForHeaderInSection: а также tableView:heightForHeaderInSection:, Подобно использованию представления заголовка таблицы, вы захотите иметь переменную экземпляра, которую вы настроили один раз, но к которой вы можете получить доступ из этих методов, чтобы вернуть либо само представление, либо его высоту соответственно. Когда вам нужно изменить вид для (первого) раздела, вы можете использовать reloadSections:withAnimation: принудительно обновить представление на экране после изменения высоты представления (или содержимого).

Что-нибудь из этого имеет смысл? Я надеюсь, что это так.:-)

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

self.tableView.transform = CGAffineTransform.init(rotationAngle: (-(CGFloat)(Double.pi)))
self.tableView.transform = CGAffineTransform.init(translationX: -view.frame.width, y: view.frame.height)

Более простой способ - добавить следующие строки внизу cellForRowAtIndexPath

if(indexPath.section == self.noOfSections - 1)
    [self scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:([self numberOfRowsInSection:self.noOfSections -1] - 1) inSection:self.noOfSections -1] atScrollPosition:UITableViewScrollPositionBottom animated:animated];

Поздно к вечеринке, но, вдохновленный идеей @Sameh Youssef, функция для прокрутки до последней ячейки в табличном представлении, если у вас есть только один раздел. Если нет, просто верните количество разделов вместо жесткого кодирования0.

Задержка в микросекундах выбрана произвольно.

 func scrollToLast() {
        DispatchQueue.main.asyncAfter(deadline: .now() + .microseconds(5)) {
            let lastIndex = IndexPath(row: self.tableView.numberOfRows(inSection: 0) - 1, section: 0)
            if lastIndex.row != -1 {
                self.tableView.scrollToRow(at: lastIndex, at: .bottom, animated: false)
            }
        }
}

Я бы рекомендовал использовать подход, описанный в этом сообщении в блоге. Проверял на iOS 12 и 13. Работает отлично.

Я просто хотел добавить кое-что ко всем этим ответам относительно использования этого метода с UICollectionView... Иногда при аннулировании макета мои ячейки преобразовывались обратно неправильно, я обнаружил, что в подклассах UICollectionViewCell и UICollectionReusableView мне пришлось сделай это:

- (void)applyLayoutAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes {
    [super applyLayoutAttributes:layoutAttributes];
    [self setTransform:CGAffineTransformMakeScale(1, -1)];
}
dataSourceArray = dataSourceArray.reversed()

tableView.transform = CGAffineTransform(scaleX: 1, y: -1)

cell.transform = CGAffineTransform(scaleX: 1, y: -1)


func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    if let text = textField.text {
        dataSourceArray.insert(text, at: 0)
        self.tableView.reloadData()
        textField.text = ""
    }
    textField.resignFirstResponder()
    return true
}

Что ж, если вы загрузите ваш просмотр таблицы с помощью NSMutableArray, я бы предложил вам отсортировать массив в обратном порядке. Таким образом, представление таблицы будет заполнено так, как вы хотите.

Другие вопросы по тегам