Juanpe / SkeletonView

☠️ An elegant way to show users that something is happening and also prepare them to which contents they are awaiting
MIT License
12.51k stars 1.1k forks source link

Does not work with new UICollectionView Compositional Layout #321

Open normand1 opened 3 years ago

normand1 commented 3 years ago

⚠️ Please fill out this template when filing an issue.

🙏🏼 Please check if it already exists other issue related with yours.

What did you do?

Implemented a UICollectionView using the new Compositional Layout feature.

Then added this to viewDidLoad()

DispatchQueue.main.async {
            self.collectionView.showSkeleton()
        }

What did you expect to happen?

Expected to see the skeleton view applied to the UICollectionView

What happened instead?

I assume that since UICollectionView implementations that use Compositional Layout use diffable datasources instead of implementing the CollecitonView data source the skeleton view was not applied to my collectionview cells.

Steps to reproduce the behavior

Implement a UICollectionView with Compositional Layout and try applying the SkeletonView

SkeletonView Environment

SkeletonView version: SkeletonView (1.8.8) Xcode version: 11.7 Swift version: 5.2

Juanpe commented 3 years ago

Hi @normand1, I need to check it, but I think we should make some changes to make SkeletonView compatible with the new Compositional layout system

james-ff commented 3 years ago

What can we do in the meantime with composition layouts?

diogot commented 3 years ago

Your problem doesn't seem related to compositional layout, but with diffable data source, take a look at #279. https://github.com/Juanpe/SkeletonView/issues/279#issuecomment-666167980 helped me to make it work.

jDomenech commented 2 years ago

Hello, I just tried to implement it in a collection view using compositional layout and the skeleton seems to work fine (it appears properly) but the method cellForItemAt of the collectionView is never called; so after calling hideSkeleton() the cells never get updated (already tried using reloadData()).

JacksonJang commented 2 years ago

@jDomenech Hello, I'm Jackson. I'd like to help you with your problem.

So give me your source code example!

jDomenech commented 2 years ago

Hello,

Thanks for the reply and the help.

So basically use a uicollectionview using compositional layout. Before loading the data I call showAnimatedSkeleton():

func fetchData() { collectionView.showAnimatedSkeleton() viewModel.loadData() }

The setup of the collectionview is:

func setUpCollecionView() { collectionView.delegate = self collectionView.dataSource = self collectionView.register(UINib(nibName: "MainHeaderCollectionViewCell", bundle: .main), forCellWithReuseIdentifier: "MainHeaderCollectionViewCell") collectionView.register(UINib(nibName: "RestaurantItemCollectionViewCell", bundle: .main), forCellWithReuseIdentifier: "RestaurantItemCollectionViewCell") collectionView.collectionViewLayout = createCompositionalLayout() }

private func createCompositionalLayout() -> UICollectionViewCompositionalLayout {

    return UICollectionViewCompositionalLayout { (sectionNumber, env) -> NSCollectionLayoutSection? in
        switch sectionNumber {
        case 0: return self.headerLayoutSection()
        default: return self.mainListLayoutSection()
        }
    }
}

private func headerLayoutSection() -> NSCollectionLayoutSection {
    let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .estimated(195))
    let item = NSCollectionLayoutItem(layoutSize: itemSize)
    let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .estimated(500))
    let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
    let section = NSCollectionLayoutSection(group: group)
    return section
}

private func mainListLayoutSection() -> NSCollectionLayoutSection {
    let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .absolute(200))
    let item = NSCollectionLayoutItem(layoutSize: itemSize)
    item.contentInsets = .init(top: 0, leading: 15, bottom: 10, trailing: 15)
    let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .estimated(500))
    let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
    let section = NSCollectionLayoutSection(group: group)
    return section
}

And the datasource / delegate is:

extension MainListViewController: UICollectionViewDataSource, UICollectionViewDelegate, SkeletonCollectionViewDataSource {

func collectionSkeletonView(_ skeletonView: UICollectionView, cellIdentifierForItemAt indexPath: IndexPath) -> ReusableCellIdentifier {
    switch indexPath.section {
    case 0:
        return MainHeaderCollectionViewCell.reuseIdentifer
    default:
        return RestaurantItemCollectionViewCell.reuseIdentifer
    }
}

func numSections(in collectionSkeletonView: UICollectionView) -> Int {
    2
}

func collectionSkeletonView(_ skeletonView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    switch section {
    case 0:
        return 1
    default:
        return 4
    }
}

func numberOfSections(in collectionView: UICollectionView) -> Int {
    return 2
}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    switch section {
        case 0:
            return 1
        default:
            return viewModel.restaurants.count
    }
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    switch indexPath.section {
    case 0:
        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MainHeaderCollectionViewCell.reuseIdentifer, for: indexPath) as? MainHeaderCollectionViewCell else {
            return UICollectionViewCell()
        }
        cell.delegate = self
        cell.setup(filters: viewModel.filters)
        return cell
    default:
        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: RestaurantItemCollectionViewCell.reuseIdentifer, for: indexPath) as? RestaurantItemCollectionViewCell else {
            return UICollectionViewCell()
        }
        cell.delegate = self
        cell.setup(restaurant: viewModel.restaurants[indexPath.row])
        return cell
    }
}

}

And after loading the data I call:

collectionView.hideSkeleton()

And the result is the following:

The skeletonview is showing properly but when I hide it the cellForItemAt is never called so the cells are showing just as the storyboard design.

Thanks for your help.

El 21 ene 2022, a las 11:53, Jackson @.**@.>> escribió:

@jDomenechhttps://github.com/jDomenech Hello, I'm Jackson. I'd like to help you with your problem.

So give me your source code example!

— Reply to this email directly, view it on GitHubhttps://github.com/Juanpe/SkeletonView/issues/321#issuecomment-1018397526, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AANU5GSG2L6HCH23SSFKIJDUXE3LFANCNFSM4QZO5RTA. Triage notifications on the go with GitHub Mobile for iOShttps://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Androidhttps://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub. You are receiving this because you were mentioned.Message ID: @.***>

JacksonJang commented 2 years ago

@jDomenech Thank you for the answer

It's hard for me to check error section So, Please upload your example project to github repository and then share for us

jDomenech commented 2 years ago

Hi again,

The problem was that the hideSkeleton() was not performed in the main thread… Sorry for the inconvenience.

Thanks!

El 21 ene 2022, a las 14:03, Jackson @.***> escribió:

@jDomenech https://github.com/jDomenech Thank you for the answer

It's hard for me to check error section So, Please upload your example project to github repository and then share for us

— Reply to this email directly, view it on GitHub https://github.com/Juanpe/SkeletonView/issues/321#issuecomment-1018486065, or unsubscribe https://github.com/notifications/unsubscribe-auth/AANU5GTFWQEH72WXSAOMPCTUXFKTDANCNFSM4QZO5RTA. Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub. You are receiving this because you were mentioned.

JacksonJang commented 2 years ago

I'm glad it's resolved ! Have a good day @jDomenech