Jak wyśrodkować w poziomie komórki UICollectionView?


124

Zrobiłem kilka badań, ale nie mogłem znaleźć żadnego przykładu kodu, jak wyśrodkować komórki w UICollectionView w poziomie.

zamiast pierwszej komórki, która jest taka X00 , chcę, aby była taka 0X0 . czy jest jakiś sposób, aby to osiągnąć?

EDYTOWAĆ:

wizualizować to, czego chcę:

wprowadź opis obrazu tutaj

Potrzebuję, aby wyglądał jak wersja B, gdy istnieje tylko jeden element w CollectionView. Kiedy mam więcej niż jeden element, to powinno być jak wersja A, ale z większą liczbą elementów.

W tej chwili wygląda to jak wersja A, gdy mam tylko 1 element i zastanawiam się, jak mogę sprawić, by wyglądała jak B.

Dzięki za pomoc!


Czy nie jest łatwiej dopasować komórkę do szerokości widoku kolekcji, a następnie wyśrodkować sam widok kolekcji w jej nadrzędnym?
Arthur Gevorkyan

tak, są co najmniej dwa sposoby, aby to zrobić, pierwszy (szybki) to zwiększenie szerokości komórki całego ekranu i wyśrodkowanie widoku podrzędnego. drugi (po prawej) zaimplementuj niestandardowy układ widoku kolekcji
sage444

Ostatecznie będzie więcej komórek pochodzących z backendu, wypełnienie całej szerokości nie byłoby dobrym pomysłem
RaptoX

zwiększenie szerokości wystarczy ustawić na środku
Kishore Kumar

Odpowiedzi:


229

Używanie biblioteki nie jest dobrym pomysłem, jeśli twoim celem jest tylko to, tj. Wyśrodkowanie wyrównanie.

Lepiej możesz wykonać to proste obliczenie w swojej funkcji collectionViewLayout.

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets {

    let totalCellWidth = CellWidth * CellCount
    let totalSpacingWidth = CellSpacing * (CellCount - 1)

    let leftInset = (collectionViewWidth - CGFloat(totalCellWidth + totalSpacingWidth)) / 2
    let rightInset = leftInset

    return UIEdgeInsets(top: 0, left: leftInset, bottom: 0, right: rightInset)
}

2
@ DarshanPatel.Dziękuję za wiele odpowiedzi, zaimplementowałem to i wiersze znalazły się na środku tak, jak powinno, ale teraz problem polega na tym, że nie mogę przewinąć do pierwszej pozycji. Kiedy próbuję przewinąć do pierwszego elementu, przenosi mnie z powrotem do zmodyfikowanych UIEdgeInsets. Możesz zobaczyć moją aplikację demonstracyjną github.com/anirudha-music/CollectionViewCenter
Anirudha Mahale

5
W języku Swift 3 nowa sygnatura metody to collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int).
Kamczatka

1
w jaki sposób możesz pobrać cellWidth, czy jest to możliwe za pomocą metody cellForItemAt? Próbowałem i zwróciło zero .. Szerokość komórki dla mnie zmienia się w zależności od rozmiaru ekranu .. @DarshanPatel.
Chris

10
@DarshanPatel. Twoja odpowiedź może czasami dać negatywną wartość na mniejszych urządzeniach. Rozważ skorzystanie z maksymalnego czeku na swoją leftInsetwartość w następujący sposób:let leftInset = max(0.0, (self.collectionView.bounds.width - CGFloat(totalCellWidth + totalSpacingWidth)) / 2)
Rhuari Glen

3
Jeśli nie tworzysz podklasy UICollectionViewController, upewnij się, że Twoja klasa jest zgodna z UICollectionViewDelegateFlowLayout, w przeciwnym razie nie zadziała
Saeed Ir

58

Swift 5.1

func centerItemsInCollectionView(cellWidth: Double, numberOfItems: Double, spaceBetweenCell: Double, collectionView: UICollectionView) -> UIEdgeInsets {
    let totalWidth = cellWidth * numberOfItems
    let totalSpacingWidth = spaceBetweenCell * (numberOfItems - 1)
    let leftInset = (collectionView.frame.width - CGFloat(totalWidth + totalSpacingWidth)) / 2
    let rightInset = leftInset
    return UIEdgeInsets(top: 0, left: leftInset, bottom: 0, right: rightInset)
}

Swift 4.2

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {

    let totalCellWidth = 80 * collectionView.numberOfItems(inSection: 0)
    let totalSpacingWidth = 10 * (collectionView.numberOfItems(inSection: 0) - 1)

    let leftInset = (collectionView.layer.frame.size.width - CGFloat(totalCellWidth + totalSpacingWidth)) / 2
    let rightInset = leftInset

    return UIEdgeInsets(top: 0, left: leftInset, bottom: 0, right: rightInset)

}

Szybki 3

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets {

        let totalCellWidth = 80 * collectionView.numberOfItems(inSection: 0)
        let totalSpacingWidth = 10 * (collectionView.numberOfItems(inSection: 0) - 1)

        let leftInset = (collectionView.layer.frame.size.width - CGFloat(totalCellWidth + totalSpacingWidth)) / 2
        let rightInset = leftInset

        return UIEdgeInsetsMake(0, leftInset, 0, rightInset)

    }

nie zapomnij dodać protokołu

UICollectionViewDelegateFlowLayout

ograniczenie może @ashForIos
Ahmed Safadi

Twoja odpowiedź działa dobrze, gdy istnieją komórki, które mieszczą się w collectionView, gdy liczba komórek wzrasta, komórki znajdują się w środku i nie można przewijać do pierwszej komórki ani do ostatniej.
NickCoder,

2
@Vitalii 80 oznacza szerokość komórki i 10 odstęp między komórkami, jeśli przeczytasz nazwę zmiennej, zrozumiesz, co to znaczy: P
Ahmed Safadi

Dzięki rozwiązaniu Swift 4.2 jest łatwiejsze! Po prostu pamiętaj, aby ustawić wartość „80” na dowolną rzeczywistą szerokość obiektu-komórki.
John Pitts

25

Wypróbuj to dla Swift 4

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        let cellWidth : CGFloat = 165.0

        let numberOfCells = floor(self.view.frame.size.width / cellWidth)
        let edgeInsets = (self.view.frame.size.width - (numberOfCells * cellWidth)) / (numberOfCells + 1)

        return UIEdgeInsetsMake(15, edgeInsets, 0, edgeInsets)
    }

Dodaj swoją cellWidth zamiast 165.0


1
to najlepsza odpowiedź. Z najprostszą matematyką. działa z dowolną liczbą wierszy i kolumn
rickrvo

20

Używam KTCenterFlowLayout do tego, i to działa świetnie. Jest to niestandardowa podklasa, UICollectionViewFlowLayoutktóra wyśrodkowuje komórki tak, jak chcesz. (Uwaga: nie jest to prosta rzecz do rozwiązania przez opublikowanie kodu, dlatego też łączę się z projektem GitHub!)


Nie mogłem tego zrobić z IB. Ta biblioteka działała na mnie jak urok. Właśnie zainstalowałem kapsułę i zmieniłem klasę układu w IB!
tagirkaZ

15

Wersja odpowiedzi Darshana Patela z obiektywnym C :

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(nonnull UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
    CGFloat totalCellWidth = kItemWidth * self.dataArray.count;
    CGFloat totalSpacingWidth = kSpacing * (((float)self.dataArray.count - 1) < 0 ? 0 :self.dataArray.count - 1);
    CGFloat leftInset = (self.bounds.size.width - (totalCellWidth + totalSpacingWidth)) / 2;
    CGFloat rightInset = leftInset;
    UIEdgeInsets sectionInset = UIEdgeInsetsMake(0, leftInset, 0, rightInset);
    return sectionInset;
}

dzięki. Działa dobrze z jednym rzędem. ale tworzy problem w wielu wierszach. nie mogę tutaj dodać adresu URL, aby pokazać zrzut ekranu. . ale możesz dodać „yynoalzg” w małym adresie URL. wpadniesz na pomysł. Sekcja złota ma 4 rekordy. Czwarty powinien znajdować się w nowej linii. . ale po tej metodzie wyświetla się tak ... daj mi znać, jeśli masz jakiś pomysł.
Hitarth

6

Nieznacznie modyfikując odpowiedź @Safad Funy, to zadziałało dla mnie w najnowszej wersji Swift i iOS. W tym przypadku chciałem, aby szerokość komórek była jedną trzecią rozmiaru widoku kolekcji.

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {

  let totalCellWidth = Int(collectionView.layer.frame.size.width) / 3 * collectionView.numberOfItems(inSection: 0)
  let totalSpacingWidth = (collectionView.numberOfItems(inSection: 0) - 1)

  let leftInset = (collectionView.layer.frame.size.width - CGFloat(totalCellWidth + totalSpacingWidth)) / 2
  let rightInset = leftInset

  return UIEdgeInsetsMake(0, leftInset, 0, rightInset)
}

2
To zadziałało dla mnie szczególnie, gdy jest tylko jedna komórka.
Dasoga

6

Możesz użyć tego rozszerzenia (Swift 4).

Można go wyśrodkować komórek, jeśli collectionViewmają layout.estimatedItemSize = UICollectionViewFlowLayoutAutomaticSize.

Działa z każdym rozmiarem komórek i działa idealnie, gdy scrollDirection = .horizontal

public extension UICollectionView {
    func centerContentHorizontalyByInsetIfNeeded(minimumInset: UIEdgeInsets) {
        guard let layout = collectionViewLayout as? UICollectionViewFlowLayout,
            layout.scrollDirection == .horizontal else {
                assertionFailure("\(#function): layout.scrollDirection != .horizontal")
                return
        }

        if layout.collectionViewContentSize.width > frame.size.width {
            contentInset = minimumInset
        } else {
            contentInset = UIEdgeInsets(top: minimumInset.top,
                                        left: (frame.size.width - layout.collectionViewContentSize.width) / 2,
                                        bottom: minimumInset.bottom,
                                        right: 0)
        }
    }
}


final class Foo: UIViewController {
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        collectionView.centerContentHorizontalyByInsetIfNeeded(minimumInset: yourDefaultInset)
    }
}

Mam nadzieję, że to ci pomoże!


1
Wyświetlanie błędu: Wątek 1: EXC_BAD_ACCESS (kod = 2, adres = 0x118ffde58)
atulkhatri

4

Swift 4.2 (poziomo i pionowo). To niewielkie ulepszenie kodu Różowej Pantery i wielkie dzięki mu!


func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
    let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
    let cellWidth: CGFloat = flowLayout.itemSize.width
    let cellHieght: CGFloat = flowLayout.itemSize.height
    let cellSpacing: CGFloat = flowLayout.minimumInteritemSpacing
    let cellCount = CGFloat(collectionView.numberOfItems(inSection: section))
    var collectionWidth = collectionView.frame.size.width
    var collectionHeight = collectionView.frame.size.height
    if #available(iOS 11.0, *) {
        collectionWidth -= collectionView.safeAreaInsets.left + collectionView.safeAreaInsets.right
        collectionHeight -= collectionView.safeAreaInsets.top + collectionView.safeAreaInsets.bottom
    }
    let totalWidth = cellWidth * cellCount + cellSpacing * (cellCount - 1)
    let totalHieght = cellHieght * cellCount + cellSpacing * (cellCount - 1)
    if totalWidth <= collectionWidth {
        let edgeInsetWidth = (collectionWidth - totalWidth) / 2

        print(edgeInsetWidth, edgeInsetWidth)
        return UIEdgeInsets(top: 5, left: edgeInsetWidth, bottom: flowLayout.sectionInset.top, right: edgeInsetWidth)
    } else {
        let edgeInsetHieght = (collectionHeight - totalHieght) / 2
        print(edgeInsetHieght, edgeInsetHieght)
        return UIEdgeInsets(top: edgeInsetHieght, left: flowLayout.sectionInset.top, bottom: edgeInsetHieght, right: flowLayout.sectionInset.top)

    }
}

Upewnij się, że Twoja klasa jest zgodna z protokołem UICollectionViewDelegateFlowLayout


Naprawdę, twój kod działa świetnie, dzięki stary; )
steveSarsawa

4

Oto nowsza wersja Swift 5, która działa również dobrze, gdy komórki mają więcej niż jeden wiersz:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
    let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
    let cellWidth: CGFloat = flowLayout.itemSize.width
    let cellSpacing: CGFloat = flowLayout.minimumInteritemSpacing
    var cellCount = CGFloat(collectionView.numberOfItems(inSection: section))
    var collectionWidth = collectionView.frame.size.width
    var totalWidth: CGFloat
    if #available(iOS 11.0, *) {
        collectionWidth -= collectionView.safeAreaInsets.left + collectionView.safeAreaInsets.right
    }
    repeat {
        totalWidth = cellWidth * cellCount + cellSpacing * (cellCount - 1)
        cellCount -= 1
    } while totalWidth >= collectionWidth

    if (totalWidth > 0) {
        let edgeInset = (collectionWidth - totalWidth) / 2
        return UIEdgeInsets.init(top: flowLayout.sectionInset.top, left: edgeInset, bottom: flowLayout.sectionInset.bottom, right: edgeInset)
    } else {
        return flowLayout.sectionInset
    }
}

Upewnij się, że Twoja klasa jest zgodna z UICollectionViewDelegateFlowLayoutprotokołem.


3

Szybki 4

extension ViewController: UICollectionViewDelegateFlowLayout {

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {

        let cellWidth: CGFloat = 170.0 // Your cell width

        let numberOfCells = floor(view.frame.size.width / cellWidth)
        let edgeInsets = (view.frame.size.width - (numberOfCells * cellWidth)) / (numberOfCells + 1)

        return UIEdgeInsetsMake(0, edgeInsets, 0, edgeInsets)
    }

 }

2

Dla osób, które chcą tylko dodać dopełnienie ( góra, lewo, dół, prawo ):

Dodaj protokół UICollectionViewDelegateFlowLayout

Ten przykład pokazuje dopełnienie po lewej i prawej stronie 40.

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {        
    return UIEdgeInsetsMake(0, 40, 0, 40)
}

2

SWIFT 4.2

private lazy var contentView: UICollectionView = {
        let layoutView: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
            layoutView.scrollDirection = .horizontal
            layoutView.minimumInteritemSpacing = 0
            layoutView.minimumLineSpacing = 5

        let collectionView: UICollectionView = UICollectionView(frame: .zero, collectionViewLayout: layoutView)
            collectionView.dataSource = self
            collectionView.delegate = self
            collectionView.showsHorizontalScrollIndicator = false
            collectionView.isPagingEnabled = true
            collectionView.registerCell(Cell.self)
            collectionView.backgroundColor = .clear
            collectionView.translatesAutoresizingMaskIntoConstraints = false
        return collectionView
    }()

//

extension CustomCollectionView: UICollectionViewDelegateFlowLayout {
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

        return CGSize(width: collectionView.frame.width*4/5, height: collectionView.frame.height)
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        let cellWidth : CGFloat = collectionView.frame.width*4/5

        let numberOfCells = floor(collectionView.frame.width / cellWidth)
        let edgeInsets = (collectionView.frame.width - (numberOfCells * cellWidth)) / (numberOfCells + 1)

        return UIEdgeInsets(top: 0, left: edgeInsets, bottom: 0, right: edgeInsets)
    }
}

1

Możesz wypróbować moje rozwiązanie, działa dobrze,

func refreshCollectionView(_ count: Int) {
    let collectionViewHeight = collectionView.bounds.height
    let collectionViewWidth = collectionView.bounds.width
    let numberOfItemsThatCanInCollectionView = Int(collectionViewWidth / collectionViewHeight)
    if numberOfItemsThatCanInCollectionView > count {
        let totalCellWidth = collectionViewHeight * CGFloat(count)
        let totalSpacingWidth: CGFloat = CGFloat(count) * (CGFloat(count) - 1)
        // leftInset, rightInset are the global variables which I am passing to the below function
        leftInset = (collectionViewWidth - CGFloat(totalCellWidth + totalSpacingWidth)) / 2;
        rightInset = -leftInset
    } else {
        leftInset = 0.0
        rightInset = -collectionViewHeight
    }
    collectionView.reloadData()
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
    return UIEdgeInsetsMake(0, leftInset, 0, rightInset)
}

1

Odpowiedź akceptowana jest prawidłowa odpowiedź, ale jeśli totalCellWidthjest mniej niż CollectionView„s width, ale tylko w celu ochrony przed tym można zrobić, jak poniżej.

if (leftInset > 0) {
     return UIEdgeInsetsMake(0, leftInset, 0, rightInset)
  } else {
     return UIEdgeInsetsMake(0, 10, 0, 10)
}

1

Ten kod powinien wyśrodkować widok kolekcji w poziomie nawet w Swift 4.0 bez żadnych modyfikacji:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
    let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
    let cellWidth: CGFloat = flowLayout.itemSize.width
    let cellSpacing: CGFloat = flowLayout.minimumInteritemSpacing
    let cellCount = CGFloat(collectionView.numberOfItems(inSection: section))
    var collectionWidth = collectionView.frame.size.width
    if #available(iOS 11.0, *) {
        collectionWidth -= collectionView.safeAreaInsets.left + collectionView.safeAreaInsets.right
    }
    let totalWidth = cellWidth * cellCount + cellSpacing * (cellCount - 1)
    if totalWidth <= collectionWidth {
        let edgeInset = (collectionWidth - totalWidth) / 2
        return UIEdgeInsetsMake(flowLayout.sectionInset.top, edgeInset, flowLayout.sectionInset.bottom, edgeInset)
    } else {
        return flowLayout.sectionInset
    }
}

Upewnij się, że Twoja klasa jest zgodna z UICollectionViewDelegateFlowLayoutprotokołem


0

Skończyło się na tym, że przyjąłem tutaj zupełnie inne podejście, o czym myślę, że warto wspomnieć.

Ustawiłem ograniczenie, aby mój widok kolekcji był wyrównany poziomo na środku. Następnie ustawiłem kolejne ograniczenie, które określa szerokość. Utworzyłem punkt sprzedaży dla ograniczenia szerokości w moim viewController, który zawiera widok kolekcji. Następnie, gdy moje źródło danych zostanie zmienione i aktualizuję widok kolekcji, obliczam liczbę komórek i wykonuję (bardzo podobne) obliczenia, aby zresetować szerokość.

let newWidth = (items.count * cellWidth) + (items.count * cellSpacing)

Następnie ustawiam wartość wyjścia ograniczenia .constantna wynik obliczeń, a autoukład zajmie się resztą.

Może to powodować konflikt z `UICollectionViewDelegateFlowLayout, ale to zadziałało idealnie, aby utworzyć widok kolekcji wyrównany do lewej. Wydaje się, że bez delegata działa tylko wtedy, gdy komórki zajmują większość widoku.


0

Ogólne rozwiązanie układu flowlayout, które wyśrodkowuje strony, jeśli są mniejsze niż szerokość, i wyrównuje do lewej, jeśli jest ich więcej

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(nonnull UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
    // Centering if there are fever pages
    CGSize itemSize = [(UICollectionViewFlowLayout *)collectionViewLayout itemSize];
    CGFloat spacing = [(UICollectionViewFlowLayout *)collectionViewLayout minimumLineSpacing];

    NSInteger count = [self collectionView:self numberOfItemsInSection:section];
    CGFloat totalCellWidth = itemSize.width * count;
    CGFloat totalSpacingWidth = spacing * ((count - 1) < 0 ? 0 : count - 1);
    CGFloat leftInset = (self.bounds.size.width - (totalCellWidth + totalSpacingWidth)) / 2;
    if (leftInset < 0) {
        UIEdgeInsets inset = [(UICollectionViewFlowLayout *)collectionViewLayout sectionInset];
        return inset;
    }
    CGFloat rightInset = leftInset;
    UIEdgeInsets sectionInset = UIEdgeInsetsMake(0, leftInset, 0, rightInset);
    return sectionInset;
}

Wersja Swift (przekonwertowana z ObjC)

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
    // Centering if there are fever pages
    let itemSize: CGSize? = (collectionViewLayout as? UICollectionViewFlowLayout)?.itemSize
    let spacing: CGFloat? = (collectionViewLayout as? UICollectionViewFlowLayout)?.minimumLineSpacing

    let count: Int = self.collectionView(self, numberOfItemsInSection: section)
    let totalCellWidth = (itemSize?.width ?? 0.0) * CGFloat(count)
    let totalSpacingWidth = (spacing ?? 0.0) * CGFloat(((count - 1) < 0 ? 0 : count - 1))
    let leftInset: CGFloat = (bounds.size.width - (totalCellWidth + totalSpacingWidth)) / 2
    if leftInset < 0 {
        let inset: UIEdgeInsets? = (collectionViewLayout as? UICollectionViewFlowLayout)?.sectionInset
        return inset!
    }
    let rightInset: CGFloat = leftInset
    let sectionInset = UIEdgeInsets(top: 0, left: Float(leftInset), bottom: 0, right: Float(rightInset))
    return sectionInset
}

Bez tytułu-3.png


Co to są ograniczenia w szybkim kodzie? Otrzymuję błąd dotyczący użycia nierozwiązanego identyfikatora „granice”
Sachin Tanpure

Cześć, w moim przykładzie zaimplementowałem metodę wewnątrz UIView, która ma granice, jeśli implementujesz ją w innym miejscu, użyj odpowiednich granic
Peter Lapisu


0

Najprostszym sposobem jest ustawienie szacunkowego rozmiaru widoku kolekcji na Brak w scenorysie lub w kodzie layout.estimatedItemSize = CGSize.zero


0

Jeśli w grupie jest miejsce tylko na jedną komórkę, a leading:i trailing:of .flexible(0)wyśrodkują komórkę w poziomie:

item.edgeSpacing = NSCollectionLayoutEdgeSpacing(
    leading: .flexible(0), top: nil,                                                     
    trailing: .flexible(0), bottom: nil
)

0

Użyłem tego kodu w projekcie. Wyśrodkowuje collectionView w poziomie i w pionie w obu kierunkach .horizontali .verticalza pomocą wstawek sekcji. Uwzględnia odstępy i oryginalne wstawki przekroju, jeśli są ustawione. Kod do użycia w delegacie, UICollectionViewDelegateFlowLayoutdzięki czemu mamy dostęp do wszystkich właściwości, które musimy pobrać ze UIcollectionViewscenorysu lub ustawić w scenorysie w celu ponownego wykorzystania.

// original function of the delegate
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
    // casting the layout as a UICollectionViewFlowLayout to have access to the properties of items for reusability - you could also link the real one from the storyboard with an outlet
    let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
    // getting all the properties we need
    let itemWidth = flowLayout.itemSize.width
    let itemHeight = flowLayout.itemSize.height
    let interSpacing = flowLayout.minimumInteritemSpacing
    let lineSpacing = flowLayout.minimumLineSpacing
    // getting the size of the collectionView
    let collectionWidth = collectionView.bounds.width
    let collectionHeight = collectionView.bounds.height
    // getting the direction to choose how to align the collection
    let direction = flowLayout.scrollDirection
    // you don't want to have an item greater than the collection
    guard (itemWidth < collectionWidth && direction == .vertical) || (itemHeight < collectionHeight && direction == .horizontal) else {
        print("Really?")
        return UIEdgeInsets(top: flowLayout.sectionInset.top, left: flowLayout.sectionInset.left, bottom: flowLayout.sectionInset.bottom, right: flowLayout.sectionInset.right)
    }
    // getting the number of item in the current section
    let totalItemCount = CGFloat(collectionView.numberOfItems(inSection: section))
    // setting number of item in a row to the max number of items that can fit in a row without spacing or to the number of items in the section if less than the max
    var itemCountInRow = totalItemCount < (collectionWidth / itemWidth).rounded(.towardZero) ? totalItemCount : (collectionWidth / itemWidth).rounded(.towardZero)
    // how many max row can we have
    var countOfRow = totalItemCount < (collectionHeight / itemHeight).rounded(.towardZero) ? totalItemCount : (collectionHeight / itemHeight).rounded(.towardZero)
    // calculating the total width of row by multiplying the number of items in the row by the width of item and adding the spacing multiplied by the number of item minus one
    var totalWidthOfRow:CGFloat {
        get{
            return (itemWidth * itemCountInRow) + (interSpacing * (itemCountInRow - 1))
        }
    }
    // calculating the total height of row by multiplying the number of row by the height of item and adding the spacing multiplied by the number of row minus one
    var totalHeightOfRow:CGFloat {
        get{
            return (itemHeight * countOfRow) + (lineSpacing * (countOfRow - 1))
        }
    }
    // first we set the inset to the default
    var edgeInsetLeft = flowLayout.sectionInset.left
    var edgeInsetTop = flowLayout.sectionInset.top

    if direction == .vertical {
        // while the width of row with original margin is greater than the width of the collection we drop one item until it fits
        while totalWidthOfRow > collectionWidth || ((collectionWidth - totalWidthOfRow) / 2) < flowLayout.sectionInset.left {
            // droping an item to fit in the row
            itemCountInRow -= 1
        }
        // calculating the number of rows in collectionView by dividing the number of items by the number of items in a row
        countOfRow = (totalItemCount / (itemCountInRow)).rounded(.up)
    } else {
        itemCountInRow = (totalItemCount / countOfRow).rounded(.up)
        // while the height of row with original marginis greater than the height of the collection we drop one row until it fits
        while totalHeightOfRow >= collectionHeight  || ((collectionHeight - totalHeightOfRow) / 2) < flowLayout.sectionInset.top  {
            // droping an item to fit in the row
            countOfRow -= 1
        }
    }
    edgeInsetLeft = max(flowLayout.sectionInset.left, (collectionWidth - totalWidthOfRow) / 2)
    edgeInsetTop = max(flowLayout.sectionInset.top, (collectionHeight - totalHeightOfRow) / 2)
    // we don't specially need insets where the items are overflowing
    let edgeInsetRight = direction == .vertical ? edgeInsetLeft : flowLayout.sectionInset.right
    let edgeInsetBottom = direction == .horizontal ? edgeInsetTop : flowLayout.sectionInset.bottom
    // returning the UIEdgeInsets
    return UIEdgeInsets(top: edgeInsetTop, left: edgeInsetLeft, bottom: edgeInsetBottom, right: edgeInsetRight)
}

Mam nadzieję, że to komuś pomogło - wyśrodkowuje sekcję, a nie elementy wewnątrz sekcji, po więcej musimy podklasować UICollectionViewFlowLayoutlub UICollectionViewLayoutjako przykład mozaiki z Apple.


-4

Myślę, że musisz wyśrodkować komórkę, więc zamiast używać collectionView, chciałbym, żeby UITableView był bardzo przydatny. Po prostu użyj UIViewController i umieść dwa UIViews z przodu iz tyłu i umieść UITableVieww środku Mam nadzieję, że to pomoże


Dodałem zdjęcie, aby pokazać, czego dokładnie potrzebuję, dzięki!
RaptoX
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.