web-dev-qa-db-fra.com

UICollectionView - Défilement horizontal, disposition horizontale?

J'ai un UIScrollView qui présente une grille d'icônes. Si vous deviez imaginer la mise en page pour le Springboard iOS, vous seriez assez près pour corriger. Il a un défilement horizontal, paginé (tout comme Springboard). Cependant, il semble que la disposition ne soit pas tout à fait correcte. Il semble que les éléments soient disposés de haut en bas. En conséquence, ma dernière colonne ne contient que 2 lignes, en raison du nombre d'éléments à afficher. Je préférerais que ma dernière ligne de la dernière page contienne 2 éléments, comme vous le verriez dans le Tremplin.

Comment cela peut-il être accompli avec UICollectionView et ses classes associées? Dois-je écrire un UICollectionViewFlowLayout personnalisé?

55
Shadowman

1ère approche

Qu'en est-il de l'utilisation de UIPageViewController avec un tableau de UICollectionViewControllers? Vous devrez chercher le nombre approprié d'éléments dans chaque UICollectionViewController, mais cela ne devrait pas être difficile. Vous obtiendrez exactement le même look que le Springboard.

2ème approche

J'ai réfléchi à cela et à mon avis, vous devez définir:

self.collectionView.pagingEnabled = YES;

et créez votre propre présentation de vue de collection en sous-classant UICollectionViewLayout. À partir de l'objet de présentation personnalisé, vous pouvez accéder à self.collectionView, vous saurez ainsi quelle est la taille de la frame, numberOfSections et numberOfItemsInSection:. Avec cette information, vous pouvez calculer les cellules frames (dans prepareLayout) et collectionViewContentSize. Voici quelques articles sur la création de mises en page personnalisées:

3ème approche

Vous pouvez faire ceci (ou une approximation de celui-ci) sans créer la disposition personnalisée. Ajoutez UIScrollView dans la vue vide, activez la pagination. Dans la vue de défilement, ajoutez la vue de collection. Ajoutez-y ensuite une contrainte de largeur, vérifiez dans le code le nombre d’éléments que vous possédez et affectez à constant la valeur correcte, par exemple. (self.view.frame.size.width * numOfScreens). Voici à quoi cela ressemble (les chiffres sur les cellules indiquent le indexPath.row): https://www.dropbox.com/s/ss4jdbvr511azxz/collection_view.mov Si vous n'êtes pas satisfait de la façon dont les cellules sont commandées, je crains fort que ce ne soit le cas aller avec 1. ou 2.

67
Arek Holko

Avez-vous essayé de définir le sens de défilement de votre UICollectionViewFlowLayout sur horizontal?

[yourFlowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];

Et si vous souhaitez que la page se comporte comme le springboard, vous devez activer la pagination sur la vue de votre collection de la manière suivante:

[yourCollectionView setPagingEnabled:YES];
91
Erik Hunter

Vous devez réduire la hauteur de UICollectionView à sa hauteur de cellule/d’élément et sélectionner "Horizontal" dans la liste "Scroll Direction "comme dans la capture d'écran ci-dessous. Ensuite, il défilera horizontalement en fonction du numberOfItems que vous avez renvoyé dans son implémentation de source de données.

enter image description here

34
Deepak Thakur

Si vous définissez UICollectionViewFlowLayout dans le code, cela annulera les configurations d'Interface Builder. Par conséquent, vous devez redéfinir le scrollDirection.

let layout = UICollectionViewFlowLayout()
...
layout.scrollDirection = .Horizontal
self.awesomeCollectionView.collectionViewLayout = layout
12
DazChong

Juste pour le plaisir, une autre approche serait de simplement laisser le jeu de pagination et de défilement horizontal, d’ajouter une méthode qui change l’ordre des éléments du tableau à convertir de 'haut en bas, de gauche à droite' en visuellement 'De gauche à droite, de haut en bas' et remplissez les cellules intermédiaires avec des cellules cachées vides pour que l'espacement soit correct. Dans le cas de 7 éléments dans une grille de 9, ceci ressemblerait à ceci:

[1][4][7]
[2][5][ ]
[3][6][ ]

devraient devenir

[1][2][3]
[4][5][6]
[7][ ][ ]

donc 1 = 1, 2 = 4, 3 = 7 etc. et 6 = vide. Vous pouvez les réorganiser en calculant le nombre total de lignes et de colonnes, puis calculer le numéro de ligne et de colonne pour chaque cellule, modifier la ligne de la colonne, et inversement, pour obtenir les nouveaux index. Lorsque la cellule n'a pas de valeur correspondant à l'image, vous pouvez retourner une cellule vide et définir cell.hidden = YES; à elle.

Cela fonctionne très bien dans une application de table de son que j'ai construite, donc si quelqu'un veut du code fonctionnel, je l'ajouterai. Il ne faut que peu de code pour que cette astuce fonctionne, ça sonne plus fort que ça!

Mise à jour

Je doute que ce soit la meilleure solution, mais à la demande, voici le code de travail:

- (void)viewDidLoad {
    // Fill an `NSArray` with items in normal order
    items = [NSMutableArray arrayWithObjects:
             [NSDictionary dictionaryWithObjectsAndKeys:@"Some label 1", @"label", @"Some value 1", @"value", nil],
             [NSDictionary dictionaryWithObjectsAndKeys:@"Some label 2", @"label", @"Some value 2", @"value", nil],
             [NSDictionary dictionaryWithObjectsAndKeys:@"Some label 3", @"label", @"Some value 3", @"value", nil],
             [NSDictionary dictionaryWithObjectsAndKeys:@"Some label 4", @"label", @"Some value 4", @"value", nil],
             [NSDictionary dictionaryWithObjectsAndKeys:@"Some label 5", @"label", @"Some value 5", @"value", nil],
              nil
              ];

    // Calculate number of rows and columns based on width and height of the `UICollectionView` and individual cells (you might have to add margins to the equation based on your setup!)
    CGFloat w = myCollectionView.frame.size.width;
    CGFloat h = myCollectionView.frame.size.height;
    rows = floor(h / cellHeight);
    columns = floor(w / cellWidth);
}

// Calculate number of sections
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
    return ceil((float)items.count / (float)(rows * columns));
}

// Every section has to have every cell filled, as we need to add empty cells as well to correct the spacing
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    return rows*columns;
}

// And now the most important one
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier@"myIdentifier" forIndexPath:indexPath];

    // Convert rows and columns
    int row = indexPath.row % rows;
    int col = floor(indexPath.row / rows);
    // Calculate the new index in the `NSArray`
    int newIndex = ((int)indexPath.section * rows * columns) + col + row * columns;

    // If the newIndex is within the range of the items array we show the cell, if not we hide it
    if(newIndex < items.count) {
        NSDictionary *item = [items objectAtIndex:newIndex];
        cell.label.text = [item objectForKey:@"label"];
        cell.hidden = NO;
    } else {
        cell.hidden = YES;
    }

    return cell;
}

Si vous souhaitez utiliser la méthode didSelectItemAtIndexPath, vous devez utiliser la même conversion que celle utilisée dans cellForItemAtIndexPath pour obtenir l'élément correspondant. Si vous avez des marges de cellule, vous devez les ajouter au calcul des lignes et des colonnes, car elles doivent être correctes pour que cela fonctionne.

8
Tum

Ce code fonctionne bien dans Swift 3.1 et Xcode 8.3.2

override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()

        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .horizontal
        self.collectionView.collectionViewLayout = layout
        self.collectionView!.contentInset = UIEdgeInsets(top: -10, left: 0, bottom:0, right: 0)

        if let layout = self.collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
            layout.minimumInteritemSpacing = 0
            layout.minimumLineSpacing = 0
            layout.itemSize = CGSize(width: self.view.frame.size.width-40, height: self.collectionView.frame.size.height-10)
            layout.invalidateLayout()
        }

    }
7
Prashant Gaikwad

De @Erik Hunter, je poste le code complet pour make horizontal UICollectionView

UICollectionViewFlowLayout *collectionViewFlowLayout = [[UICollectionViewFlowLayout alloc] init];
[collectionViewFlowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
self.myCollectionView.collectionViewLayout = collectionViewFlowLayout;

En rapide

let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .Horizontal
self.myCollectionView.collectionViewLayout = layout

Dans Swift 3.0

let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
self.myCollectionView.collectionViewLayout = layout

J'espère que cette aide

6
Phan Van Linh

Je travaille sur Xcode 6.2 et pour le défilement horizontal, j’ai changé le sens du défilement dans l’inspecteur d’attributs.

cliquez sur collectionView-> attribut attribut-> défilement Direction-> changer à l'horizontale

enter image description here J'espère que ça aide quelqu'un.

6

Nous pouvons utiliser le même comportement Springboard avec UICollectionView et pour cela, nous devons écrire du code pour une présentation personnalisée.

Je l'ai atteint avec mon implémentation de classe de présentation personnalisée avec "SMCollectionViewFillLayout"

Dépôt de code:

https://github.com/smindia1988/SMCollectionViewFillLayout

Sortie comme ci-dessous:

1.png

First.png

2_Code_H-Scroll_V-Fill.png

enter image description here

3_Output_H-Scroll_V-Fill.png enter image description here

4_Code_H-Scroll_H-Fill.png enter image description here

5_Output_H-Scroll_H-Fill.png enter image description here

6
Sandip Patel - SM

pour xcode 8 je l'ai fait et cela a fonctionné:

6
Gulz

Vous pouvez écrire une mise en page personnalisée UICollectionView pour y parvenir, voici une image démo de mon implémentation:

demo image

Voici le référentiel de code: KSTCollectionViewPageHorizontalLayout

@iPhoneDev (cela peut peut-être vous aider aussi)

1
Zeng