Отримайте сповіщення, коли UITableView закінчує запитувати дані?


108

Чи є якийсь спосіб дізнатися, коли UITableViewзакінчив запитувати дані зі свого джерела даних?

Жоден з viewDidLoad/ viewWillAppear/ viewDidAppearметодів пов'язаного контролера перегляду ( UITableViewController) тут не використовується, оскільки всі вони надто рано запускаються. Жоден з них (цілком зрозуміло) не гарантує, що запити до джерела даних на даний момент закінчені (наприклад, до прокрутки подання).

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

Однак це здається досить неприємним, оскільки я припускаю, що це викликає запит джерела даних про ту саму інформацію двічі (один раз автоматично та один раз через reloadData виклик) під час її першого завантаження.

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

При відновленні положення прокрутки ( з допомогою scrollRectToVisible:animated:), мені потрібно табличне вже є достатня кількість даних в ньому, інакше scrollRectToVisible:animated:виклик методу нічого не робить (що і відбувається , якщо ви помістіть виклик на свій власний в будь-якому з viewDidLoad, viewWillAppearабо viewDidAppear).


Здається, ви шукаєте щось подібне до цього stackoverflow.com/a/11672379/2082172 .
Тимур Кучкаров

На мій досвід, UITableView може кешувати виклики для reloadData, як і кешує дзвінки для вставки / видалення рядків та інших речей. UITableView викликає делегата джерела даних, коли він буде готовий, залежно від використання процесора та інших речей.
Walt Sellers

Відповіді:


61

Ця відповідь, здається, вже не працює через деякі зміни, внесені до реалізації UITableView з моменту написання відповіді. Дивіться цей коментар: отримуйте сповіщення, коли UITableView закінчує запитувати дані?

Я грав з цією проблемою в протягом декількох днів , і думаю , що підкласи UITableView«s reloadDataце найкращий підхід:

- (void)reloadData {

    NSLog(@"BEGIN reloadData");

    [super reloadData];

    NSLog(@"END reloadData");

}

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

Я підкласифікувати UITableViewнадсилання методів до делегата до і після reloadData. Це працює як шарм.


2
Треба сказати, це, здається, найкраще рішення. Просто реалізував це і, як ти кажеш, він працює як шарм. Дякую!
теорія

2
@EricMORAND Ви кажете, що "reloadData не закінчується до того, як таблиця закінчить перезавантажити свої дані". Чи можете ви уточнити, що ви маєте на увазі під цим? Я знаходжу цеreloadData виявляю, повертається негайно, і я бачу "END reloadData" перед тим, як клітини фактично перезавантажуються (тобто перед викликом UITableViewDataSourceметодів). Моє експериментування демонструє точну протилежність тому, що ви говорите. Я повинен неправильно зрозуміти, що ви намагаєтесь сказати.
Роб

3
Чи не є відповідь Еріка такою ж, як не реалізовувати (читати, не перекручуючи) оновлення даних, викликаючи reloaddata (що буде по суті [супер перезавантаження даних], а потім після його виклику робити те, що ви хочете, після його завершення?
Нірав Бхатт

5
Колись reloadData завершив процес завантаження до його закінчення. Але Apple в якийсь момент змінила це. Тепер клас UITableView може кешувати виклик reloadData з усіма рядками вставки та видалення викликів. Якщо ви подивитеся на декларацію @interface для UITableView, ви знайдете член NSMutableArray _reloadItems прямо під _insertItems та _deleteItems. (Мені довелося переробити код, який я успадкував через цю зміну.)
Walt Sellers,

3
Проводка коду завершення в блоці на головній черзі після виклику [super reloadData]працює для мене: dispatch_async(dispatch_get_main_queue(), ^{NSLog(@"reload complete");});. Це в основному стрибки жаб блоків, які розміщуються в таблиці reloadData.
Тімоті Муз

53

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

Нарешті, це єдине, що для мене спрацювало.

[yourTableview reloadData];

dispatch_async(dispatch_get_main_queue(),^{
        NSIndexPath *path = [NSIndexPath indexPathForRow:yourRow inSection:yourSection];
        //Basically maintain your logic to get the indexpath
        [yourTableview scrollToRowAtIndexPath:path atScrollPosition:UITableViewScrollPositionTop animated:YES];
 });

Швидке оновлення:

yourTableview.reloadData()
dispatch_async(dispatch_get_main_queue(), { () -> Void in
    let path : NSIndexPath = NSIndexPath(forRow: myRowValue, inSection: mySectionValue)
    //Basically maintain your logic to get the indexpath
    yourTableview.scrollToRowAtIndexPath(path, atScrollPosition: UITableViewScrollPosition.Top, animated: true)

})

Отже, як це працює.

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

Тестовано в iOS7 та iOS8, і це працює приголомшливо;)

Оновлення для iOS9: Це просто чудово працює і для iOS9. Я створив зразок проекту в github як POC. https://github.com/ipraba/TableReloadingNotifier

Я додаю сюди скріншот свого тесту.

Тестоване середовище: тренажер iOS9 iPhone6 ​​від Xcode7

введіть тут опис зображення


8
найкращий одяг, який я знайшов!
Микола Шубенков

@Gon я зробив тест на iOS9, і він просто працює добре. Ви можете звернутися до github.com/ipraba/TableReloadingNotifier
iPrabu

Він добре працює на емуляторі, але, здається, не працює на фактичному пристрої. Хтось ще має цю проблему?
sosale151

1
Це рішення, нарешті, працює для мене! він чудово працює на iOS 9
сильний

1
Я тестував на Real Device, iPhone 6s. Це також добре працює.
Сильний

25

EDIT: Ця відповідь насправді не є рішенням. Це, мабуть, спочатку працює, тому що перезавантаження може відбутися досить швидко, але насправді блок завершення не обов'язково викликається після повного завершення завантаження даних - оскільки reloadData не блокується. Вам, мабуть, слід шукати краще рішення.

Щоб розширити відповідь на @Eric MORAND, давайте поставити блок завершення. Хто не любить блок?

@interface DUTableView : UITableView

   - (void) reloadDataWithCompletion:( void (^) (void) )completionBlock;

@end

і ...

#import "DUTableView.h"

@implementation DUTableView

- (void) reloadDataWithCompletion:( void (^) (void) )completionBlock {
    [super reloadData];
    if(completionBlock) {
        completionBlock();
    }
}

@end

Використання:

[self.tableView reloadDataWithCompletion:^{
                                            //do your stuff here
                                        }];

2
Я не можу отримати достатню кількість блоків. Кому потрібен делегат, коли у вас є хороший блок!
bandejapaisa

Мені це подобається, але як бути з часом, коли система викликає reloadData (), наприклад, коли вперше відображається таблиця?
Симетричний

12
Це не рішення Комплектаційний блок починає виконання перед cellForRowAtIndexPath
zvjerka24

1
Це не вийде; reloadData не є блокувальним методом. Цей код викликається відразу після виклику reloadData, навіть якщо комірки ще не завантажені. Крім того, подивіться на цей код, і ви побачите, що ви можете просто поставити код після reloadData .
colinta

1
Це працює для мене з незначною зміною. Замість того , щоб викликати блок завершення безпосередньо, викличте його в блоці , розміщеному на головній черзі: dispatch_async(dispatch_get_main_queue(), ^{completionBlock();});. Це в основному стрибок жаб блоків, розміщених у поданні таблиці в reloadData.
Тімоті Муз

11

reloadData просто запитує дані для видимих ​​комірок. Каже, щоб отримати сповіщення, коли вказана частина вашої таблиці завантажена, будь ласка, підключіть tableView: willDisplayCell:метод.

- (void) reloadDisplayData
{
    isLoading =  YES;
    NSLog(@"Reload display with last index %d", lastIndex);
    [_tableView reloadData];
    if(lastIndex <= 0){
    isLoading = YES;
    //Notify completed
}

- (void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if(indexPath.row >= lastIndex){
    isLoading = NO;
    //Notify completed
}

1
Я не впевнений, чи спрацює це. Останній індекс - це кінець даних таблиці (наприклад, 100 записів), але таблиця відображатиме лише те, що видно на екрані (наприклад, 8 записів).
Травіс М.

10

Це моє рішення. 100% працює і використовується у багатьох проектах. Це простий підклас UITableView.

@protocol MyTableViewDelegate<NSObject, UITableViewDelegate>
@optional
- (void)tableViewWillReloadData:(UITableView *)tableView;
- (void)tableViewDidReloadData:(UITableView *)tableView;
@end

@interface MyTableView : UITableView {
    struct {
        unsigned int delegateWillReloadData:1;
        unsigned int delegateDidReloadData:1;
        unsigned int reloading:1;
    } _flags;
}
@end

@implementation MyTableView
- (id<MyTableViewDelegate>)delegate {
    return (id<MyTableViewDelegate>)[super delegate];
}

- (void)setDelegate:(id<MyTableViewDelegate>)delegate {
    [super setDelegate:delegate];
    _flags.delegateWillReloadData = [delegate respondsToSelector:@selector(tableViewWillReloadData:)];
    _flags.delegateDidReloadData = [delegate    respondsToSelector:@selector(tableViewDidReloadData:)];
}

- (void)reloadData {
    [super reloadData];
    if (_flags.reloading == NO) {
        _flags.reloading = YES;
        if (_flags.delegateWillReloadData) {
            [(id<MyTableViewDelegate>)self.delegate tableViewWillReloadData:self];
        }
        [self performSelector:@selector(finishReload) withObject:nil afterDelay:0.0f];
    }
}

- (void)finishReload {
    _flags.reloading = NO;
    if (_flags.delegateDidReloadData) {
        [(id<MyTableViewDelegate>)self.delegate tableViewDidReloadData:self];
    }
}

@end

Це схоже на рішення Джоша Брауна за одним винятком. У методі performSelector затримка не потрібна. Незалежно від того, скільки часу reloadDataзаймає. tableViewDidLoadData:завжди стріляє, коли tableViewзакінчує просити dataSource cellForRowAtIndexPath.

Навіть якщо ви не хочете підклас, UITableViewви можете просто зателефонувати, [performSelector:@selector(finishReload) withObject:nil afterDelay:0.0f]і ваш селектор буде викликаний відразу після закінчення перезавантаження таблиці. Але ви повинні переконатися, що селектор викликається лише один раз за виклик reloadData:

[self.tableView reloadData];
[self performSelector:@selector(finishReload) withObject:nil afterDelay:0.0f];

Насолоджуйтесь. :)


1
Використання виклику performSelector є геніальним. Проста і робоча, ніж подяка
Джулія

Це абсолютно дивовижно. Я боровся з цим цілими днями. Дякую!
Девід Карріко

@MarkKryzhanouski, ви протестували на iOS 9?
Віктор

@MarkKryzhanouski, дякую за швидкий відгук! Відмінно працює на iOS 7 та 8.
Віктор

Розв’язання performSelectorабо виконання на основному потоці dispatch_asynchне працює на iOS 9 .
Мануель

8

Це відповідь на дещо інше запитання: мені потрібно було знати, коли UITableViewтакож закінчував дзвінки cellForRowAtIndexPath(). Я підкласифікуюlayoutSubviews() (спасибі @Eric MORAND) і додав зворотний виклик делегата:

SDTableView.h:

@protocol SDTableViewDelegate <NSObject, UITableViewDelegate>
@required
- (void)willReloadData;
- (void)didReloadData;
- (void)willLayoutSubviews;
- (void)didLayoutSubviews;
@end

@interface SDTableView : UITableView

@property(nonatomic,assign) id <SDTableViewDelegate> delegate;

@end;

SDTableView.m:

#import "SDTableView.h"

@implementation SDTableView

@dynamic delegate;

- (void) reloadData {
    [self.delegate willReloadData];

    [super reloadData];

    [self.delegate didReloadData];
}

- (void) layoutSubviews {
    [self.delegate willLayoutSubviews];

    [super layoutSubviews];

    [self.delegate didLayoutSubviews];
}

@end

Використання:

MyTableViewController.h:

#import "SDTableView.h"
@interface MyTableViewController : UITableViewController <SDTableViewDelegate>
@property (nonatomic) BOOL reloadInProgress;

MyTableViewController.m:

#import "MyTableViewController.h"
@implementation MyTableViewController
@synthesize reloadInProgress;

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {

    if ( ! reloadInProgress) {
        NSLog(@"---- numberOfSectionsInTableView(): reloadInProgress=TRUE");
        reloadInProgress = TRUE;
    }

    return 1;
}

- (void)willReloadData {}
- (void)didReloadData {}
- (void)willLayoutSubviews {}

- (void)didLayoutSubviews {
    if (reloadInProgress) {
        NSLog(@"---- layoutSubviewsEnd(): reloadInProgress=FALSE");
        reloadInProgress = FALSE;
    }
}

ПРИМІТКИ. Оскільки це підклас, UITableViewякий вже має властивість делегата, що вказує на MyTableViewControllerнеобхідність додавати ще один. "@Dynamic delegate" повідомляє компілятору використовувати цю властивість. (Ось посилання, що описує це: http://farhadnoorzay.com/2012/01/20/objective-c-how-to-add-delegate-methods-in-a-subclass/ )

Для використання нового класу потрібно змінити UITableViewвластивість . Це робиться у інспектора ідентичності інтерфейсу Builder. Виберіть внутрішню частину та встановіть його "Спеціальний клас" на .MyTableViewControllerSDTableViewUITableViewUITableViewControllerSDTableView


Де ви встановите MyTableViewController як делегат для SDTableView? Як можна встановити властивість імені "delegate" на SDTableView, коли його надклас вже має властивість цього імені (UITableView.delegate)? Як ви додаєте свій власний SDTableView до властивості MyTableViewController.tableView, коли властивість типу "UITablewView", а об'єкт (екземпляр SDTableView) має тип "SDTableView"? Я борюся з тією ж проблемою, тож сподіваюся, що для цих питань є рішення :)
Граф Грей,

У коді Symmetric (SDTableView), чи не слід перезавантажувати InProgress встановити значення FALSE у didReloadData замість didLayoutSubviews? Оскільки reloadData викликається після layoutSubviews і завантаження не слід вважати виконаним до завершення reloadData.
tzuchien.chiu

Це не працює для iOS 8, довелося включити відповідь iPrabu .
оглушення

6

Я знайшов що - щось подібне , щоб отримати повідомлення про зміну contentSizeв TableView. Я думаю, що це повинно працювати і тут, оскільки contentSize також змінюється з завантаженням даних.

Спробуйте це:

У viewDidLoadзапису,

[self.tableView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld | NSKeyValueObservingOptionPrior context:NULL];

і додайте цей метод у свій viewController:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"contentSize"]) {
        DLog(@"change = %@", change.description)

        NSValue *new = [change valueForKey:@"new"];
        NSValue *old = [change valueForKey:@"old"];

        if (new && old) {
            if (![old isEqualToValue:new]) {
                // do your stuff
            }
        }


    }
}

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

Ура! :)


1
Дуже розумний. Для мене прекрасно працює. Дякую, що поділились!
DZenBot

2
Елегантний! Єдине, що я хотів би додати, це те, що вам потрібно видалити себе та спостерігача (можливо, методом -dealloc). Або додайте себе в якості спостерігача в -viewWillAppearі видаліть себе в -viewWillDisapearметоді.
Loozie

2

Ось можливе рішення, хоч це і хак:

[self.tableView reloadData];
[self performSelector:@selector(scrollTableView) withObject:nil afterDelay:0.3];

Там, де ваш -scrollTableViewметод прокручує подання таблиці -scrollRectToVisible:animated:. І, звичайно, ви могли налаштувати затримку коду вище від 0,3 до того, що, здається, працює для вас. Так, це смішно хакі, але це працює для мене на моїх iPhone 5 і 4S ...


2
Це може здатися "хитким", але це дійсно стандартний підхід для прокрутки: відкласти його до наступного циклу запуску. Я б змінив затримку на 0, оскільки це працює так само добре і має меншу затримку.
phatmann

Не працювало для мене із затримкою, встановленою на 0; 0,3 була найнижчою, яку я міг перейти, і досі отримую дані.
Джош Браун

@phatmann Це працювало для мене. Я також зміг використати 0 для моєї затримки. Дякую обом.
mcphersonjr

1

У мене було щось подібне, я вважаю. Я додав BOOL як змінну екземпляра, яка повідомляє мені, чи було змінено відновлення, і перевірити це -viewWillAppear:. Коли вона не була відновлена, я відновлюю її в тому методі і встановлюю BOOL таким чином, щоб я вказав, що я відновив зміщення.

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


Так, проблема полягає в тому, що viewWillAppear здається занадто рано (принаймні в моєму сценарії). Спроба відновити зміщення у viewWillAppear нічого не робить - якщо я не додаю хак виклику reloadData спочатку. Як я розумію, viewWillAppear / viewDidAppear посилається лише на сам вид таблиці, який фактично відображається - вони не пред'являють жодних претензій щодо того, чи були перелічені або заповнені комірки таблиці у представленні ... і це має відбутися до того, як ви зможете відновити компенсація, оскільки в іншому випадку ви будете відновлювати зсув на порожньому перегляді (і я розумію, чому це не вийде!).
kennethmac2000

Але, можливо, ви мали на увазі, що ви також змушуєте спочатку завантажувати комірки таблиці, викликаючи reloadData в межах viewWillAppear?
kennethmac2000

Ні, я не змушую перезавантажувати. Коли у мене виникли проблеми, я спробував відновити зміщення в -viewDidLoad(де це має статися звичайно), але це спрацювало лише тоді, коли я встановив зміщення анімованим. Перемістивши налаштування зміщення на -viewWillAppear:нього спрацювало, але мені довелося підтримувати прапор, щоб встановити його лише один раз. Я припускаю, що представлення таблиці перезавантажує свої дані, як тільки вони додаються до представлення, так що це вже в -loadView. Ви впевнені, що ваші дані доступні для завантаження перегляду? Або завантажується в окрему нитку чи щось таке?
Joost

Гаразд, можливо, ви можете допомогти мені тут зрозуміти. Ось як я розумію послідовність викликів, коли буде створено UITableView. 1) viewDidLoad запускається першим. Це вказує, що UITableView завантажується в пам'ять. 2) viewWillAppear знаходиться поруч із вогнем. Це вказує на те, що UITableView буде відображатися, але не обов'язково, що всі видимі об’єкти UITableViewCell будуть повністю інстанційними / закінченими візуалізацією.
kennethmac2000

2
І все вищезазначене вірно, тоді питання полягає в тому, які не хакітні варіанти ми маємо для з'ясування, коли UITableView отримав достатню інформацію зі свого джерела даних, щоб гарантувати, що запит прокрутки (тобто, scrollRectToVisible: animated: call ) реально буде працювати (а не просто нічого не робити)?
kennethmac2000

1

Здається, ви хочете оновити вміст комірок, але без раптових стрибків, які можуть супроводжувати вставки та видалення комірок.

Є кілька статей про це. Це одне.

Я пропоную використовувати setContentOffset: анімований: замість scrollRectToVisible: анімований: для ідеальних пікселів параметрів подання прокрутки.


1

Ви можете спробувати таку логіку:

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

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MyIdentifier"];

    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"MyIdentifier"];
        cell.selectionStyle = UITableViewCellSelectionStyleNone;
    }

    if ( [self chkIfLastCellIndexToCreate:tableView :indexPath]){
        NSLog(@"Created Last Cell. IndexPath = %@", indexPath);
        //[self.activityIndicator hide];
        //Do the task for TableView Loading Finished
    }
    prevIndexPath = indexPath;

    return cell;
}



-(BOOL) chkIfLastCellIndexToCreate:(UITableView*)tableView : (NSIndexPath *)indexPath{

    BOOL bRetVal = NO;
    NSArray *visibleIndices = [tableView indexPathsForVisibleRows];

    if (!visibleIndices || ![visibleIndices count])
        bRetVal = YES;

    NSIndexPath *firstVisibleIP = [visibleIndices objectAtIndex:0];
    NSIndexPath *lastVisibleIP = [visibleIndices objectAtIndex:[visibleIndices count]-1];

    if ((indexPath.row > prevIndexPath.row) && (indexPath.section >= prevIndexPath.section)){
        //Ascending - scrolling up
        if ([indexPath isEqual:lastVisibleIP]) {
            bRetVal = YES;
            //NSLog(@"Last Loading Cell :: %@", indexPath);
        }
    } else if ((indexPath.row < prevIndexPath.row) && (indexPath.section <= prevIndexPath.section)) {
        //Descending - scrolling down
        if ([indexPath isEqual:firstVisibleIP]) {
            bRetVal = YES;
            //NSLog(@"Last Loading Cell :: %@", indexPath);
        }
    }
    return bRetVal;
}

І перш ніж викликати reloadData, встановіть prevIndexPath на нуль. Подібно до:

prevIndexPath = nil;
[mainTableView reloadData];

Я перевірив NSLogs, і ця логіка здається нормальною. Ви можете налаштувати / покращити за потребою.


0

нарешті я змусив свій код працювати з цим -

[tableView scrollToRowAtIndexPath:scrollToIndex atScrollPosition:UITableViewScrollPositionTop animated:YES];

було небагато речей, над якими потрібно подбати -

  1. зателефонуйте в межах " - (UITableViewCell *)MyTableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath"
  2. просто переконайтеся, що повідомлення "scrollToRowAtIndexPath" надсилається до відповідного екземпляра UITableView, що, безумовно, MyTableview в цьому випадку.
  3. У моєму випадку UIView - це представлення, яке містить примірник UITableView
  4. Крім того, це буде викликано для кожного завантаження клітини. Тому викладіть логіку всередині "cellForRowAtIndexPath", щоб уникнути виклику "scrollToRowAtIndexPath" не один раз.

і просто переконайтеся, що цей твір не називається більше одного разу. якщо ні, то він блокує прокрутку.
smile.al.d.way

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

0

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

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    tableView.frame =CGRectMake(tableView.frame.origin.x, tableView.frame.origin.y, tableView.frame.size.width, tableView.contentSize.height);
}

0

Я просто запускаю повторюваний запланований таймер і визнаю його недійсним лише тоді, коли вміст таблиці більший, коли висота tableHeaderView (означає, що в таблиці є вміст рядків). Код у C # (monotouch), але я сподіваюся, що ідея зрозуміла:

    public override void ReloadTableData()
    {
        base.ReloadTableData();

        // don't do anything if there is no data
        if (ItemsSource != null && ItemsSource.Length > 0)
        {
            _timer = NSTimer.CreateRepeatingScheduledTimer(TimeSpan.MinValue, 
                new NSAction(() => 
                {
                    // make sure that table has header view and content size is big enought
                    if (TableView.TableHeaderView != null &&
                        TableView.ContentSize.Height > 
                            TableView.TableHeaderView.Frame.Height)
                    {
                        TableView.SetContentOffset(
                            new PointF(0, TableView.TableHeaderView.Frame.Height), false);
                        _timer.Invalidate();
                        _timer = null;
                    }
                }));
        }
    }

0

Чи не UITableView layoutSubviewsвикликається безпосередньо перед поданням таблиці відображає його вміст? Я помітив, що він викликається, коли огляд таблиці закінчить завантажувати свої дані, можливо, вам слід дослідити в цьому напрямку.


0

Починаючи з iOS 6, UITableviewметод делегата називав:

-(void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section

буде виконано, коли ваша таблиця буде успішно завантажена. Ви можете виконати налаштування відповідно до цього методу.


0

Найкраще рішення, яке я знайшов у Swift

extension UITableView {
    func reloadData(completion: ()->()) {
        self.reloadData()
        dispatch_async(dispatch_get_main_queue()) {
            completion()
        }
    }
}

-1

Чому просто не продовжують?

@interface UITableView(reloadComplete)
- (void) reloadDataWithCompletion:( void (^) (void) )completionBlock;
@end

@implementation UITableView(reloadComplete)
- (void) reloadDataWithCompletion:( void (^) (void) )completionBlock {
    [self reloadData];
    if(completionBlock) {
        completionBlock();
    }
}
@end

прокрутіть до кінця:

[self.table reloadDataWithCompletion:^{
    NSInteger numberOfRows = [self.table numberOfRowsInSection:0];
    if (numberOfRows > 0)
    {
        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:numberOfRows-1 inSection:0];
        [self.table scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:NO];
    }
}];

Не перевірено з великою кількістю даних

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