How to implement paging on user swipe? (Previously used UICollectionView -> paging enabled)
Asked Answered
H

2

5

Background: I'm converting a project from UIKit to SwiftUI. Currently with UIKit, I have a UICollectionView within a UICollectionView, both with Paging enabled. This allows users to swipe up/down and left/right on cells. Each cell fills the entire screen (similar to TikTok's main UI) and each cell has a lot of data to pull from Firebase, so I do not want to load all items when the first view appears, but rather as each cell will appear (this is the current implementation under UIKit via UICollectionView delegates).

Problem: I can't find a way to enable this "paging" (based on user swiping) in SwiftUI. It's hard to imagine that Apple made this new framework without a Paging feature? If they haven't included this, is there a workaround? Otherwise, is there an easy way to include a UICollectionView into a SwiftUIView?

Any help or workarounds would be nice.

Hamann answered 10/8, 2020 at 22:27 Comment(1)
What's the reason of converting?Viewing
D
1

SwiftUI 2

It looks like a LazyGrid may be what you need.

Here is a sample code for a vertical grid:

struct ContentView: View {
    let data = (1...1000).map { "Item \($0)" }

    let columns = [
        GridItem(.adaptive(minimum: 80))
    ]

    var body: some View {
        ScrollView {
            LazyVGrid(columns: columns, spacing: 20) {
                ForEach(data, id: \.self) { item in
                    Text(item)
                }
            }
            .padding(.horizontal)
        }
    }
}

You can find more information in these links:


SwiftUI 1

If you're bound to iOS 13 or LazyGrid just doesn't match your expectations, you can still wrap your UICollectionView in UIViewRepresentable.

See this link for more explanation: Implementing UICollectionView / UICollectionView DiffableDataSource in SwiftUI

Danieldaniela answered 10/8, 2020 at 22:48 Comment(8)
Thanks!! I will try implementing this later this week. I was running Xcode 11.6 (doesn't have LazyGrid), but I just downloaded the Xcode 12.0 beta and see it now! However, it's my understanding that we can't actually deploy builds from Xcode while it is in Beta. Do you have any idea when we would expect Xcode 12.0 to be usable to actually push a version to the App Store? I'm fairly new to this and just want to be cautious of building on a Beta version and having to wait months to deploy it to the App Store?Hamann
@purebreadd Nothing official yet, probably in fall. Just note that SwiftUI 2.0 is available on iOS14+ and SwiftUI 1.0 on iOS13+. It's better to know this before rewriting your app in SwiftUI.Danieldaniela
Hi again, I'm working with the GridItems now and I got the lazy cells in place. However, the ScrollViews are smooth scrolling only and not paging. Any idea how to enable "Paging" on them? The UICollectionView used to have a nice little delegate :(Hamann
@purebreadd You can take a look at this answer on How can I implement PageView in SwiftUI? But note that SwiftUI is still new - it might not have everything you need. And it might be better to stick with UIKit for now if you're using more complex views.Danieldaniela
Thanks again. I saw this, but I need it to work on the LazyGrids. I believe TabView loads all views at once :(Hamann
@purebreadd You can use UIViewRepresentable to integrate UIKit into SwiftUI. See Implementing UICollectionView / UICollectionView DiffableDataSource in SwiftUI. I updated my answer as well.Danieldaniela
That looks like the best bet lol gunna play around with it nowHamann
If you're curious, I went through the process to convert UICollectionView into SwiftUI and to incorporate all the custom sizing / cells in our app, it turned into a headache. This approach is probably best with simple UICollectionViews. Anyway, our solution for now is to use the old project (to keep the functionality on the screens that have complex CollecionViews) and only updating screens that don't need this functionality to SwiftUI. Thanks again for the help :)Hamann
L
6

Horizontal/Vertical paging in iOS 17

From iOS 17, you can enable the paging behavior by applying the following modifier on the ScrollView:

.scrollTargetBehavior(.paging)

This works for b both horizontal and vertical ScrollViews. You can use .containerRelativeFrame(...) on the content to make it size as the visible area of the scrollView:

Demo:
ScrollView(.horizontal) {
    LazyHStack {
        ForEach((1...100), id: \.self) { index in
            Text("\(index)")
                .containerRelativeFrame(.horizontal) // 👈 Makes it match the parent's visible width
                .containerRelativeFrame(.vertical) // 👈 Makes it match the parent's visible height
        }
    }
}
.scrollTargetBehavior(.paging) // 👈 Enables paging
Ledda answered 16/6, 2023 at 11:49 Comment(3)
@mohitaba is this available in Xcode 14.3.1? It doesn't seem to be for meAbutter
With this approach is there anyway to keep track of the selection like you would in a TabView?Faddist
scrollTargetBehavior does not work on the List, but you can make your selection tracking by 2 lines of code. @FaddistLedda
D
1

SwiftUI 2

It looks like a LazyGrid may be what you need.

Here is a sample code for a vertical grid:

struct ContentView: View {
    let data = (1...1000).map { "Item \($0)" }

    let columns = [
        GridItem(.adaptive(minimum: 80))
    ]

    var body: some View {
        ScrollView {
            LazyVGrid(columns: columns, spacing: 20) {
                ForEach(data, id: \.self) { item in
                    Text(item)
                }
            }
            .padding(.horizontal)
        }
    }
}

You can find more information in these links:


SwiftUI 1

If you're bound to iOS 13 or LazyGrid just doesn't match your expectations, you can still wrap your UICollectionView in UIViewRepresentable.

See this link for more explanation: Implementing UICollectionView / UICollectionView DiffableDataSource in SwiftUI

Danieldaniela answered 10/8, 2020 at 22:48 Comment(8)
Thanks!! I will try implementing this later this week. I was running Xcode 11.6 (doesn't have LazyGrid), but I just downloaded the Xcode 12.0 beta and see it now! However, it's my understanding that we can't actually deploy builds from Xcode while it is in Beta. Do you have any idea when we would expect Xcode 12.0 to be usable to actually push a version to the App Store? I'm fairly new to this and just want to be cautious of building on a Beta version and having to wait months to deploy it to the App Store?Hamann
@purebreadd Nothing official yet, probably in fall. Just note that SwiftUI 2.0 is available on iOS14+ and SwiftUI 1.0 on iOS13+. It's better to know this before rewriting your app in SwiftUI.Danieldaniela
Hi again, I'm working with the GridItems now and I got the lazy cells in place. However, the ScrollViews are smooth scrolling only and not paging. Any idea how to enable "Paging" on them? The UICollectionView used to have a nice little delegate :(Hamann
@purebreadd You can take a look at this answer on How can I implement PageView in SwiftUI? But note that SwiftUI is still new - it might not have everything you need. And it might be better to stick with UIKit for now if you're using more complex views.Danieldaniela
Thanks again. I saw this, but I need it to work on the LazyGrids. I believe TabView loads all views at once :(Hamann
@purebreadd You can use UIViewRepresentable to integrate UIKit into SwiftUI. See Implementing UICollectionView / UICollectionView DiffableDataSource in SwiftUI. I updated my answer as well.Danieldaniela
That looks like the best bet lol gunna play around with it nowHamann
If you're curious, I went through the process to convert UICollectionView into SwiftUI and to incorporate all the custom sizing / cells in our app, it turned into a headache. This approach is probably best with simple UICollectionViews. Anyway, our solution for now is to use the old project (to keep the functionality on the screens that have complex CollecionViews) and only updating screens that don't need this functionality to SwiftUI. Thanks again for the help :)Hamann

© 2022 - 2024 — McMap. All rights reserved.