shaps80 / SwiftUIBackports

A collection of SwiftUI backports for iOS, macOS, tvOS and watchOS
MIT License
931 stars 59 forks source link

Lazy Stacks #5

Closed shaps80 closed 2 years ago

shaps80 commented 2 years ago

Are there any plans to backport LazyVStack or LazyGrid?

@K1NXZ Moving your question to its own Issue, so its tracked correctly 👍

shaps80 commented 2 years ago

It's non-obvious how best to achieve this, however I am looking at alternatives. For example I think it might be possible to provide a backport fo the new Layout APIs which would potentially open the door for creating this kind of thing, as well as any other layouts.

My other idea was to create a new type (not a backport) that wraps UICollectionView and provides a really nice SwiftUI API that would enable lazy stacks and other implementations. I’ve actually been working on this one prior to WWDC so I may explore this a little more. The API is really nice and its quite promising. This would be a separate library of course, but I’ll let you know when I’ve explored this a little more 👍🏻.

pofat commented 2 years ago

I think it might be possible to provide a backport for the new Layout APIs

Hi, this is interesting and sounds challenging (to me). Very curious about what kind of solution you have in your mind.

Here's the example code in WWDC22:

// In the Layout protocol conformance
func placeSubviews(
    in bounds: CGRect,
    proposal: ProposedViewSize,
    subviews: Subviews,
    cache: inout Void
) {
    // layout subviews
}

// FooView.swift
let layout = model.isAllWayTie ? AnyLayout(HStack()) : AnyLayout(MyRadialLayout())

Podium()
    .overlay(alignment: .top) {
        layout { // ? How do you get subviews? 
            ForEach(model.pets) { pet in
                Avatar(pet: pet)
                    .rank(model.rank(pet))
            }
        }
        .animation(.default, value: model.pets)
    }

The difficult part is that layout only receives a some View in the closure generated by @ViewBuilder. I don't know if there is a way to get layout information of subviews that compose this some View without some hacking in SwiftUI.

I guess that you might decompose some View into subviews if you can use some runtime api to figure what subviews are there.

Btw, it's also nice to back port ViewThatFits. However, it also seems difficult, IMO.

shaps80 commented 2 years ago

Hi, this is interesting and sounds challenging (to me).

Agreed, feel free to give it a shot and contribute if its done well 👍

K1NXZ commented 2 years ago

I don't know what's possible with the new layouts API, but I feel like its limited in the factor of cell reuse and memory management.

Another quick idea that jumps into my mind is to make a UICollectionView wrapper with a custom result builder.

shaps80 commented 2 years ago

Yep as I mentioned above, that's what I've even working on, CompositionalList I called it (since its backed by UICollectionView + CompositionalLayout).

Quick side note, last night I released a backport for UIHostingConfiguration which should help at least, since that will allow you to use UICollectionView yourself with SwiftUI view.

shaps80 commented 2 years ago

I don't know what's possible with the new layouts API, but I feel like its limited in the factor of cell reuse and memory management.

Just to reference this, the Layout APIs are about, well, Layout. Not View's, thus memory management, cell reuse, etc is not relevant here. Hence why its a far better abstraction.

K1NXZ commented 2 years ago

Yep as I mentioned above, that's what I've even working on, CompositionalList I called it (since its backed by UICollectionView + CompositionalLayout).

Quick side note, last night I released a backport for UIHostingConfiguration which should help at least, since that will allow you to use UICollectionView yourself with SwiftUI view.

Yes I think that would be the best approach. The UIHostingConfiguration Backport can be used in the backed UICollectionView

shaps80 commented 2 years ago

I'm gonna close this for now as it's not feasible beyond the work that's already been done. If anything changes I'll open a new and more specific issue with details. 👍