Open seboslaw opened 4 years ago
Apple's UICollectionViewCompositionalLayout
(which is what you're using here) seems to struggle with this type of sizing. You'll notice that where they use it on the app store and elsewhere they actually use a fixed size. Curiously, none of their demos show the estimated sizing being used either. I'm not sure how to fix this other than to use a fixed size sorry!
I think I've solved this, only be mere chance and with a lot of extra additional help.
There's a lot of things that I've done to make this work, and I don't know which of them will help you.
This is how I'm using ASCollectionView to create a horizontally scrollable list of cards. The .dynamicHorizontalList function is similar to what you've used for layout, in that it allows you to set values for height as well, instead of .fractional(1) value offered with the .list() method
ASCollectionView(data: stores) {store,_ in
StoreCard(store: store)
}.layout(scrollDirection: .horizontal) { sectionId in
.dynamicHorizontalList(itemWidth: .fractionalWidth(0.42), itemHeight: .estimated(200), spacing: 10, sectionInsets: .init(top: 0, leading: AppSpacings.large, bottom: 0, trailing: 0))
}
.scrollIndicatorsEnabled(horizontal: false)
.fitContentSize(dimension: .vertical)
.padding(.bottom, AppSpacings.large)
.listRowInsets(EdgeInsets())
Another thing to note is that I've used a custom HorizontalGeometryReader to compute the height of the cell, which only takes the width value of the parent and does not scale on the y-axis like the usual GeometryReader.
var body: some View {
HorizontalGeometryReader { width in
VStack(alignment: .leading) {
ZStack(alignment: .bottom) {
KFImage(store.storeImageURL)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: width, height: width * 1.4)
.cornerRadius(20)
.clipped()
KFImage(store.storeLogoIconURL)
.resizable()
.frame(width: 80, height: 80)
.aspectRatio(contentMode: .fill)
.clipShape(Circle())
.offset(y: -AppSpacings.small)
}
HStack {
Image("time")
Text(estimatedTime)
Spacer()
Image("car")
Text(shippmentPrice)
}
.font(.regularSmall)
.accentColor(.appPrimary)
Text(store.storeName).font(.semiboldMedium)
Spacer()
}
}
}
The final sauce that made this work, which is something that I've discovered by accident, was adding the Spacer() in the VStack that I've used for the card in the code above. Without this, the card will not grow to fit its content, but will instead collapse along its y-axis. I don't understand why, but oh well.
Also, here's the code for the HorizontalGeometryReader class.
import SwiftUI
struct WidthReader : PreferenceKey, Equatable {
static var defaultValue: CGFloat { 10 }
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
value = max(value, nextValue())
}
}
struct WidthReaderView : View {
var body: some View {
GeometryReader { geometry in
Color.clear.preference(key: WidthReader.self, value: geometry.size.width)
}
}
}
public struct HorizontalGeometryReader<Content: View> : View {
var content: (CGFloat)->Content
@State private var width: CGFloat = WidthReader.defaultValue
public init(@ViewBuilder content: @escaping (CGFloat)->Content) {
self.content = content
}
public var body: some View {
content(width)
.frame(minWidth: 0, maxWidth: .infinity)
.background(WidthReaderView())
.onPreferenceChange(WidthReader.self) { width in
self.width = width
}
}
}
Hey guys,
I'm basically trying to implement the AppStore example (vertical scroll view with horizontally scrollable sections) but with dynamic type support. In order for this to work I've modified the
var layout: ASCollectionLayout<Int>
extension to deliver the following code:However, the
.estimated(350)
for the item's and group's height don't seem to work. The resulting section always has a height of 350 and doesn't adopt to the actual content's height. The actual cell content has a blue background for debugging purposes - when you scroll sideways you get the next item...in the next release these cells should only be 1/3 of the screen's width. The white area underneath the blue cell however should actually shrink.Cheers, Sebastian