sgr-ksmt / WaterfallLayout

water-fall layout in iOS
MIT License
218 stars 43 forks source link

It works with automatic size but crashed with custom size #3

Open BhavinBhadani opened 6 years ago

BhavinBhadani commented 6 years ago

It works with automatic size

return WaterfallLayout.automaticSize

But if we give some custom size it crashed on prepare layout

koust commented 6 years ago

I get the same error, did you solve the problem?

BhavinBhadani commented 6 years ago

@koust nope :(

pavankataria commented 6 years ago

bump.

Vinod-kumar-ios commented 6 years ago

same error getting

khawars commented 6 years ago

Facing same issue here.

fuxingloh commented 5 years ago

10 Fixes it but diable auto sizing for waterfall mode.

n1schal commented 5 years ago

I copied the updated code but it's still crashing for me.

let layout = WaterfallLayout() layout.delegate = self layout.sectionInset = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8) layout.minimumLineSpacing = 8.0 layout.minimumInteritemSpacing = 8.0 layout.headerHeight = AppDimensions.HeaderHeight collectionView?.collectionViewLayout = layout`

extension HomeCollectionViewController : WaterfallLayoutDelegate{ func collectionViewLayout(for section: Int) -> WaterfallLayout.Layout { switch collectionView?.numberOfItems(inSection: section) { case 1: return .flow(column: 1) case 2: return .flow(column: 2) case 3: return .waterfall(column: 2, distributionMethod: .balanced) default: return .flow(column: 2) } }

func collectionView(_ collectionView: UICollectionView, layout: WaterfallLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    var width: CGFloat!
    var height: CGFloat!
    let picCount = collectionView.numberOfItems(inSection: indexPath.section)
    switch picCount {
    case 1:
        width = scW
        height = scW
    case 2:
        width = (scW-8)/2
        height = scW
    case 3:
        height = scW/2
        if(indexPath.row == 0){
            width = scW
        }else{
            width = (scW-8)/2
        }
    case 4:
        Log.add(info: "Width: \(scW)")
        width = (scW-8)/2
        height = (scW-8)/2
    default:
        width = (scW-8)/2
        height = (scW-8)/2
    }
    return CGSize.init(width: width, height: height)
}

} `

scWidth is ScreenWidth from UIScreen.main.bounds.width

fuxingloh commented 5 years ago

@n1schal the crash is most likely due to constraints issues on your ViewCells.

The code I suggested, fixes issues with constraints issues caused by UIView that adjusts the content hugging property; which causes constraints to change. However, if your constraints itself is not set correctly, regardless of the fix, it will still crash.

You need to set a breakpoint on unsatisfiable constraints. https://stackoverflow.com/questions/26389273/how-to-trap-on-uiviewalertforunsatisfiableconstraints

n1schal commented 5 years ago

The only constraints I have on the imageView inside the cell is 0 on all side i.e. leading, trailing, top, bottom

fuxingloh commented 5 years ago

Try changing their priority to high (750).

gdetari commented 5 years ago

Yeah it has nothing to do with constraints (at least in my case). I have cells that have no constraints at all, and it's crashing in prepareLayout in waterfall mode (EXC_BAD_ACCESS) on line 261

fuxingloh commented 5 years ago

That sucks, but EXC_BAD_ACCESS can be thrown due to constraints issues (unable to satisfy constraints simultaneously). I had the same error before I changed the constraints priority.

If you insist on using this library, I recommend you remove all the constraints for every single cell and slowly introduce them back until you fixed all the cells constraints. Including non waterfall mode cells.

gdetari commented 5 years ago

Like I wrote, no constraints. Also constraint errors cannot cause bad access, ios breaks them if unsolvable.

fuxingloh commented 5 years ago

Oh, what I meant is that because of how this lib implement shouldInvalidateLayout(forPreferredLayoutAttributes... which is false in the default UIKit implementation. It causes a stack overflow event because, both the cells and the collection view is suggesting a different set of constraints via a repeated loop.

The reasons why iOS doesn't attempt to break if unsolvable is because it's not caused via the AutoLayout Engine but rather this delegate. And an infinite recursion causes EXC_BAD_ACCESS in iOS.

This was the issue that causes the crash for me, I hope this helps.

yokoboko commented 5 years ago

How can we fix that? If I use autoresize mask it works but with constraint layout it does not. I have simple cell with UIImageView constrained to top, bottom, left & right?

iamcam commented 5 years ago

I made some progress on this issue so far. I can reproduce the crash by adding a xib for ColorView and a subView (eg, UIImageView), and setting auto layout constraints. Scrolling the content will soon lead to a BAD ACCESS crash. I started reading through this SO answer. He mentioned adding this code to your collection cell,

//forces the system to do one layout pass
var isHeightCalculated: Bool = false

override func preferredLayoutAttributesFittingAttributes(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
    //Exhibit A - We need to cache our calculation to prevent a crash.
    if !isHeightCalculated {
        setNeedsLayout()
        layoutIfNeeded()
        let size = contentView.systemLayoutSizeFitting(layoutAttributes.size)
        var newFrame = layoutAttributes.frame
        newFrame.size.width = CGFloat(ceilf(Float(size.width)))
        layoutAttributes.frame = newFrame
        isHeightCalculated = true
    }
    return layoutAttributes
}

... and so I tried it. The crash stops and the cells appear to be laid out properly.

It appears to be a nuance of UICollectionViewLayout, rather than this library. Give it a shot and see if that fixes your issue.

swapneshp-spaceo commented 4 years ago

Is anyone found the solution, please let me know.