it-swarm.com.ru

iOS 8 Auto высота ячейки - не удается прокрутить до последней строки

Я использую iOS 8 новые самоизмеряющиеся ячейки. Визуально это работает хорошо - каждая ячейка получает свой правильный размер. Однако, если я попытаюсь прокрутить до последней строки, табличное представление, кажется, не знает его правильный размер. Это ошибка или есть исправление?

Вот как воссоздать проблему:

Используя этот проект - TableViewCellWithAutoLayoutiOS8 (ссылается на этот SO ответ ), я получил ячейки с автоматическим изменением размера, как и ожидалось. 

Однако, если я вызываю функцию scrollToRowAtIndexPath, например:

tableView.scrollToRowAtIndexPath(NSIndexPath(forRow: model.dataArray.count - 1, inSection: 0), atScrollPosition: .Bottom, animated: true)

Я не дохожу до последнего ряда - Это только приводит меня на полпути туда. 

Даже пытаясь использовать функцию более низкого уровня, как это:

tableView.setContentOffset(CGPointMake(0, tableView.contentSize.height - tableView.frame.size.height), animated: true)

Результат не такой, как ожидалось, он не дойдет до конца. Если я нажму на него много раз или подожду несколько минут, в конечном итоге он попадет в нужное место. Кажется, что tableView.contentSize.height настроен неправильно, поэтому iOS «не знает», где находится последняя ячейка.

Буду признателен за любую помощь.

Спасибо

56
BenB

Обновление: 24 июня 2015 г.

Apple исправила большинство этих ошибок с iOS 9.0 SDK. Все проблемы исправлены в iOS 9 beta 2, включая прокрутку до верхней и нижней части табличного представления без анимации и вызов reloadData при прокрутке в середине табличного представления. 

Вот остальные проблемы, которые еще не были устранены:

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

Новый отчет об ошибке (rdar: // 21539211) был подан для этих проблем, связанных с прокруткой с анимацией.

Оригинальный ответ

Это ошибка Apple, связанная с оценкой высоты строки табличного представления, и она существует с тех пор, как эта функциональность впервые была представлена ​​в iOS 7. Я напрямую работал с инженерами Apple UIKit и евангелистами-разработчиками над этой проблемой - они признали, что это ошибка, но не имеет надежного обходного пути (если не считать отключение оценки высоты строки), и, похоже, не особенно заинтересован в ее исправлении.

Обратите внимание, что ошибка проявляется другими способами, такими как исчезновение ячеек табличного представления при вызове reloadData при прокрутке частично или полностью вниз (например, contentOffset.y значительно больше 0).

Понятно, что для ячеек с саморазмерением в iOS 8 критически важна оценка высоты строк, поэтому Apple действительно необходимо решить эту проблему как можно скорее.

Я подал эту проблему еще 21 октября 2013 года в качестве радара # 15283329. Пожалуйста, создайте дубликаты отчетов об ошибках в файлах, чтобы Apple расставила приоритеты для исправления.

Вы можете прикрепить этот простой пример проекта , чтобы продемонстрировать проблему. Он основан непосредственно на собственном примере кода Apple.

32
smileyborg

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

Вызвать функцию после небольшой (незаметной) задержки:

let delay = 0.1 * Double(NSEC_PER_SEC)
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))

dispatch_after(time, dispatch_get_main_queue(), {
  tableView.scrollToRowAtIndexPath(NSIndexPath(forRow: model.dataArray.count - 1, inSection: 0), atScrollPosition: .Bottom, animated: true)
})

Скажи мне, если это работает и для тебя.

20
abinop

Это определенно ошибка от Apple. У меня тоже есть эта проблема. Я решил эту проблему, вызвав метод "scrollToRowAtIndexPath" дважды. Пример кода:

        if array.count > 0 {
        let indexPath: NSIndexPath = NSIndexPath(forRow: array.count - 1, inSection: 0)
        self.tblView.scrollToRowAtIndexPath(indexPath, atScrollPosition: .Bottom, animated: true)
        let delay = 0.1 * Double(NSEC_PER_SEC)
        let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))

        dispatch_after(time, dispatch_get_main_queue(), {
            self.tblView.scrollToRowAtIndexPath(indexPath, atScrollPosition: .Bottom, animated: true)
        })
    }
13
Bhavesh Tiwari

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

- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString *text = [self findTextForIndexPath:indexPath];
    UIFont *font = [UIFont fontWithName:@"HelveticaNeue" size:13];
    CGRect estimatedHeight = [text boundingRectWithSize:CGSizeMake(215, MAXFLOAT)
                                                options:NSStringDrawingUsesLineFragmentOrigin
                                             attributes:@{NSFontAttributeName: font}
                                                context:nil];
    return TOP_PADDING + CGRectGetHeight(estimatedHeight) + BOTTOM_PADDING;
}

Это не идеально, но это сделало всю работу за меня. Теперь я могу позвонить:

- (void)scrollToLastestSeenMessageAnimated:(BOOL)animated
{
    NSInteger count = [self tableView:self.tableView numberOfRowsInSection:0];
    if (count > 0) {
        NSInteger lastPos = MAX(0, count-1);
        [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForItem:lastPos inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:animated];
    }
}

На viewDidLayoutSubviews и он находит правильное место внизу (или очень близко оценочную позицию).

Надеюсь, это поможет.

4
Guilherme Sprint

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

- (CGFloat) tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath

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

Надеюсь, поможет!

1
Marcus

Мое решение состояло в том, чтобы использовать размер раскадровки в качестве оценки. 

Итак, вместо этого:

- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {   
return UITableViewAutomaticDimension;

}

Я сделал что-то вроде этого:

- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath { 

MyMessageType messageType = [self messageTypeForRowAtIndexPath:indexPath];

switch (messageType) {

    case MyMessageTypeText:
        return 45;
        break;

    case MyMessageTypeMaybeWithSomeMediaOrSomethingBiggerThanJustText:
        return 96;
        break;

    default:
        break;
 }
}

Я пишу представление таблицы чата, поэтому вполне вероятно, что многие из моих ячеек, особенно этот тип текста, будут больше, чем в IB, особенно если сообщение чата очень длинное. Это выглядит довольно неплохо ... ну ... оценка и прокрутка до дна довольно близки. Кажется, что это немного хуже, поскольку прокрутка становится длиннее, но это, как я полагаю, следует ожидать

0
Roderic Campbell

У меня была такая же проблема при создании чата tableView с разной высотой ячеек. Я вызываю код ниже в методе жизненного цикла viewDidAppear ():

// First figure out how many sections there are
let lastSectionIndex = self.tableView.numberOfSections - 1

// Then grab the number of rows in the last section
let lastRowIndex = self.tableView.numberOfRowsInSection(lastSectionIndex) - 1

// Now just construct the index path
let pathToLastRow = NSIndexPath(forRow: lastRowIndex, inSection: lastSectionIndex)

// Make the last row visible
self.tableView.scrollToRowAtIndexPath(pathToLastRow, atScrollPosition: UITableViewScrollPosition.None, animated: true)

Пожалуйста, дайте мне знать, если это сработало и для вас.

0
Stefan Olaru

В окне раскадровки щелкните в пустой области, чтобы отменить выбор всех представлений, затем щелкните представление, в котором есть представление таблицы, а затем щелкните значок Resolve Auto Layout Issue и выберите Reset to Suggested Constraints

enter image description hereenter image description here

0
kendotwill

Несмотря на то, что ответ smileyborg это ошибка в iOS 8.x, она должна быть исправлена ​​на всех платформах, которые вы поддерживаете ...

Чтобы обойти это решение до iOS9, используйте следующий код без каких-либо dispatch_async или dispatch_after . Протестировано на симуляторе iOS 8.4.

UPDATE: вызов (только) layoutIfNeeded не работает, когда контроллер представления становится видимым при прокрутке UIPageViewController. Поэтому используйте вместо этого layoutSubviews (или, возможно, setNeedsLayout + layoutIfNeeded).

// For iOS 8 bug workaround.
// See https://stackoverflow.com/a/33515872/1474113
- (void)scrollToBottomForPreiOS9
{
    CGFloat originalY, scrolledY;
    do {
        // Lay out visible cells immediately for current contentOffset.
        // NOTE: layoutIfNeeded does not work when hosting UIPageViewController is dragged.
        [self.tableView layoutSubviews];
        originalY = self.tableView.contentOffset.y;
        [self scrollToBottom];  // Call -scrollToRowAtIndexPath as usual.
        scrolledY = self.tableView.contentOffset.y;
    } while (scrolledY > originalY);
}
0
ypresto

Используйте этот простой код для прокрутки снизу

 var rows:NSInteger=self.tableName.numberOfRowsInSection(0)
        if(rows > 0)
        {
            let indexPath = NSIndexPath(forRow: rows-1, inSection: 0)
            tableName.scrollToRowAtIndexPath(indexPath , atScrollPosition:  UITableViewScrollPosition.Bottom, animated: true)
        }
            }
0
Bibin Joseph

Просто вызовите tableview reloadData после того, как viewDidAppear может решить проблему

-(void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    [self.tableView reloadData];
}
0
Evan JIANG