web-dev-qa-db-fra.com

Comment démarrer UitailView sur la dernière cellule?

Dans l'application Messages d'Apple, lorsque vous cliquez sur le nom d'un correspondant et passez à la vue Tableau de la conversation (avec des ballons pour chaque message), le tableau apparaît défilé jusqu'à la fin. Aucune animation ou quoi que ce soit, c'est juste là.

De même, à Tweetie 2, lorsque vous chargez la vue Tweets, il apparaît juste là où vous avez examiné la dernière fois. Aucune animation pour y arriver, c'est juste là, comme si aucune des cellules ci-dessus n'avait été chargée.

Comment ces applications font cela? Sont-ils appelant scrollToRowAtIndexPath:atScrollPosition:animated: quelque part dans le contrôleur de table? Si oui, comment savent-ils quoi passer à atScrollPosition:? Et dans quelle méthode est-elle appelée?

27
theory

scrollToRowAtIndexPath devrait fonctionner.

Dans viewWillAppear:, essaye ça:

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

rowNumberHere est le numéro de ligne dans la source de données que vous souhaitez faire défiler.

atScrollPosition est une seule des valeurs du UITableViewScrollPosition Enum, qui peut déterminer où sur l'écran le numéro de ligne que vous souhaitez apparaître. Cependant, en fonction du nombre de lignes et de quelle ligne vous faites défiler, cela peut ne pas faire la différence.

En mettant reloadData: Évite une exception si les données ne sont pas encore chargées dans viewWillAppear:. Si vous mettez le scrollToRowAtIndexPath dans viewDidAppear:, vous n'avez pas besoin de la reloadData: Mais vous verrez la table sauter un peu que vous dites que vous ne voulez pas.

Edit: @Theory, essayez de changer votre code comme suit ...

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

Veuillez noter numberOfRowsInSection Retourne le nombre de lignes, pas le dernier numéro de ligne (qui est le nombre de lignes - 1).

57
user121301

Vous pouvez appeler -scrolltorowatudexpath: Atscrollposition: animé dans la vue -Voyerwillappear: méthode de votre tableViewController.

aTScrollPosition: vous permet de définir l'endroit où vous souhaitez que votre cellule pour que RowaTindexPath apparaisse. Il y a quatre options:

itablesViewscrollpositiontop - met votre cellule en haut de la vue

itablesViewscrollPosiMPositionMiddle - Centre votre cellule dans la vue

itablesViewscrollpositionBottom - met votre cellule en bas

itablesViewscrollpositionNone - L'utilisation de ce paramètre se positionnera dans la cellule dans la vue utilisateur avec un minimum de défilement/mouvement.

Le comportement est différent dans trois scénarios: -

Si la cellule est déjà en vue, cela ne fait rien.

Si la cellule est au-dessus de la vue actuelle, elle fait défiler la cellule en haut de la vue.

Si la cellule est sous la vue actuelle, elle fait défiler la cellule au bas de la vue.

9
Deepak Danduprolu

Réponse de @dyingCactus dans Swift & Swift 4:

    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)
9
Gent Berani

J'utilise Autolayout et aucune des réponses ne s'est produite pour moi. Voici ma solution qui a finalement fonctionné:

@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)];
    }
}
7
RaffAl

Après la réponse de DyingCactus ci-dessus, j'ai ajouté cette méthode à mon contrôleur:

-(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];
}

Et maintenant ça marche, exactement ce que je voulais. Merci!

7
theory

Le problème avec la méthode ScrollProwatidexpath est lent et la vision de la table prend du temps à faire défiler jusqu'au fond.

j'ai eu exactement le même problème, après avoir tout essayé (identique que vous), cela a fonctionné, la clé est que si vous utilisez Autolayout Initialize ScrollTobottom à True, puis faites cela

- (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];
    } }

faire cela vous assurera que vous êtes presque au bas de votre tableview mais que vous ne serez peut-être pas au fond même que son impossible de connaître le décalage exact du fond lorsque vous êtes en haut de la tableView, de manière à ce que nous puissions mettre en œuvre 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;
    }
}
4
Ankur Teotia
#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 *cellIdentifier=@"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
0
jeetendra

Remarque Pour faire défiler vers la ligne inférieure, la section doit être la dernière section non 0 (première section):

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];
0
Gamma-Point