web-dev-qa-db-fra.com

iOS: étirement/redimensionnement de l'en-tête UITableView lorsque l'utilisateur ralentit?

En utilisant le storyboard, j'ai placé une imageView comme mon tableView'sheaderView dans une ViewController.

Voici comment mon story-board est mis en place:

enter image description here

Selon les données consultées par l'utilisateur, la variable viewController affichera ou masquera la variable headerView. Ma question est la suivante: lorsque la headerView est visible et que l'utilisateur glisse sur la tableView, comment puis-je demander à la imageView de coller à la fois à la navigationBar et à la tableView alors qu'elle redimensionne pour couvrir l'espace entre les deux?

C'est ce qu'il fait actuellement:

enter image description here

Mais voici ce que je vais faire:

enter image description here

Toute aide serait grandement appréciée. J'ai consulté des bibliothèques de parallaxe, mais aucune ne prend en charge sectionTitles, et je ne cherche pas nécessairement non plus l'effet de parallaxe. Lorsque l'utilisateur fait défiler l'écran vers le haut, je souhaite que ce dernier retourne à la vue normale et ne masque pas l'en-tête. Merci!

METTRE À JOUR:

J'ai suivi les conseils postés par Dany ci-dessous et fait le Suivant:

-(void)scrollViewDidScroll:(UIScrollView*)scrollView {

CGRect initialFrame = CGRectMake(0, 0, 320, 160);

if (scrollView.contentOffset.y < 0) {

    initialFrame.size.height =! scrollView.contentOffset.y;
    childHeaderView.frame = initialFrame;
} }

childHeaderView est une imageView et pour une raison quelconque, lorsque je glisse vers le bas, l'image monte (comme la moitié derrière la barre de navigation) et ne revient pas. Tout conseil serait très appréciée!! Merci!

27
KingPolygon

J'ai récemment posté un article sur la réalisation de cette contrainte en utilisant des contraintes qui pourraient aider, il s'avère que c'était assez simple.

Voici le lien: Créer un effet de parallaxe sur UIScrollView en utilisant des contraintes

7
petehare

Tout d'abord, vous devez supprimer la UIImageView de l'en-tête et l'ajouter en tant que simple UIImageView au-dessus de la UITableView puis, puisque le protocole UITableViewDelegate est conforme au protocole UIScrollViewDelegate, vous pouvez implémenter la méthode scrollViewDidScroll: pour vérifier quand la tableView défile et a un effet bouncing. . quelque chose comme ça:

-(void)someInitMethod {
   initialFrame = yourHeaderView.frame;
}
-(void)scrollViewDidScroll:(UIScrollView*)scrollView {
    if(scrollView.contentOffset.y < 0) {
       initialFrame.size.height -= scrollView.contentOffset.y;
       yourHeaderView.frame = initialFrame;
    }
}

Assurez-vous également que vous avez défini la variable contentMode appropriée pour votre UIImageView. De plus, je pense que cette implémentation va créer un effet de rebond mais je ne suis pas sûr car je ne peux pas le tester pour le moment mais je pense que c'est un bon point de départ pour vous.

5
danypata

Voici comment je l'ai réalisé. Dans mon cas, j'utilisais une vue cartographique en haut:

  1. Créez un contrôleur de vue dans le storyboard.
  2. Ajoutez une vue tableau et définissez les contraintes sur 0 de tous les côtés.
  3. Ajoutez une vue cartographique (ou une vue quelconque) en dessous de la vue tableau pour qu’elle soit rendue au-dessus. Cela va se chevaucher.
  4. Ajoutez des contraintes en haut à gauche et à droite.
  5. Dans le contrôleur de vue viewDidLoad, ajoutez ce qui suit: tableView.contentInset = UIEdgeInsetsMake(200, 0, 0, 0)200 est la hauteur de la vue. Cela poussera le contenu de la vue tableau vers le bas.
  6. Dans le contrôleur de vue, ajoutez le code suivant, qui redimensionne la vue en fonction du défilement:

    func scrollViewDidScroll(scrollView: UIScrollView) {
        var scrollOffset = scrollView.contentOffset.y
        var headerFrame = mapView.frame
        if (scrollOffset < 0) {
            // Adjust map
            headerFrame = CGRect(x: mapView.frame.Origin.x,
                y: mapView.frame.Origin.y,
                width: mapView.frame.size.width,
                height: -scrollOffset)
        } else {
            // Adjust map
            headerFrame = CGRect(x: mapView.frame.Origin.x,
                y: mapView.frame.Origin.y,
                width: mapView.frame.size.width,
                height: 0)
        }
        mapView.frame = headerFrame
    }
    

Si je pouvais mettre contentInset dans le storyboard, ce serait encore plus joli

2
geometrikal

Les solutions précédentes sur cette page m'avaient posé quelques problèmes lorsque j'avais besoin que cela fonctionne avec les titres de section et la barre d'index. J'ai donc proposé moi-même la solution suivante. Notez s'il vous plaît; Je n'utilise pas l'autolayout dans mon projet et je ne l'ai testé que sur iOS9 +;

Dans le storyboard de votre projet:

  1. Créez un UITableView dans un UIViewController (ou essayez-le avec un UITableViewController).
  2. Déposez un UIView en haut (mais à l'intérieur) de UITableView pour qu'il devienne un en-tête de table au-dessus de la première cellule.
  3. Donnez à cet en-tête la hauteur souhaitée (200px par exemple) et définissez la couleur d'arrière-plan sur "Couleur claire". La couleur transparente est importante, la vue doit être transparente.
  4. Déposez une deuxième UIView dans l'en-tête de la table UIView et donnez-lui la même taille que son parent. Ce sera l'en-tête, alors n'hésitez pas à lui attribuer n'importe quelle couleur, à configurer une vue ou tout autre contenu.
  5. Connectez cette 2ème UIView à votre UIViewController IBOutlet, je l’ai nommée "headerView" dans mon cas.

Ensuite, allez sur votre UIViewController.m:

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Remove view from table header and place it in the background instead.
    [self.headerView removeFromSuperview];
    UIView *backgroundView = [UIView new];
    [backgroundView addSubview:self.headerView];
    self.tableView.backgroundView = backgroundView;
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    /* Set initialScrollOffset ivar to start offset, because in my case
       the scroll offset was affected by the statusbar + navigation bar heights
       and the view controller's "extend edges under top bars" option. */
    initialScrollOffset = self.tableView.contentOffset.y;
}

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    /* Modify headerView height only if the table content gets pulled
       beyond initial offset. */
    if (scrollView.contentOffset.y < initialScrollOffset) {
        CGRect frame = self.headerView.frame;
        frame.size.height = self.tableView.tableHeaderView.frame.size.height + -scrollView.contentOffset.y;
        self.headerView.frame = frame;
    }
}

J'avais besoin de cette implémentation uniquement pour un en-tête d'étirement avec une couleur d'arrière-plan et des étiquettes. Il devrait cependant être facile d’ajouter un UIImageView à cet en-tête.

De plus, les étapes 1 à 5 sont bien sûr facultatives. Vous pouvez créer par programme votre vue en-tête ou utiliser un fichier XIB à la place. Tant que vous vous assurez que la table a une vue d'en-tête Clear Colored définie avec la même hauteur que l'en-tête souhaité, car elle sert d'espaceur pour conserver vos titres de cellules et de sections en ligne.

MODIFIER:

J'ai trouvé un moyen encore plus propre d'accomplir cela.

  1. Construisez votre en-tête de table dans le générateur d'interface comme décrit ci-dessus: 1 UIView en tant que conteneur avec une seconde UIView intégrée.
  2. Ignorez le code viewDidLoad ci-dessus, il n'est pas nécessaire d'extraire UIView de son conteneur et nous n'avons pas besoin de le définir en tant qu'arrière-plan de table.
  3. Changez la méthode scrollViewDidScroll: en ceci:

UIViewController.m:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
      if (scrollView.contentOffset.y < initialScrollOffset) {
           CGRect frame = self.headerView.frame;
           frame.size.height = self.tableView.tableHeaderView.frame.size.height - scrollView.contentOffset.y;
           frame.Origin.y = self.tableView.tableHeaderView.frame.Origin.y + scrollView.contentOffset.y;
           self.headerView.frame = frame;
    }
}

C'est tout. La seule différence visuelle par rapport à l’autre solution est que le contenu défilera maintenant avec le reste des cellules au lieu d’être recouvertes par celles-ci.

1
Tonnie

S'il vous plaît jeter un oeil à ce https://github.com/matteogobbi/MGSpotyViewController qui implémente le même effet selon vos besoins.

1
Prabhu

Je ne sais pas si cela vous aiderait ou non .. 

Réglez votre délégué de défilement à soi-même.

et ensuite implémenter ceci:

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

    if (scrollOffset == 0)
    {
        // then we are at the top
    }
    else if (scrollOffset + scrollViewHeight == scrollContentSizeHeight)
    {
        // then we are at the end
        // Do what you need here 
    }
}
0
Islam Adel