Как запустить UITableView на последней ячейке?

В приложении "Сообщения Apple", когда вы нажимаете соответствующее имя и переключаетесь на представление таблицы в разговоре (с воздушными шарами для каждого сообщения), таблица отображается прокручивается до конца. Нет анимации или чего-то еще, она просто там.

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

Как это делают эти приложения? Вызывают ли они scrollToRowAtIndexPath:atScrollPosition:animated: где-то в контроллере таблицы? Если да, то как они знают, что передать на atScrollPosition:? И в каком методе он называется?

Ответ 1

scrollToRowAtIndexPath должен работать.

В viewWillAppear: попробуйте следующее:

[theTableView reloadData];    
NSIndexPath* ip = [NSIndexPath indexPathForRow:rowNumberHere inSection:sectionNumberHere];
[theTableView scrollToRowAtIndexPath:ip atScrollPosition:UITableViewScrollPositionTop animated:NO];

rowNumberHere - номер строки в источнике данных, который вы хотите прокрутить.

atScrollPosition - это только одно из значений в перечислении UITableViewScrollPosition, которое может определять, где на экране появится номер строки, который вы хотите. Однако, в зависимости от количества строк и строки, в которую вы прокручиваете, это может не иметь значения.

Ввод reloadData: исключает исключение, если данные еще не загружены в viewWillAppear:. Если вы поместите scrollToRowAtIndexPath в viewDidAppear:, вам не понадобится reloadData:, но вы увидите, что таблица немного перескакивает, что вы говорите, что не хотите.

Изменить: @Theory, попробуйте изменить свой код следующим образом:

[tableView reloadData];
int lastRowNumber = [tableView numberOfRowsInSection:0] - 1;
NSIndexPath* ip = [NSIndexPath indexPathForRow:lastRowNumber inSection:0];
[tableView scrollToRowAtIndexPath:ip atScrollPosition:UITableViewScrollPositionTop animated:NO];

Обратите внимание, что numberOfRowsInSection возвращает число строк, а не последнее число строк (число строк - 1).

Ответ 2

Вы можете вызвать -scrollToRowAtIndexPath: atScrollPosition: анимированный в методе -viewWillAppear: вашего TableViewController.

atScrollPosition: позволяет указать, где вы хотите, чтобы ваша ячейка для строкиAtIndexPath отображалась. Существует четыре варианта:

UITableViewScrollPositionTop - помещает вашу ячейку в верхнюю часть представления

UITableViewScrollPositionMiddle - центрирует вашу ячейку в представлении

UITableViewScrollPositionBottom - помещает вашу ячейку внизу

UITableViewScrollPositionNone - Использование этой настройки будет располагаться в ячейке в пользовательском режиме с минимальной прокруткой/перемещением.

В трех сценариях поведение различно: -

Если ячейка уже отображается, она ничего не делает.

Если ячейка находится выше текущего представления, она прокручивает ячейку в верхней части представления.

Если ячейка находится под текущим видом, она прокручивает ячейку в нижней части представления.

Ответ 3

После ответа DyingCactus выше, я добавил этот метод к моему контроллеру:

-(void)viewWillAppear:(BOOL)animated {
      [self.tableView reloadData];    
      NSIndexPath* ip = [NSIndexPath indexPathForRow:[self.tableView numberOfRowsInSection:0] - 1 inSection:0];
      [self.tableView scrollToRowAtIndexPath:ip atScrollPosition:UITableViewScrollPositionTop animated:NO];
}

И теперь это работает, именно то, что я хотел. Спасибо!

Ответ 4

Я использую автозапуск, и ни один из ответов не работал у меня. Вот мое решение, которое наконец-то сработало:

@property (nonatomic, assign) BOOL shouldScrollToLastRow;


- (void)viewDidLoad
{
    [super viewDidLoad];

    _shouldScrollToLastRow = YES;
}


- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];

    // Scroll table view to the last row
    if (_shouldScrollToLastRow)
    {
        _shouldScrollToLastRow = NO;
        [self.tableView setContentOffset:CGPointMake(0, CGFLOAT_MAX)];
    }
}

Ответ 5

Ответ @DyingCactus в Swift 3:

    let lastRow: Int = self.tableView.numberOfRows(inSection: 0) - 1
    let indexPath = IndexPath(row: lastRow, section: 0);
    self.tableView.scrollToRow(at: indexPath, at: .top, animated: false)

Ответ 6

Проблема с методом scrollToRowAtIndexPath является медленной, и tableView требует времени для прокрутки до нижней части.

У меня была одна и та же проблема, после того, как вы все пробовали (так же, как и вы), это сработало, ключ - если вы используете автозапуск инициализировать scrollToBottom в true, а затем сделать это

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];
    // Scroll table view to the last row
    [self scrollToBottom];
}

-(void)scrollToBottom {
    if (shouldScrollToLastRow)
    {
        CGPoint bottomOffset = CGPointMake(0, self.tableView.contentSize.height - self.tableView.bounds.size.height);
        [self.tableView setContentOffset:bottomOffset animated:NO];
    } }

сделав это, вы убедитесь, что вы почти на дне вашего стола, но не можете быть на самом дне, так как его невозможно узнать точное смещение вниз, когда вы находитесь в верхней части таблицы, поэтому после этого мы можем реализовать scrollViewDidScroll

-(void)scrollViewDidScroll: (UIScrollView*)scrollView
{
    float scrollViewHeight = scrollView.frame.size.height;
    float scrollContentSizeHeight = scrollView.contentSize.height;
    float scrollOffset = scrollView.contentOffset.y;

    // if you're not at bottom then scroll to bottom
    if (!(scrollOffset + scrollViewHeight == scrollContentSizeHeight))
    {
        [self scrollToBottom];
    } else {
    // bottom reached now stop scrolling
        shouldScrollToLastRow = false;
    }
}

Ответ 7

Примечание: для прокрутки в нижнюю строку раздел должен быть последним, а не 0 (первый раздел):

int lastSection = [self.myTableView numberOfSections] -1;
if (lastSection < 0) return;

int lastRow = [self.myTableView numberOfRowsInSection:lastSection] - 1;
if (lastRow < 0) return;  
NSIndexPath* ip = [NSIndexPath indexPathForRow:lastRow inSection:lastSection];

 [self.myTableView scrollToRowAtIndexPath:ip atScrollPosition:UITableViewScrollPositionTop animated:YES];

Ответ 8

#import "ViewController.h"


@interface ViewController ()
@end

@implementation ViewController
CGFloat labelWidth = 260.0f;
CGFloat labelRequiredHeight = 180.0f;
@synthesize tblView;
@synthesize txtField;
@synthesize chatData;

- (void)viewDidLoad
{
    [super viewDidLoad];
    tblView.delegate = self;

    [self.tblView setSeparatorStyle:UITableViewCellSeparatorStyleNone];
    chatData  = [[NSMutableArray alloc] init];
    [self registerForKeyboardNotifications];

}

-(IBAction) textFieldDoneEditing : (id) sender
{
    NSLog(@"the text content%@",txtField.text);
    [sender resignFirstResponder];
    [txtField resignFirstResponder];
}

- (IBAction)sendButton:(id)sender
{
    if (txtField.text.length>0) {
        // updating the table immediately
        NSArray *data = [NSArray arrayWithObject:@"text"];
        NSArray *objects = [NSArray arrayWithObject:txtField.text];
        NSDictionary *dictionary = [NSDictionary dictionaryWithObjects:objects forKeys:data];
        [chatData addObject:dictionary];

        NSMutableArray *insertIndexPaths = [[NSMutableArray alloc] init];
        NSIndexPath *newPath = [NSIndexPath indexPathForRow:0 inSection:0];
        [insertIndexPaths addObject:newPath];
        [tblView beginUpdates];
        [tblView insertRowsAtIndexPaths:insertIndexPaths withRowAnimation:UITableViewRowAnimationTop];
        [tblView endUpdates];
        [tblView reloadData];

        txtField.text = @"";
        [self.view endEditing:YES];
    }
}

-(IBAction) backgroundTap:(id) sender
{
    [self.txtField resignFirstResponder];
}

-(BOOL)SendbtnShouldReturn:(UITextField *)textfield
{
    [textfield resignFirstResponder];
    return YES;
}

- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
    NSLog(@"the text content%@",txtField.text);
    [textField resignFirstResponder];
    if (txtField.text.length>0)
    {
        // updating the table immediately
        NSArray *keys = [NSArray arrayWithObject:@"text"];
        NSArray *objects = [NSArray arrayWithObject:txtField.text];
        NSDictionary *dictionary = [NSDictionary dictionaryWithObjects:objects forKeys:keys];
        [chatData addObject:dictionary];

        NSMutableArray *insertIndexPaths = [[NSMutableArray alloc] init];
        NSIndexPath *newPath = [NSIndexPath indexPathForRow:0 inSection:0];
        [insertIndexPaths addObject:newPath];
        [tblView beginUpdates];
        [tblView insertRowsAtIndexPaths:insertIndexPaths withRowAnimation:UITableViewRowAnimationTop];
        [tblView endUpdates];
        [tblView reloadData];
        txtField.text = @"";
    }
    return NO;
}


// Keyboard Functionality

-(void) registerForKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWasShown:) name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}

-(void) freeKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}

-(void) keyboardWasShown:(NSNotification*)aNotification
{
    NSLog(@"Keyboard was shown");
    NSDictionary* info = [aNotification userInfo];
    // Get animation info from userInfo
    NSTimeInterval animationDuration;
    UIViewAnimationCurve animationCurve;
    CGRect keyboardFrame;
    [[info objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
    [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
    [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] getValue:&keyboardFrame];
    // Move
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:animationDuration];
    [UIView setAnimationCurve:animationCurve];
    NSLog(@"frame..%f..%f..%f..%f",self.view.frame.origin.x, self.view.frame.origin.y, self.view.frame.size.width, self.view.frame.size.height);
    NSLog(@"keyboard..%f..%f..%f..%f",keyboardFrame.origin.x, keyboardFrame.origin.y, keyboardFrame.size.width, keyboardFrame.size.height);
    [self.view setFrame:CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y- keyboardFrame.size.height, self.view.frame.size.width, self.view.frame.size.height)];
    [tblView setFrame:CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y+ keyboardFrame.size.height, self.view.frame.size.width, self.view.frame.size.height-keyboardFrame.size.height)];
    [tblView scrollsToTop];
    [UIView commitAnimations];

}

-(void) keyboardWillHide:(NSNotification*)aNotification
{
    NSLog(@"Keyboard will hide");
    NSDictionary* info = [aNotification userInfo];
    // Get animation info from userInfo
    NSTimeInterval animationDuration;
    UIViewAnimationCurve animationCurve;
    CGRect keyboardFrame;
    [[info objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
    [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
    [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] getValue:&keyboardFrame];
    // Move
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:animationDuration];
    [UIView setAnimationCurve:animationCurve];
    [self.view setFrame:CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y + keyboardFrame.size.height, self.view.frame.size.width, self.view.frame.size.height)];
    [tblView setFrame:CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y, self.view.frame.size.width, self.view.frame.size.height)];
    [UIView commitAnimations];
    UIEdgeInsets contentInsets = UIEdgeInsetsZero;
    self.tblView.contentInset = contentInsets;
    self.tblView.scrollIndicatorInsets = contentInsets;
    self.tblView.scrollEnabled=chatData;


}

#pragma mark UITableViewDataSource protocol methods
- (void)scrollTableToBottom
{
    int rowNumber = [self.tblView numberOfRowsInSection:1];
    if (rowNumber > 0) [self.tblView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:rowNumber-1 inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [chatData count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *[email protected]"chatCell";
    chatCell *cell = (chatCell *)[tableView dequeueReusableCellWithIdentifier: @"chatCellIdentifier"];
    if(!cell)
        cell =[[chatCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
//    NSUInteger row = [chatData count]-[indexPath row]-1;
    NSUInteger row=[indexPath row];
    NSUInteger count = [chatData count];
    if (row <chatData.count)
    {
        NSString *chatText = [[chatData objectAtIndex:row] objectForKey:@"text"];
        cell.txtMsg.text = chatText;
    }
    return cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString *cellText = [[chatData objectAtIndex:chatData.count-indexPath.row-1] objectForKey:@"text"];
    UIFont *cellFont = [UIFont fontWithName:@"Helvetica" size:20.0];
    CGSize constraintSize = CGSizeMake(225.0f, MAXFLOAT);
    CGSize labelSize = [cellText sizeWithFont:cellFont constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap];
        return labelSize.height + 40;
}


//-(void)scrollToBottomTableView
//{
//    if (self.tblView.contentOffset.y > self.tblView.frame.size.height)
//    {
//        [self.tblView scrollToRowAtIndexPath:[self. indexPathForLastMessage]
//                              atScrollPosition:UITableViewScrollPositionBottom animated:YES];
//    }
//}


-(void)viewWillAppear:(BOOL)animated
{

//        [tblView reloadData];
//   
//    int lastRowNumber = [tblView numberOfRowsInSection:0] - 1;
//    NSIndexPath* ip = [NSIndexPath indexPathForRow:lastRowNumber inSection:0];
//    [tblView scrollToRowAtIndexPath:ip atScrollPosition:UITableViewScrollPositionTop animated:NO];
}
-(void)viewDidAppear:(BOOL)animated
{
//[tblView reloadData];

}
- (void)reloadTableViewDataSource
{
    [tblView reloadData];

}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}
@end