Как заполнить UITableView снизу вверх?

Можно ли изменить порядок таблицы. Я много искал решение, но все результаты не совсем то, что я пытаюсь достичь. Все они предлагают прокрутить до последней позиции таблицы с scrollToRowAtIndexPath и заполнение данных в обратном порядке. Но это не работает, если содержимое таблицы является динамическим, и в некоторых случаях не все ячейки имеют данные. Например, в обычном tableView порядок:


этикетка 1

ярлык 2

ярлык 3

пустой

пустой

направление прокрутки
v
В


желаемый результат будет:
направление прокрутки
^
^

пустой

пустой

пустой

ярлык 3

ярлык 2

этикетка 1


в этом примере, если я использовал предложенный метод scrollToRowAtIndexPath и использовать длину массива объектов, я бы получил только третью ячейку сверху. И в конечном итоге что-то вроде этого:


нежелательный результат:

ярлык 3

ярлык 2

этикетка 1

пустой

пустой

направление прокрутки
v
В


любая помощь будет здорово, спасибо.

12 ответов

Решение

Для заполнения таблицы снизу используйте это:

- (void)updateTableContentInset {
    NSInteger numRows = [self tableView:self.tableView numberOfRowsInSection:0];
    CGFloat contentInsetTop = self.tableView.bounds.size.height;
    for (NSInteger i = 0; i < numRows; i++) {
        contentInsetTop -= [self tableView:self.tableView heightForRowAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];
        if (contentInsetTop <= 0) {
            contentInsetTop = 0;
            break;
        }
    }
    self.tableView.contentInset = UIEdgeInsetsMake(contentInsetTop, 0, 0, 0);
}

Чтобы изменить порядок элементов, используйте это:

dataSourceArray = dataSourceArray.reverseObjectEnumerator.allObjects;

ВерсияSwift 2.2 (обновлено):

func updateTableContentInset() {
    let numRows = tableView(self.tableView, numberOfRowsInSection: 0)
    var contentInsetTop = self.tableView.bounds.size.height
    for i in 0..<numRows {
        let rowRect = self.tableView.rectForRowAtIndexPath(NSIndexPath(forItem: i, inSection: 0))
        contentInsetTop -= rowRect.size.height
        if contentInsetTop <= 0 {
            contentInsetTop = 0
        }
    }
    self.tableView.contentInset = UIEdgeInsetsMake(contentInsetTop, 0, 0, 0)
}

ВерсияSwift 3.0+/4.0 (обновлено):

func updateTableContentInset() {
    let numRows = tableView(self.tableView, numberOfRowsInSection: 0)
    var contentInsetTop = self.tableView.bounds.size.height
    for i in 0..<numRows {
        let rowRect = self.tableView.rectForRow(at: IndexPath(item: i, section: 0))
        contentInsetTop -= rowRect.size.height
        if contentInsetTop <= 0 {
            contentInsetTop = 0
        }
    }
    self.tableView.contentInset = UIEdgeInsetsMake(contentInsetTop, 0, 0, 0)
}

Первый обратный просмотр

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

затем обратная ячейка в ячейке создания.

- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;

    ...

    cell.contentView.transform = CGAffineTransformMakeScale (1,-1);

Swift 4.0 и 4.2 версии

Первый обратный UITableView в viewDidLoad

override func viewDidLoad() {
        super.viewDidLoad()
        tableView.transform = CGAffineTransform(scaleX: 1, y: -1)
}

Затем переверните ячейку в cellForRowAt.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "MyTableViewCell", for: indexPath) as? MyTableViewCell else { fatalError() }

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

Не надо писать код самостоятельно. Почему бы вам не использовать ReverseExtension. Это очень просто и даст вам все необходимые результаты. Пожалуйста, следуйте этой https://github.com/marty-suzuki/ReverseExtension

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

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

Swift 3.0:

func updateTableContentInset(forTableView tv: UITableView) {
    let numSections = tv.numberOfSections
    var contentInsetTop = tv.bounds.size.height -
        (self.navigationBar?.frame.size.height ?? 0)

    for section in 0..<numSections {
        let numRows = tv.numberOfRows(inSection: section)
        let sectionHeaderHeight = tv.rectForHeader(inSection: section).size.height
        let sectionFooterHeight = tv.rectForFooter(inSection: section).size.height
        contentInsetTop -= sectionHeaderHeight + sectionFooterHeight
        for i in 0..<numRows {
            let rowHeight = tv.rectForRow(at: IndexPath(item: i, section: section)).size.height
            contentInsetTop -= rowHeight
            if contentInsetTop <= 0 {
                contentInsetTop = 0
                break
            }
        }
        // Break outer loop as well if contentInsetTop == 0
        if contentInsetTop == 0 {
            break
        }
    }
    tv.contentInset = UIEdgeInsetsMake(contentInsetTop, 0, 0, 0)
}

НОТА:

Выше код не проверен, но должен работать. Просто убедитесь, что вы справляетесь с высотой любой панели навигации или вкладки, и все будет в порядке. В приведенном выше коде я делаю это только для navbar!

Простой способ - использовать несколько строк UILabel + autolayout. -> UITableView должен изменить размер, основываясь на его содержимом (так называемый внутренний макет). Создайте свое табличное представление и установите следующий базовый класс:

class IntrinsicTableView: UITableView {

override var contentSize:CGSize {
    didSet {
        self.invalidateIntrinsicContentSize()
    }
}

override var intrinsicContentSize: CGSize {
    self.layoutIfNeeded()
    return CGSize(width: UIViewNoIntrinsicMetric, height: contentSize.height)
}

}

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

Swift 3.01 - другое решение можно повернуть и перевернуть tableView.

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

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

Я сделал в методе cellForRowAt:

let reverseIndex = myArray.count-indexPath.row-1

let currCellData = myArray.object(at: reverseIndex) 

а затем вы продолжаете работать с currCellData

     //Add these lines where you want to reload your tableView  
let indexpath = IndexPath(row: self.Array.count-1, section: 0)
                                self.tableView.scrollToRow(at: indexpath, at: .top, animated: true)
                                self.updateTableContentInset()
    
    
    
    //Add this function below
    func updateTableContentInset() {
        let numRows = self.tableView.numberOfRows(inSection: 0)
        var contentInsetTop = self.tableView.bounds.size.height
        for i in 0..<numRows {
            let rowRect = self.tableView.rectForRow(at: IndexPath(item: i, section: 0))
            contentInsetTop -= rowRect.size.height
            if contentInsetTop <= 0 {
                contentInsetTop = 0
                break
            }
        }
        self.tableView.contentInset = UIEdgeInsets(top: contentInsetTop,left: 0,bottom: 0,right: 0)
    }

Если вы хотите, чтобы каждая новая ячейка появлялась в нижней части tableView, используйте это:-1) Инвертируйте tableView: myTableView.transform = CGAffineTransform (scaleX: -1,y: -1) 2) Также инвертируйте ячейки: cell.contentView.transform = CGAffineTransform (scaleX: -1,y: -1) 3) Теперь заполните свой tabelViewDataSource в противоположном направлении, например, если вы используете массив, вы можете сделать следующее: myTableViewData.insert(<Your New Array Element>), at: 0)

Голосуйте за вас, спасибо.

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

-(void)startObservingContentSizeChanges
{
    [self.tableView addObserver:self forKeyPath:kKeyPathContentSize options:0 context:nil];
}

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if([keyPath isEqualToString:kKeyPathContentSize] && object == self.tableView)
    {
        // difference between content and table heights. +1 accounts for last row separator
        CGFloat height = MAX(self.tableView.frame.size.height - self.tableView.contentSize.height, 0) + 1;

        self.tableView.contentInset = UIEdgeInsetsMake(height, 0, 0, 0);

        // "scroll" to top taking inset into account
        [self.tableView setContentOffset:CGPointMake(0, -height) animated:NO];

    }
}

Если у вас есть массив объектов, которые вы отображаете в cellForRowAtIndexPath:допустим dataArray Вы можете изменить это, или в cellForRowAtIndexPath:Вы можете сделать что-то подобное:

NSString *yourObject = dataArray[[dataArray count] - 1 - indexPath.row];
cell.textLabel.text = yourObject

Я предполагаю, что вы храните строки в dataArray.

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