16

2015年8月18日16:07:51.523實施例[16070:269647]的 UICollectionViewFlowLayout的行爲沒有被定義,因爲: 2015-08-18 16:07:51.523
示例[16070:269647]項目寬度必須小於 UICollectionView的寬度減去左側部分插槽的寬度並減去右側值的 減去內容的左右值。
2015-08-18 16:07:51.524示例[16070:269647]相關的 UICollectionViewFlowLayout實例是,並將其附加到;動畫= {position = { position =; bounds.origin =; bounds.size =; }; layer =; contentOffset:{0,0}; contentSize:{1024,770}> 集合視圖佈局:。 2015-08-18 16:07:51.524示例[16070:269647]在UICollectionViewFlowLayoutBreakForInvalidSizes中創建符號 斷點,以在調試器中捕獲 。的UICollectionViewFlowLayout的行爲沒有被定義,因爲細胞寬度比的CollectionView寬度大

這是我得到的,我做的是

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize { 
     return CGSizeMake(self.collectionView!.frame.size.width - 20, 66) 
    } 

,當我從橫向到縱向旋轉,控制檯顯示僅在iOS版9此錯誤信息,沒有人知道這是什麼情況,如果這有一個解決辦法?

Screenshot

+0

問題解決了嗎? –

+0

nope,未解決 –

回答

0

我有一個類似的問題。

就我而言,我有一個收集視圖,當您點擊其中一個單元格時,打開一個彈出框(UITextField)來編輯該項目。在彈出消失後,self.collectionView.contentInset.bottom被設置爲55(最初爲0)。

要解決我的問題,popover視圖消失後,我手動將contentInset設置爲UIEdgeInsetsZero

contextual prediction bar

原來的問題似乎是相關的,顯示了在鍵盤頂部的上下文預測吧。當鍵盤被隱藏時,欄會消失,但contentInset.bottom值不會恢復到原始值。

由於您的問題似乎與寬度有關,而與單元格的高度無關,因此請檢查contentInsetlayout.sectionInset中的任何值是否與您設置的值相同。

7

發生這種情況是因爲您的收藏視圖單元格的寬度比旋轉後的集合視圖寬度要大。請假設您有1024x768的屏幕,並且您的收藏視圖填充了屏幕。當設備處於橫向模式時,單元格的寬度將爲self.collectionView .frame.size.width - 20 = 1004,並且它大於portrait = 768中的集合視圖寬度。調試器說:「項目寬度必須小於UICollectionView的寬度減去左側和右側值的值內容插入左右值「。

+0

右...所以你如何解決它... – Magoo

+0

@Magoo你可以通過更改項目大小的集合視圖流佈局值來修復它。代表必須考慮輪換。正如調試器所說的,項目寬度必須小於UICollectionView的寬度減去左側和右側部分的值,減去左側和右側內容的值。 – mohammadrhemmati

4

我正在使用UICollectionViewFlowLayout的子類並使用其itemSize屬性來指定單元格大小(而不是collectionView:sizeForItemAtIndexPath:委託方法)。每當我將屏幕旋轉到較短寬度時(例如風景 - >人像),我都會得到這個巨大的警告。

我能夠通過執行2個步驟來修復它。

步驟1:UICollectionViewFlowLayout子類的prepareLayout()功能,移動super.prepareLayout()其中self.itemSize被設定之後。我認爲這使得超類使用正確的itemSize值。

import UIKit 

extension UICollectionViewFlowLayout { 

    var collectionViewWidthWithoutInsets: CGFloat { 
    get { 
     guard let collectionView = self.collectionView else { return 0 } 
     let collectionViewSize = collectionView.bounds.size 
     let widthWithoutInsets = collectionViewSize.width 
     - self.sectionInset.left - self.sectionInset.right 
     - collectionView.contentInset.left - collectionView.contentInset.right 
     return widthWithoutInsets 
    } 
    } 

} 

class StickyHeaderCollectionViewLayout: UICollectionViewFlowLayout { 

    // MARK: - Variables 
    let cellAspectRatio: CGFloat = 3/1 

    // MARK: - Layout 
    override func prepareLayout() { 
    self.scrollDirection = .Vertical 
    self.minimumInteritemSpacing = 1 
    self.minimumLineSpacing = 1 
    self.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: self.minimumLineSpacing, right: 0) 
    let collectionViewWidth = self.collectionView?.bounds.size.width ?? 0 
    self.headerReferenceSize = CGSize(width: collectionViewWidth, height: 40) 

    // cell size 
    let itemWidth = collectionViewWidthWithoutInsets 
    self.itemSize = CGSize(width: itemWidth, height: itemWidth/cellAspectRatio) 

    // Note: call super last if we set itemSize 
    super.prepareLayout() 
    } 

    // ... 

} 

請注意,上述更改將在屏幕旋轉停止工作時以某種方式使佈局大小發生更改。這就是第2步進來

步驟2:在視圖控制器保持所述集合視圖將這個。

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) { 
    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator) 
    collectionView.collectionViewLayout.invalidateLayout() 
    } 

現在警告了:)

+1

不好意思看看這個解決方案,答案比我從項目中出去晚了很多:( –

12

這發生在您的收藏視圖調整大小以較少的廣泛事情(從橫向到縱向模式去,例如),細胞變得太大,不適合。

爲什麼單元格變得太大,因爲集合視圖流程佈局應該被調用並返回合適的大小?

的CollectionView(的CollectionView:UICollectionView,佈局 collectionViewLayout:UICollectionViewLayout,sizeForItemAtIndexPath indexPath:NSIndexPath)

更新以包括夫特4

@objc倍率FUNC的CollectionView(_的CollectionView: UICollectionView,cellForItemAt indexPath:IndexPath) - > UICollectionViewCell {...}

這是因爲這個函數是而不是被調用,或者至少不是直接的。

會發生什麼情況是您的集合視圖流佈局子類不覆蓋shouldInvalidateLayoutForBoundsChange函數,默認情況下爲returns false

當此方法返回false時,集合視圖首先嚐試使用當前單元格大小,檢測到問題(記錄警告),然後調用流佈局來調整單元格的大小。

這意味着兩件事情:

1 - 這本身就是警告是無害的

2 - 你可以通過簡單地重寫shouldInvalidateLayoutForBoundsChange函數返回真正的擺脫它。 在這種情況下,當集合視圖邊界更改時,將始終調用流佈局。

+0

我已經在互聯網上嘗試了所有可能的建議,這是正確的答案!!!非常感謝您的詳細解釋和簡單的解決方案!如果我能我會upvote這個答案10次。 – ElectroBuddha

+0

謝謝,這對我工作。更新爲swift 4:更改「sizeForItemAtIndexPath」爲「sizeForItem」或它將無法正常工作,並不顯示任何錯誤。 –

3

如果collectionView.contentOffset更改爲負數,我可以在調試程序中檢查它是否從(0,0)變爲(0,-40)。您可以通過使用此方法來解決此問題

if ([self respondsToSelector:@selector(setAutomaticallyAdjustsScrollViewInsets:)]) { 
    self.automaticallyAdjustsScrollViewInsets = NO; 
} 
2

做了一些試驗後,這似乎也與您如何佈局collectionView有關。

tl; dr是:使用AutoLayout,而不是autoresizingMask。

所以對於這個問題的核心的最佳方案,我發現處理方向更改使用下面的代碼,而這一切是有道理的:

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { 
    super.viewWillTransition(to: size, with: coordinator) 

    coordinator.animate(alongsideTransition: { (context) in 
     self.collectionView.collectionViewLayout.invalidateLayout() 
    }, completion: nil) 
} 

然而,仍有情況下,您可以獲取項目大小警告。對我來說,如果我在一個選項卡中處於橫向模式,切換到另一個選項卡,旋轉到縱向,然後返回到上一個選項卡。我試圖在willAppear,willLayout,所有通常的嫌疑犯無效佈局,但沒有運氣。事實上,即使您在super.willAppear()之前致電invalidateLayout,您仍然會收到警告。

最終,此問題與代表被詢問itemSize之前collectionView邊界更新的大小有關。

因此,考慮到這一點,我嘗試使用AutoLayout而不是collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight],並解決了這個問題! (我使用SnapKit來做AutoLayout,這樣我就不會一直拉我的頭髮)。你也只需要invalidateLayoutviewWillTransition(沒有coordinator.animate,所以就像你在你的例子中),invalidateLayoutviewWillAppear(:)的底部。 似乎涵蓋所有情況。

我不知道你是否正在使用自動調整 - 這將是有趣的知道我的理論/解決方案是否適用於每個人。

1

我有同樣的問題。我通過清除收集視圖的約束來解決這個問題,並在Storyboard中重置它們。

-1

這是你所需要的:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { 
    //Get frame width 
    let width = self.view.frame.width 
    //I want a width of 418 and height of 274 (Aspect ratio 209:137) with a margin of 24 on each side of the cell (See insetForSectionAt 24 + 24 = 48). So, check if a have that much screen real estate. 
    if width > (418 + 48) { 
     //If I do return the size I want 
     return CGSize(width: 418, height: 274) 
    }else{ 
     //Get new width. Frame width minus the margins I want to maintain 
     let newWidth = (width - 48) 
     //If not calculate the new height that maintains the aspect ratio I want. NewHeight = (originalHeight/originalWidth) * newWidth 
     let height = (274/418) * newWidth 
     //Return the new size that is Aspect ratio 209:137 
     return CGSize(width: newWidth, height: height) 
    } 
} 

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets { 
    return UIEdgeInsets(top: 24, left: 24, bottom: 24, right: 24) 
} 

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { 
    return 33 
} 

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { 
    return 33 
} 
1

我用safeAreaLayoutGuide解決這個問題。

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

    return CGSize(width: (view.safeAreaLayoutGuide.layoutFrame.width), height: 80); 
} 

而且您還必須重寫此功能以正確支持縱向和橫向模式。

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { 
    collectionView?.collectionViewLayout.invalidateLayout(); 
}