web-dev-qa-db-fra.com

Comment redimensionner une tableHeaderView d'une UITableView?

Je ne parviens pas à redimensionner une tableHeaderView. C'est simple, ça ne marche pas.

1) Créez un UITableView et UIView (100 x 320 px);

2) Définissez UIView comme tableHeaderView de UITableView;

3) Construire et aller. Tout va bien.

Maintenant, je veux redimensionner la tableHeaderView, alors j'ajoute ce code dans viewDidLoad:

self.tableView.autoresizesSubviews = YES;

self.tableView.tableHeaderView = myHeaderView;
self.tableView.tableFooterView = myFooterView;

CGRect newFrame = self.tableView.tableHeaderView.frame;
newFrame.size.height = newFrame.size.height + 100;
self.tableView.tableHeaderView.frame = newFrame;

La hauteur de la tableHeaderView doit apparaître avec 200, mais avec 100.

Si j'écris:

self.tableView.autoresizesSubviews = YES;


CGRect newFrame = myHeaderView.frame;
newFrame.size.height = newFrame.size.height + 100;
myHeaderView.frame = newFrame;


self.tableView.tableHeaderView = myHeaderView;
self.tableView.tableFooterView = myFooterView;

Ensuite, ça commence avec 200 de hauteur, comme je veux. Mais je veux pouvoir le modifier en cours d'exécution.

J'ai aussi essayé cela, sans succès:

self.tableView.autoresizesSubviews = YES;

self.tableView.tableHeaderView = myHeaderView;
self.tableView.tableFooterView = myFooterView;

CGRect newFrame = self.tableView.tableHeaderView.frame;
newFrame.size.height = newFrame.size.height + 100;
self.tableView.tableHeaderView.frame = newFrame;

[self.tableView.tableHeaderView setNeedsLayout];
[self.tableView.tableHeaderView setNeedsDisplay];
[self.tableView setNeedsLayout];
[self.tableView setNeedsDisplay];

Le point ici est: Comment redimensionnons-nous une tableHeaderView au runtime ???

Quelqu'un a-t-il pu faire cela?

Merci

je suis

96
iMe

FYI: Cela a fonctionné en modifiant la tableHeaderView et en la réinitialisant. Dans ce cas, je suis en train d'ajuster la taille de la tableHeaderView lorsque le chargement de la sous-vue UIWebView est terminé.

[webView sizeToFit];
CGRect newFrame = headerView.frame;
newFrame.size.height = newFrame.size.height + webView.frame.size.height;
headerView.frame = newFrame;
[self.tableView setTableHeaderView:headerView];
179
kubi

Cette réponse est ancienne et apparemment ne fonctionne pas sur iOS 7 et supérieur.

J'ai rencontré le même problème et je voulais aussi que les modifications s'animent. J'ai donc créé une sous-classe d'UIView pour ma vue d'en-tête et ajouté ces méthodes:

- (void)adjustTableHeaderHeight:(NSUInteger)newHeight{
    NSUInteger oldHeight = self.frame.size.height;
    NSInteger originChange = oldHeight - newHeight;

    [UIView beginAnimations:nil context:nil];

    [UIView setAnimationDuration:1.0f];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];

    self.frame = CGRectMake(self.frame.Origin.x, 
                        self.frame.Origin.y, 
                        self.frame.size.width, 
                        newHeight);

    for (UIView *view in [(UITableView *)self.superview subviews]) {
        if ([view isKindOfClass:[self class]]) {
            continue;
        }
        view.frame = CGRectMake(view.frame.Origin.x, 
                            view.frame.Origin.y - originChange, 
                            view.frame.size.width, 
                            view.frame.size.height);
    }

    [UIView commitAnimations];
}

- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context{
    [(UITableView *)self.superview setTableHeaderView:self];
}

Cela anime essentiellement toutes les sous-vues de UITableView qui ne sont pas du même type que la classe appelante. À la fin de l'animation, il appelle setTableHeaderView sur le superview (le UITableView) - sans cela, le contenu du UITableView reviendra en arrière lors du prochain défilement de l'utilisateur. La seule limitation que j'ai trouvée jusqu'à présent est que si l'utilisateur tente de faire défiler UITableView pendant le déroulement de l'animation, le défilement s'animera comme si la vue d'en-tête n'avait pas été redimensionnée (ce n'est pas grave si l'animation est rapide).

12
garrettmoon

Si vous souhaitez animer les modifications de manière conditionnelle, vous pouvez procéder comme suit:

- (void) showHeader:(BOOL)show animated:(BOOL)animated{

    CGRect closedFrame = CGRectMake(0, 0, self.view.frame.size.width, 0);
    CGRect newFrame = show?self.initialFrame:closedFrame;

    if(animated){
        // The UIView animation block handles the animation of our header view
        [UIView beginAnimations:nil context:nil];
        [UIView setAnimationDuration:0.3];
        [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];

        // beginUpdates and endUpdates trigger the animation of our cells
        [self.tableView beginUpdates];
    }

    self.headerView.frame = newFrame;
    [self.tableView setTableHeaderView:self.headerView];

    if(animated){
        [self.tableView endUpdates];
        [UIView commitAnimations];
    }
}

Veuillez noter que l'animation est double: 

  1. L'animation des cellules sous la tableHeaderView. Ceci est fait en utilisant beginUpdates et endUpdates
  2. L'animation de la vue d'en-tête réelle. Ceci est fait en utilisant un bloc d'animation UIView

Afin de synchroniser ces deux animations, la variable animationCurve doit être définie sur UIViewAnimationCurveEaseInOut et la durée sur 0.3, ce qui semble être ce que UITableView utilise pour son animation.

Mettre à jour

J'ai créé un projet Xcode sur gihub, qui le fait . Consultez le projet ResizeTableHeaderViewAnimated dans besi/ios-quickies

screenshot

10
Besi

Je pense que cela devrait fonctionner si vous définissez la hauteur de myHeaderView comme suit:

CGRect newFrame = myHeaderView.frame;
newFrame.size.height = newFrame.size.height + 100;
myHeaderView.frame = newFrame;

self.tableView.tableHeaderView = myHeaderView;
8
Greg Martin

Utiliser la solution @ garrettmoon ci-dessus jusqu'à iOS 7.
Voici une solution mise à jour basée sur @ garrettmoon:

- (void)adjustTableHeaderHeight:(NSUInteger)newHeight animated:(BOOL)animated {

    [UIView beginAnimations:nil context:nil];

    [UIView setAnimationDuration:[CATransaction animationDuration]];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];

    self.frame = CGRectMake(self.frame.Origin.x,
                        self.frame.Origin.y,
                        self.frame.size.width,
                        newHeight);

    [(UITableView *)self.superview setTableHeaderView:self];

    [UIView commitAnimations];
}

- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context{
    [(UITableView *)self.superview setTableHeaderView:self];
}
6
avishic

Cela a fonctionné pour moi sur iOS 7 et 8. Ce code est exécuté sur le contrôleur de vue de table.

[UIView animateWithDuration:0.3 animations:^{
    CGRect oldFrame = self.headerView.frame;
    self.headerView.frame = CGRectMake(oldFrame.Origin.x, oldFrame.Origin.y, oldFrame.size.width, newHeight);
    [self.tableView setTableHeaderView:self.headerView];
}];
5
Darcy Rayner

C'est parce que le passeur de tableHeaderView.

Vous devez définir la hauteur UIView avant de définir tableHeaderView. (Ce serait beaucoup plus facile si Apple ouvrait ce cadre avec des sources ouvertes ...) 

4
Thomas Decaux

Sur iOS 9 et les versions antérieures, tableHeaderView ne remettrait pas en page après le redimensionnement . Ce problème est résolu dans iOS 10.

Pour résoudre ce problème, faites-le simplement avec le code suivant:

self.tableView.tableHeaderView = self.tableView.tableHeaderView;
3
klaudz

Sur iOS 9.x, cela sur viewDidLoad fonctionne parfaitement:

var frame = headerView.frame
frame.size.height = 11  // New size
headerView.frame = frame

headerView est déclaré en tant que @IBOutlet var headerView: UIView! et connecté au storyboard, où il est placé en haut de tableView, pour fonctionner en tant que tableHeaderView.

2
Eneko Alonso

La définition de height pour la propriété tableView.tableHeaderView dans viewDidLoad semble ne pas fonctionner, la hauteur de la vue en-tête ne change toujours pas comme prévu.

Après avoir lutté contre ce problème pendant de nombreux essais. J'ai trouvé que vous pouvez modifier la hauteur en appelant la logique de création de la vue en-tête dans la méthode - (void)didMoveToParentViewController:(UIViewController *)parent.

Ainsi, l'exemple de code ressemblerait à ceci:

- (void)didMoveToParentViewController:(UIViewController *)parent {
    [super didMoveToParentViewController:parent];

    if ( _tableView.tableHeaderView == nil ) {
        UIView *header = [[[UINib nibWithNibName:@"your header view" bundle:nil] instantiateWithOwner:self options:nil] firstObject];

        header.frame = CGRectMake(0, 0, CGRectGetWidth([UIScreen mainScreen].bounds), HeaderViewHeight);

        [_tableView setTableHeaderView:header];
    }
}
1
Enix

Évidemment, à ce jour, Apple aurait dû implémenter UITableViewAutomaticDimension pour tableHeaderView & tableFooterView ...

Ce qui suit semble fonctionner pour moi en utilisant des contraintes de mise en page:

CGSize   s  = [ self  systemLayoutSizeFittingSize : UILayoutFittingCompressedSize ];
CGRect   f  = [ self  frame ];

f.size   = s;

[ self  setFrame : f ];
0
digitaldaemon

Cela s'applique uniquement lorsque vous utilisez la mise en page automatique et définissez translatesAutoresizingMaskIntoConstraints = false sur une vue d'en-tête personnalisée.

La meilleure et la plus simple consiste à remplacer intrinsicContentSize. En interne, UITableView utilise intrinsicContentSize pour décider de la taille de son en-tête/pied de page. Une fois que vous avez remplacé intrinsicContentSize dans votre vue personnalisée, procédez comme suit:

  1. configurer la présentation de la vue d'en-tête/pied de page personnalisée (sous-vues)
  2. invoquer invalidateIntrinsicContentSize()
  3. invoquer tableView.setNeedsLayout() et tableView.layoutIfNeeded()

Ensuite, l'en-tête/le pied de page de UITableView sera mis à jour comme vous le souhaitez. Pas besoin de définir la vue nil ou réinitialiser.

Une chose vraiment intéressante pour le UITableView.tableHeaderView ou le .tableFooterView est que UIStackView perd sa capacité à gérer son arrangedSubviews. Si vous voulez utiliser UIStackView en tant que tableHeaderView ou tableFooterView, vous devez incorporer stackView dans un UIView et remplacer le UIView's intrinsicContentSize.

0
Ryan

Si votre tableHeaderView est une webView à contenu réglable, vous pouvez essayer:

[self.webView.scrollView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew context:nil];

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    self.webView.height = self.webView.scrollView.contentSize.height;
    self.tableView.tableHeaderView = self.webView;
}

Je l'ai testé sur iOS9 et iOS11, a bien fonctionné.

0
无夜之星辰

J'ai trouvé que l'initialiseur initWithFrame d'un UIView ne respecte pas correctement le rect que je passe. J'ai donc fait ce qui suit parfaitement:

 - (id)initWithFrame:(CGRect)aRect {

    CGRect frame = [[UIScreen mainScreen] applicationFrame];

    if ((self = [super initWithFrame:CGRectZero])) {

        // Ugly initialization behavior - initWithFrame will not properly honor the frame we pass
        self.frame = CGRectMake(0, 0, frame.size.width, 200);

        // ...
    }
}

L'avantage de ceci est qu'il est mieux encapsulé dans votre code d'affichage.

0
Harald Schubert

En-tête de redimensionnement UITableView - UISearchBar avec barre d’étendue

Je voulais une UITableView avec une UISearchBar comme en-tête de la table afin d'avoir une hiérarchie qui ressemble à ceci

UITableView
  |
  |--> UIView
  |     |--> UISearchBar
  |
  |--> UITableViewCells

Méthodes UISearchBarDelegate

Comme il a été indiqué ailleurs, si vous ne définissez pas TableViewHeader après l'avoir modifié, rien ne se passera.

- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar
{
    searchBar.showsScopeBar = YES;
    [UIView animateWithDuration:0.2f animations:^{
        [searchBar sizeToFit];
        CGFloat height = CGRectGetHeight(searchBar.frame);

        CGRect frame = self.tableView.tableHeaderView.frame;
        frame.size.height = height;
        self.tableHeaderView.frame = frame;
        self.tableView.tableHeaderView = self.tableHeaderView;
    }];

    [searchBar setShowsCancelButton:YES animated:YES];
    return YES;
}

- (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar
{
    searchBar.showsScopeBar = NO;
    [UIView animateWithDuration:0.f animations:^{
        [searchBar sizeToFit];

        CGFloat height = CGRectGetHeight(searchBar.frame);

        CGRect frame = self.tableView.tableHeaderView.frame;
        frame.size.height = height;
        self.tableHeaderView.frame = frame;
        self.tableView.tableHeaderView = self.tableHeaderView;
    }];

    [searchBar setShowsCancelButton:NO animated:YES];
    return YES;
}
0

J'ai implémenté le changement de hauteur animé de l'en-tête de la table pour passer à l'écran général lorsque vous appuyez dessus. Cependant, le code peut aider dans d'autres cas:

// Swift
@IBAction func tapped(sender: UITapGestureRecognizer) {

    self.tableView.beginUpdates()       // Required to update cells. 

    // Collapse table header to original height
    if isHeaderExpandedToFullScreen {   

        UIView.animateWithDuration(0.5, animations: { () -> Void in
            self.scrollView.frame.size.height = 110   // original height in my case is 110
        })

    }
    // Expand table header to overall screen            
    else {      
        let screenSize = self.view.frame           // "screen" size

        UIView.animateWithDuration(0.5, animations: { () -> Void in
            self.scrollView.frame.size.height = screenSize.height
        })
    }

    self.tableView.endUpdates()  // Required to update cells. 

    isHeaderExpandedToFullScreen= !isHeaderExpandedToFullScreen  // Toggle
}
0
Alexander Volkov

Si headerView personnalisé est conçu à l'aide de autolayout et que headerView doit être mis à jour après la récupération Web ou une tâche similaire paresseuse . Puis dans iOS-Swift j'ai procédé ainsi et mis à jour mon headerView avec le code ci-dessous:

//to reload your cell data
self.tableView.reloadData()
dispatch_async(dispatch_get_main_queue(),{
// this is needed to update a specific tableview's headerview layout on main queue otherwise it's won't update perfectly cause reloaddata() is called
  self.tableView.beginUpdates()
  self.tableView.endUpdates()
} 
0