2015-02-02 13 views
27

problempodrzędny ramka jest niepoprawna podczas tworzenia UICollectionViewCell

stworzyłem UICollectionViewController ze zwyczajem UICollectionViewCell. Niestandardowa komórka zawiera duże i prostokątne UIView (o nazwie colorView) i UILabel (o nazwie nazwaLabel).

Gdy kolekcja zostanie po raz pierwszy wypełniona komórkami, a ja wydrukuję colorView.frame, wydrukowane ramki mają nieprawidłowe wartości. Wiem, że są one niepoprawne, ponieważ ramki colorView są większe niż ramka komórki, nawet jeśli colorView zostanie poprawnie narysowany.

Jeśli jednak przewinąć kolekcję wystarczająco, aby uruchomić ponowne użycie wcześniej utworzonej komórki, colorView.frame ma teraz poprawne wartości! Potrzebuję poprawnych ramek, ponieważ chcę zastosować zaokrąglone rogi do warstwy colorView i potrzebuję prawidłowego rozmiaru coloView, aby to zrobić. Nawiasem mówiąc, w przypadku, gdy zastanawiasz się, colorView.bounds ma również tę samą wartość nieprawidłowego rozmiaru co colorView.frame.

Pytanie

Dlaczego podczas tworzenia klatek nieprawidłowe komórki?

A teraz jakiś kod

To mój UICollectionViewCell:

class BugCollectionViewCell: UICollectionViewCell { 
    @IBOutlet weak var colorView: UIView! 
    @IBOutlet weak var nameLabel: UILabel! 
} 

i to jest UICollectionViewController:

import UIKit 

let reuseIdentifier = "Cell" 
let colors = [UIColor.redColor(), UIColor.blueColor(), 
       UIColor.greenColor(), UIColor.purpleColor()] 
let labels = ["red", "blue", "green", "purple"] 

class BugCollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout { 
    override func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int { 
     return 1 
    } 

    override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 
     return colors.count 
    } 

    override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { 
     let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as BugCollectionViewCell 

     println("ColorView frame: \(cell.colorView.frame) Cell frame: \(cell.frame)") 

     cell.colorView.backgroundColor = colors[indexPath.row] 
     cell.nameLabel.text = labels[indexPath.row] 

     return cell 
    } 

    func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize { 
     let width = self.collectionView?.frame.width 
     let height = self.collectionView?.frame.height 
     return CGSizeMake(width!, height!/2) 
    } 
} 

Widok kolekcja jest ustawiony aby pokazać dwie komórki w tym samym czasie, w pionie, każda komórka zawierająca duży prostokąt pomalowany kolorem i etykietą z nazwą koloru.

Kiedy wystarczy uruchomić powyższy kod na symulatorze, otrzymuję następujący wynik: wydrukowany

ColorView frame: (0.0,0.0,320.0,568.0) Cell frame: (0.0,0.0,375.0,333.5) 
ColorView frame: (0.0,0.0,320.0,568.0) Cell frame: (0.0,343.5,375.0,333.5) 

Jest to dziwny wynik - colorView.frame ma wysokość 568 punktów, podczas gdy rama jest komórka tylko 333,5 punktu wysoki.

Gdybym przeciągnij CollectionView dół a komórka zostanie ponownie użyty następujący wynik jest drukowany:

ColorView frame: (8.0,8.0,359.0,294.0) Cell frame: (0.0,1030.5,375.0,333.5) 
ColorView frame: (8.0,8.0,359.0,294.0) Cell frame: (0.0,343.5,375.0,333.5) 

Coś, co nie mogę zrozumieć, stało się po drodze, która koryguje klatki Colorview.

Myślę, że ma to coś wspólnego z faktem, że komórka jest ładowana z końcówki, więc zamiast używać inicjalizatora init (frame: frame) kontroler używa inicjatora init (koder: aCoder), więc wkrótce ponieważ komórka jest tworzona, prawdopodobnie zawiera pewną domyślną ramkę, której nie mogę edytować w żaden sposób.

Doceniam każdą pomoc, która pozwoli mi zrozumieć, co się dzieje!

Używam Xcode 6.1.1. z pakietem SDK iOS 8.1.

+0

Jak pozycjonujesz ColorView? Nie korzystasz z prawa autolayout? Myślę, że to, co się z tobą dzieje, to układ widoku jest ładowany z stalówki i tłumaczony na autolayout. Ale rozmiar kontrolera viewboard kontrolera różni się od symulatora. Użyj autolayout, aby ustawić swoje poglądy, a rzeczy powinny działać w tym momencie. –

+0

Hej @ CharlieWu, rzeczywiście używam automatycznego układu ... colorView i nameLabel są w pełni ograniczone ... –

Odpowiedz

37

można uzyskać ostateczne ramy swojej komórce nadrzędnymi layoutIfNeeded() w niestandardowej klasy komórki tak:

override func layoutIfNeeded() { 
    super.layoutIfNeeded() 
    self.subView.layer.cornerRadius = self.subView.bounds.width/2 
} 

następnie w UICollectionView metoda dane Źródło cellForRowAtIndexPath: to zrobić:

let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as! CustomCollectionViewCell 
cell.setNeedsLayout() 
cell.layoutIfNeeded() 
+3

Pierwszy tutaj przykładowy kod jest ostatecznie prawdziwą odpowiedzią. Dziękuję Ci. – Fattie

+0

Znów miałem ten sam problem, a twoja odpowiedź była lepsza niż moja. :-) –

+0

To samo rozwiązanie dla 'UITableViewCell' również. –

8

Ok, teraz rozumiem, że komórka jest tworzona przed automatycznym układem definiującym jej ramki.Z tego powodu w momencie tworzenia granice są błędne. Gdy komórki są ponownie użyte, ramki zostały już skorygowane.

Wystąpił ten problem podczas tworzenia niestandardowego interfejsu UIView, który umieszczał niektóre warstwy i subviews w określonych współrzędnych. Po utworzeniu wystąpień tego UIView, umieszczenie subviews było błędne (ponieważ układ automatyczny jeszcze się nie rozpoczął).

Dowiedziałem się, że zamiast konfigurować subviews widoków na init(coder: aCoder) musiałem przesłonić metodę layoutSubviews(). Jest to wywoływane, gdy automatyczny układ pyta każdy widok o układ własnych podstron, więc w tym momencie przynajmniej widok nadrzędny ma poprawną ramkę i mogę go użyć do poprawnego ułożenia podobrazów.

Prawdopodobnie, gdybym użył wiązań na niestandardowym kodzie widoku zamiast zajmować się rozmiarami ramek i pozycjonowaniem, układ byłby wykonany prawidłowo i nie byłoby konieczne przesłonięcie layoutSubviews().

+0

Najlepsze rozwiązanie do tej pory! Wielkie dzięki :) – inokey

+0

Najlepsze miejsce do dodania logiki do mojego widoku dostosowywania. – JerryZhou

13

Miałem ten sam problem z UICollectionViewCell przy użyciu ograniczeń układu automatycznego.

Musiałem zadzwonić pod numer layoutIfNeeded, zanim skonfigurowałem mój wydział, który polegał na szerokości ramki widoku.

+2

Gdzie dokładnie dzwonisz do layoutIfNeeded? Pamiętam, że próbowałem wywołać to w init kontrolera widoku, ale nie działało, wydawało się, że komórki zostały wczytane przed uruchomieniem automatycznego układu, nawet po kolejkowaniu z layoutIfNeeded ... –

+0

Sidenote: '- (void) awakeFromNib {[super awakeFromNib]; [self layoutIfNeeded];/* ramki już tu obliczone * /} ' –

+0

Genialny! Dziękuję Ci. – inokey

5

Wystąpił ten problem podczas rysowania grafiki głównej w iOS 10, Swift 3.0.1.

Dodaj tę metodę UICollectionView podklasy:

override func didMoveToSuperview() { 
    super.didMoveToSuperview() 
    setNeedsLayout() 
    layoutIfNeeded() 
} 

Moim problemem było to, że rdzeń graficzny kształty nie zostały obliczone prawidłowo, ponieważ layoutSubviews() nie został powołany.

+0

Skąd dodałeś ten kod? – Magnas

+1

@Magnas w podklasie UICollectionViewCell. –