2017-01-24 1 views
2

Ich versuche, die UICollectionView für benutzerdefinierte Zellen in der Form von Kreis zu implementieren. Jetzt sind die Kreise standardmäßig wie die normale quadratische Zelle ausgerichtet: der obere Kreis und der untere Kreis befinden sich auf derselben vertikalen Linie. Wie kann ich die Ausrichtung ändern: Der obere Kreis und zwei Kreise darunter bilden ein gleichseitiges Dreieck (Positionen von oberem Kreis und unterem Kreis werden um die Radiuslänge verschoben)? Wie weiter unten:iOS UICollectionView: Zellen mit kreisförmiger Ansicht in wechselnder Rasterausrichtung

from OOO 
    OOO 
    OOO 

to O O O 
    O O O (no spacing among the circles) 
    O O O 
+0

Sie müssen Ihre eigenen 'UICollectionViewLayout' erstellen," sagen ", was ist der Rahmen für Ihre Zellen. – Larme

Antwort

8

Die Grundidee ist eine benutzerdefinierte UICollectionViewLayout zu erstellen, die implementiert:

  • collectionViewContentSize, das heißt, was die Größe des Voll, scrollbaren contentSize der Sammlung Ansicht ist;

  • layoutAttributesForItem(at indexPath:), d.h. was sind die Schlüsselattribute (nämlich center und size) einer bestimmten Zelle; und

  • layoutAttributesForElements(in rect:), das heißt, was die wichtigsten Attribute für Zellen sind, die in dieser speziellen rect fallen ... wird diese verwendet werden, um festzustellen, welche Zellen sind zu einem bestimmten Zeitpunkt sowie die Attribute für diese Zellen ; Dies ist im Grunde ein Array der Attribute für die Zellen aus der vorherigen Methode, gefiltert auf nur diejenigen innerhalb der rect.

    class AlternatingGridLayout: UICollectionViewLayout { 
    
        private var itemSize: CGSize! 
        private var numberOfItems: Int! 
        private var itemsPerRow: Int! 
        private var rows: Int! 
        private var circleViewCenterOffset: CGPoint! 
        private var radiusOfCircleViews: CGFloat! 
        private var insets: UIEdgeInsets! 
    
        override func prepare() { 
         super.prepare() 
    
         guard let collectionView = collectionView else { return } 
    
         radiusOfCircleViews = CGFloat(40.0) 
         itemSize = CGSize(width: radiusOfCircleViews * 2, height: radiusOfCircleViews * 2) 
         circleViewCenterOffset = CGPoint(x: 2 * radiusOfCircleViews * cos(.pi/3), 
                 y: 2 * radiusOfCircleViews * sin(.pi/3)) 
         numberOfItems = collectionView.numberOfItems(inSection: 0) 
         itemsPerRow = Int(floor((collectionView.bounds.width - radiusOfCircleViews)/CGFloat(2 * radiusOfCircleViews)) + 0.5) 
         rows = (numberOfItems - 1)/itemsPerRow + 1 
         let excess = collectionView.bounds.width - (CGFloat(itemsPerRow) * radiusOfCircleViews * 2 + circleViewCenterOffset.x) 
         insets = UIEdgeInsets(top: 10, left: excess/2, bottom: 10, right: excess/2) 
        } 
    
        override var collectionViewContentSize: CGSize { 
         return CGSize(width: collectionView!.bounds.width, 
             height: 2 * radiusOfCircleViews + CGFloat(rows - 1) * circleViewCenterOffset.y + insets.top + insets.bottom) 
        } 
    
        override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { 
         let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath) 
    
         attributes.center = centerForItem(at: indexPath) 
         attributes.size = itemSize 
    
         return attributes 
        } 
    
        override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { 
         return (0 ..< collectionView!.numberOfItems(inSection: 0)).map { IndexPath(item: $0, section: 0) } 
          .filter { rect.intersects(rectForItem(at: $0)) } 
          .flatMap { self.layoutAttributesForItem(at: $0) } // `compactMap` in Xcode 9.3 
        } 
    
        private func centerForItem(at indexPath: IndexPath) -> CGPoint { 
         let row = indexPath.item/itemsPerRow 
         let col = indexPath.item - row * itemsPerRow 
    
         var x: CGFloat = radiusOfCircleViews + CGFloat(col) * (radiusOfCircleViews * 2) 
         let y: CGFloat = radiusOfCircleViews + CGFloat(row) * (circleViewCenterOffset.y) 
    
         if row % 2 == 0 { 
          x += circleViewCenterOffset.x 
         } 
    
         return CGPoint(x: x + insets.left, y: y + insets.top) 
        } 
    
        private func rectForItem(at indexPath: IndexPath) -> CGRect { 
         let center = centerForItem(at: indexPath) 
    
         return CGRect(x: center.x - radiusOfCircleViews, y: center.y - radiusOfCircleViews, width: radiusOfCircleViews * 2, height: radiusOfCircleViews * 2) 
        }   
    } 
    

    Das ergibt::

So in Swift 3 Sie so etwas wie tun könnte

enter image description here

ist klar, diese anpassen, wie Sie sehen, passen, aber es zeigt die Grundidee.


In meiner ursprünglichen Antwort, unten, nahm ich an Sie, diese Zellen in einem Kreis sehen wollten, wie es in der WWDC 2012 Video Advanced Collection Views and Building Custom Layouts (ca. 40+ Minuten im Video) gezeigt. Siehe das unten.


Zum Beispiel in Swift 3:

class CircleLayout: UICollectionViewLayout { 

    private var center: CGPoint! 
    private var itemSize: CGSize! 
    private var radius: CGFloat! 
    private var numberOfItems: Int! 

    override func prepare() { 
     super.prepare() 

     guard let collectionView = collectionView else { return } 

     center = CGPoint(x: collectionView.bounds.midX, y: collectionView.bounds.midY) 
     let shortestAxisLength = min(collectionView.bounds.width, collectionView.bounds.height) 
     itemSize = CGSize(width: shortestAxisLength * 0.1, height: shortestAxisLength * 0.1) 
     radius = shortestAxisLength * 0.4 
     numberOfItems = collectionView.numberOfItems(inSection: 0) 
    } 

    override var collectionViewContentSize: CGSize { 
     return collectionView!.bounds.size 
    } 

    override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { 
     let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath) 

     let angle = 2 * .pi * CGFloat(indexPath.item)/CGFloat(numberOfItems) 

     attributes.center = CGPoint(x: center.x + radius * cos(angle), y: center.y + radius * sin(angle)) 
     attributes.size = itemSize 

     return attributes 
    } 

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { 
     return (0 ..< collectionView!.numberOfItems(inSection: 0)) 
      .flatMap { item -> UICollectionViewLayoutAttributes? in // `compactMap` in Xcode 9.3 
       self.layoutAttributesForItem(at: IndexPath(item: item, section: 0)) 
     } 
    } 
} 

Dann setzen Sie einfach die collectionViewLayout und dann die Standard UICollectionViewDataSource Methoden implementieren.

class ViewController: UICollectionViewController { 

    var numberOfCells = 10 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     collectionView?.collectionViewLayout = CircleLayout() 

     // just for giggles and grins, let's show the insertion of a cell 

     DispatchQueue.main.asyncAfter(deadline: .now() + 2) { 
      self.collectionView?.performBatchUpdates({ 
       self.numberOfCells += 1 
       self.collectionView?.insertItems(at: [IndexPath(item: 0, section: 0)]) 
      }, completion: nil) 
     } 
    } 

} 

// MARK: UICollectionViewDataSource 

extension ViewController { 
    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 
     return numberOfCells 
    } 

    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 
     let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CircleCell", for: indexPath) 
     return cell 
    } 
} 

Das ergibt:

circle view


Siehe https://github.com/robertmryan/CircularCollectionView für Probe.


Hinweis, Sie erwähnten, dass Sie „kein Abstand zwischen den Kreisen“ wollen, so justieren Sie einfach die radius und/oder itemSize dementsprechend das gewünschte Layout zu erhalten.

Verwandte Themen