4

我需要一個UICollectionView來顯示一個網格,該網格在寬度和高度上都可能比可見框更大,同時保持行和列的完整性。默認UICollectionViewFlowLayout允許部分可以在屏幕外滾動,但它會將某些部分中的項目包裝在屏幕上,以便將我的網格固定在屏幕上。防止UICollectionView中的項目「打包」

認識到UICollectionViewUIScrollView一個子類,我嘗試了手動設置集合視圖的內容大小屬性在viewDidLoad中:

self.collectionView.contentSize = CGSizeMake((columns * (cellWidth + itemSpacingX), (rows * (cellHeight + itemSpacingY)); 

但是,這並沒有影響。問題:

  • 有沒有一種簡單的方法來實現這一點,而不建立自定義佈局?
  • 使用自定義佈局並覆蓋collectionViewContentSize方法能否成功獲取集合視圖來停止包裝項目並向兩個方向滾動?
  • 如果我必須建立一個自定義佈局 - 我必須投入一些時間來學習 - 我可以繼承UICollectionViewLayout,還是繼承UICollectionViewFlowLayout保存時間?

更新: 我試圖嵌入UICollectionView作爲UIScrollView的子視圖。集合視圖本身的行爲是正確的 - 這些行不包含在滾動視圖的邊緣,告訴我它正在填充我設置的UIScrollView內容大小。但是,滾動視圖不會在水平方向上平移,即它只是垂直滾動,而集合視圖本身無論如何都會自動滾動。所以再次卡住。響應者鏈可能存在問題嗎?

+0

'self.layout.scrollDirection = UICollectionViewScrollDirectionHorizo​​ntal;'得到了這份工作爲我做的。我想知道這是否適合你的情況。 –

回答

5

找出了兩種方法來做到這一點。兩者都需要自定義佈局。問題在於默認的流佈局 - 我現在知道從集合視圖編程指南這部分是流佈局的定義 - 根據超視圖的邊界生成單元格佈局屬性,並將包裝項目在一個部分保持界限,以便滾動只發生在一個軸上。將跳過代碼的細節,因爲它不難,我的問題主要是在採取什麼方法混淆。

簡單的方法:使用UIScrollView和子類'UICollectionViewFlowLayout'。UICollectionView嵌入UIScrollView。將滾動視圖的contentSize屬性設置爲viewDiDLoad以匹配您的集合視圖將佔用的全部大小(這將使默認流佈局將項放置在一個節中的單個行中而不包裝)。子類UICollectionViewFlowLayout,並將該對象設置爲集合視圖的自定義佈局。在自定義流佈局中,覆蓋collectionViewContentSize以返回集合視圖矩陣的完整大小。採用這種方法,您將使用流佈局,但可以雙向滾動以查看未包裝的部分。缺點是你仍然有一個非常有限的流佈局。此外,將UICollectionView置於其自己的超類的實例中似乎很笨重,以獲得集合視圖本身應具有的功能。

更難的方式,但更通用和優雅:子類UICollectionViewLayout。我用this tutorial來學習如何實現一個完整的自定義佈局。這裏您不需要UIScrollView。如果您放棄流佈局,子類UICollectionViewLayout,並將其設置爲自定義佈局,則可以構建矩陣並從集合視圖本身獲取正確的行爲。這是更多的工作,因爲你必須產生所有的佈局屬性,但你將被定位爲使集合視圖做你想做的任何事情。

在我看來,蘋果應該添加一個屬性到壓制包裝的默認流佈局。獲取設備以顯示完整的行和列的2D矩陣並不是一項奇特的功能,它看起來應該更容易做到。

0

下面是完整的矩陣customLayout:

import UIKit 

class MatrixLayout: UICollectionViewLayout { 

    var itemSize: CGSize! 
    var interItemSpacingY: CGFloat! 
    var interItemSpacingX: CGFloat! 
    var layoutInfo: Dictionary<NSIndexPath, UICollectionViewLayoutAttributes>! 

    required init?(coder aDecoder: NSCoder) { 

     super.init(coder: aDecoder) 

     itemSize = CGSizeMake(50.0, 50.0) 
     interItemSpacingY = 1.0 
     interItemSpacingX = 1.0 
    } 

    override func prepareLayout() { 

     var cellLayoutInfo = Dictionary<NSIndexPath, UICollectionViewLayoutAttributes>() 

     let sectionCount = self.collectionView?.numberOfSections() 
     var indexPath = NSIndexPath(forItem: 0, inSection: 0) 

     for (var section = 0; section < sectionCount; section += 1) 
     { 
      let itemCount = self.collectionView?.numberOfItemsInSection(section) 

      for (var item = 0; item < itemCount; item += 1) 
      { 
       indexPath = NSIndexPath(forItem:item, inSection: section) 
       let itemAttributes = UICollectionViewLayoutAttributes(forCellWithIndexPath: indexPath) 
       itemAttributes.frame = frameForCellAtIndexPath(indexPath) 
       cellLayoutInfo[indexPath] = itemAttributes 
      } 

      self.layoutInfo = cellLayoutInfo 
     } 
    } 

    func frameForCellAtIndexPath(indexPath: NSIndexPath) -> CGRect 
    { 
     let row = indexPath.section 
     let column = indexPath.item 

     let originX = (self.itemSize.width + self.interItemSpacingX) * CGFloat(column) 
     let originY = (self.itemSize.height + self.interItemSpacingY) * CGFloat(row) 

     return CGRectMake(originX, originY, self.itemSize.width, self.itemSize.height) 
    } 

    override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? 
    { 
     var allAttributes = Array<UICollectionViewLayoutAttributes>() 

     for (index, attributes) in self.layoutInfo 
     { 
      if (CGRectIntersectsRect(rect, attributes.frame)) 
      { 
       allAttributes.append(attributes) 
      } 
     } 
     return allAttributes 
    } 

    override func layoutAttributesForItemAtIndexPath(indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes? { 
     return self.layoutInfo[indexPath] 
    } 


    override func collectionViewContentSize() -> CGSize { 

     let width:CGFloat = (self.itemSize.width + self.interItemSpacingX) * CGFloat((self.collectionView?.numberOfItemsInSection(0))!) 
     let height:CGFloat = (self.itemSize.height + self.interItemSpacingY) * CGFloat((self.collectionView?.numberOfSections())!) 

     return CGSizeMake(width, height) 
    } 
} 

部分都行, 項目列