Ändern Sie die UICollectionViewCell-Größe in verschiedenen Geräteorientierungen

100

Ich benutze ein UICollectionViewmit UICollectionViewFlowLayout.

Ich stelle die Größe jeder Zelle durch die ein

collectionView:layout:sizeForItemAtIndexPath:

Beim Wechsel von Hoch- zu Querformat möchte ich die Größe jeder Zelle so anpassen, dass sie vollständig der Größe der CollectionView entspricht, ohne dass zwischen den Zellen Platz zum Auffüllen bleibt.

Fragen:

1) Wie ändere ich die Größe einer Zelle nach einem Rotationsereignis?

2) Und noch besser, wie kann man das Layout so gestalten, dass die Zellen immer auf die gesamte Größe des Bildschirms passen?

Fmessina
quelle
Die Antwort von followben wird derzeit akzeptiert, hat jedoch einige Probleme: Es wird ein Konsolenfehler ausgegeben und die Animation auf die neue Größe wird nicht korrekt ausgeführt. Siehe meine Antwort für die korrekte Implementierung.
Memmons
@ MichaelG.Emmons: Ihre Antwort funktioniert besser, wenn in einer Sammlungsansicht jeweils nur eine Zelle in voller Größe angezeigt wird. In diesem Fall ist es sinnvoll, dass sich UIKit über die Rotation beschwert, da diese sizeForItemAtIndexPathvor dem Anruf abgefragt wird didRotateFromInterfaceOrientation. Bei einer Sammlungsansicht mit mehreren Zellen auf dem Bildschirm führt das Ungültigmachen des Layouts vor dem Drehen jedoch zu einem unangenehmen, sichtbaren Größensprung, bevor sich die Ansicht dreht. In diesem Fall glaube ich, dass meine Antwort immer noch die korrekteste Implementierung ist.
Followben
@followben Stimmen Sie zu, dass jeder seine Probleme in verschiedenen Anwendungsfällen hat. In diesem Fall gibt das OP jedoch an, I would like to adjust the size of each cell to **completely fit the size of the CollectionView**welche Lösung genau in meiner Antwort vorgeschlagen wurde. Wenn Sie meine Lösung in Ihre Antwort aufnehmen und notieren könnten, welcher Ansatz unter welchen Bedingungen am besten funktioniert, wäre das für mich gut genug.
Memmons

Antworten:

200

1) Sie können mehrere Layoutobjekte verwalten und austauschen, aber es gibt einen einfacheren Weg. Fügen Sie Ihrer UICollectionViewControllerUnterklasse einfach Folgendes hinzu und passen Sie die Größen nach Bedarf an:

- (CGSize)collectionView:(UICollectionView *)collectionView
                  layout:(UICollectionViewLayout *)collectionViewLayout
  sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{    
    // Adjust cell size for orientation
    if (UIDeviceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation])) {
        return CGSizeMake(170.f, 170.f);
    }
    return CGSizeMake(192.f, 192.f);
}

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
    [self.collectionView performBatchUpdates:nil completion:nil];
}

Durch Aufrufen -performBatchUpdates:completion:wird das Layout ungültig und die Größe der Zellen mit Animation wird geändert (Sie können einfach Null an beide Blockparameter übergeben, wenn Sie keine zusätzlichen Anpassungen vornehmen müssen).

2) Anstatt die Elementgrößen fest zu codieren -collectionView:layout:sizeForItemAtIndexPath, teilen Sie einfach die Höhe oder Breite der Grenzen der CollectionView durch die Anzahl der Zellen, die auf den Bildschirm passen sollen. Verwenden Sie die Höhe, wenn Ihre collectionView horizontal scrollt, oder die Breite, wenn sie vertikal scrollt.

followben
quelle
3
warum nicht einfach anrufen [self.collectionView.collectionViewLayout invalidateLayout];?
user102008
7
@ user102008 Durch Aufrufen invalidateLayoutwerden die Zellen mit der richtigen Größe neu gezeichnet , aber -performBatchUpdates:completion:die Änderungen werden animiert, was meiner Meinung nach viel besser aussieht.
Followben
4
In meinem Fall ändert der Code die Größe der Sammlungsansichtszelle erst, wenn ich über den Bildschirm scrolle.
Newguy
9
didRotateFromInterfaceOrientationveraltet in iOS 8
János
8
Unter iOS8 rufe ich coordinator.animateAlongsideTransitionan viewWillTransitionToSizeund rufe performBatchUpdatesinnerhalb seines animationBlocks an. Dies ergibt einen schönen Animationseffekt.
Mike Taverne
33

Wenn Sie keine zusätzlichen Animationen benötigen , erzwingen Sie performBatchUpdates:completion:einfach invalidateLayoutdas Neuladen des collectionViewLayout.

- (void)viewWillLayoutSubviews
{
    [super viewWillLayoutSubviews];
    [self.collectionView.collectionViewLayout invalidateLayout];
}
Hai Feng Kao
quelle
13

Ich habe mit zwei UICollectionViewFlowLayout gelöst. Eine für Porträt und eine für Landschaft. Ich ordne sie meiner collectionView in -viewDidLoad zu

self.portraitLayout = [[UICollectionViewFlowLayout alloc] init];
self.landscapeLayout = [[UICollectionViewFlowLayout alloc] init];

UIInterfaceOrientation orientationOnLunch = [[UIApplication sharedApplication] statusBarOrientation];

if (UIInterfaceOrientationIsPortrait(orientationOnLunch)) {
    [self.menuCollectionView setCollectionViewLayout:self.portraitLayout];
} else {
    [self.menuCollectionView setCollectionViewLayout:self.landscapeLayout];
}

Dann habe ich einfach meine collectionViewFlowLayoutDelgate-Methoden wie folgt geändert

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{
    CGSize returnSize = CGSizeZero;

    if (collectionViewLayout == self.portraitLayout) {
        returnSize = CGSizeMake(230.0, 120.0);
    } else {
        returnSize = CGSizeMake(315.0, 120.0);
    }

    return returnSize;
}

Zuletzt wechsle ich beim Drehen von einem Layout zu einem anderen

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation{
    if (UIInterfaceOrientationIsPortrait(fromInterfaceOrientation)) {
        [self.menuCollectionView setCollectionViewLayout:self.landscapeLayout animated:YES];
    } else {
        [self.menuCollectionView setCollectionViewLayout:self.portraitLayout animated:YES];
    }
}
Fiveagle
quelle
8

Es gibt eine einfache Möglichkeit, die Zellengröße der Sammlungsansicht festzulegen:

UICollectionViewFlowLayout *layout = (id) self.collectionView.collectionViewLayout;
layout.itemSize = CGSizeMake(cellSize, cellSize);

Ich bin mir nicht sicher, ob es animierbar ist.

Dannie P.
quelle
Ich musste dies innerhalb von viewWillLayoutSubviews mit Hai Feng Kaos Antwort verwenden: stackoverflow.com/a/14776915/2298002
Gewächshaus
7

Swift: Sammlungsansichtszelle, die n% der Bildschirmhöhe beträgt

Ich brauchte eine Zelle, die einen bestimmten Prozentsatz der Ansichtshöhe hatte und deren Größe sich mit der Gerätedrehung ändern würde.

Mit Hilfe von oben ist hier die Lösung

override func viewDidLoad() {
    super.viewDidLoad()
    automaticallyAdjustsScrollViewInsets = false
    // if inside nav controller set to true
}

override func willRotateToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) {
    collectionViewLayout.invalidateLayout()
}

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
    return CGSize(width: 100, height: collectionView.frame.height * 0.9)
}
DogCoffee
quelle
2

Wenn Sie verwenden. autolayoutSie müssen sich invalidate layoutbeim Drehen nur in Ihrem Ansichts-Controller befinden und offsetin Ihrer Unterklasse für das Flusslayout anpassen .

Also, in Ihrer Ansicht Controller -

override func willRotateToInterfaceOrientation(toInterfaceOrientation:     UIInterfaceOrientation, duration: NSTimeInterval) {
    self.galleryCollectionView.collectionViewLayout.invalidateLayout()
}

Und in deinem FlowLayout Subclass

override func prepareLayout() {
    if self.collectionView!.indexPathsForVisibleItems().count > 0{
    var currentIndex : CGFloat!
    currentIndex = CGFloat((self.collectionView!.indexPathsForVisibleItems()[0] as! NSIndexPath).row)
    if let currentVal = currentIndex{
        self.collectionView!.contentOffset = CGPointMake(currentIndex * self.collectionView!.frame.width, self.collectionView!.contentOffset.y);
    }   
    }     
}
toofani
quelle
1
Das funktioniert super! willRotateToInterfaceOrientationist in iOS 8 veraltet, viewWillTransitionToSizefunktioniert aber genauso gut.
Keegan3d