Skip to content
This repository has been archived by the owner on Nov 22, 2023. It is now read-only.

Can ScrollViews play nice with content inset? #2

Closed
digitalheir opened this issue Aug 1, 2021 · 6 comments
Closed

Can ScrollViews play nice with content inset? #2

digitalheir opened this issue Aug 1, 2021 · 6 comments
Labels
adjustment Changes to existing functionality

Comments

@digitalheir
Copy link
Contributor

digitalheir commented Aug 1, 2021

I've adapted the demo view with a TabView, and in the bottom sheet a ScrollView instead of List. When using List, the scroll element pushes the bottom of the list upwards to account for the tab selection bar. But when I use a ScrollView, like below, the last item is obscured by the tab selection bar. Do you know how to account for this? Is it a SwiftUI issue?

image


struct DemoSheetContent: View {
    init(style: BottomSheetStyle) {
        self.style = style
    }
    var style: BottomSheetStyle
    
    var body: some View {
//        List {
//            ForEach(1...20, id: \.self) {
//                Text("\($0)")
//            }
//            .listRowBackground(style.color)
//        }
        ScrollView {
            VStack {
                ForEach(1...20, id: \.self) { i in
                    HStack {
                        Text("Item \(i)")
                        Spacer()
                        Button(
                            action: { print("Clicked \(i)") },
                            label: {
                            Image(systemName: "tray.and.arrow.down.fill")
                        })
                    }
                    .padding()
                    .frame(minHeight: 50)
                }
            }
        }
    }
}

struct DemoSheetContent_Previews: PreviewProvider {
    static var previews: some View {
        DemoSheetContent(style: .standard)
    }
}

struct ContentView: View {
    var body: some View {
            TabView {
                SettingsView()
                            .tabItem {
                                Label("Tab 1", systemImage: "list.dash")
                            }

                SettingsView()
                            .tabItem {
                                Label("Tab 2", systemImage: "square.and.pencil")
                            }
            }
    }
}

struct SettingsView: View {
    @State private var useTallerMinHeight = false
    @State private var useShorterMaxHeight = false
    @State private var sheetStyle = BottomSheetStyle.standard
    
    @State private var isExpanded = false
    var body: some View {
        NavigationView {
            List {
                Section(header: Text("").frame(height: 1)) {
                    Toggle("Is expanded", isOn: $isExpanded)
                    Toggle("Use taller min height", isOn: $useTallerMinHeight)
                    Toggle("Use shorter max height", isOn: $useShorterMaxHeight)
                }
                
                Section(header: Text("Sheet Styles").frame(height: 1)) {
                    sheetStyleButton("Standard", style: .standard)
                    sheetStyleButton("(Demo) Red", style: .demoRed)
                    sheetStyleButton("(Demo) Green", style: .demoGreen)
                    sheetStyleButton("(Demo) Blue", style: .demoBlue)
                    sheetStyleButton("(Demo) Larger Corner Radius", style: .demoRound)
                }
                
                Section(header: Text("Sheet Handle Styles").frame(height: 1), footer: bottomPadding) {
                    sheetHandleStyleButton("Standard", style: .standard)
                    sheetHandleStyleButton("(Demo) Red", style: .demoRed)
                    sheetHandleStyleButton("(Demo) Green", style: .demoGreen)
                    sheetHandleStyleButton("(Demo) Blue", style: .demoBlue)
                    sheetHandleStyleButton("(Demo) Large Yellow", style: .demoLargeYellow)
                }
            }
            .buttonStyle(PlainButtonStyle())
            .navigationTitle("Bottom Sheet Demo")
            .listStyle(InsetGroupedListStyle())
        }
        .bottomSheet(sheet)
    }
}

private extension SettingsView {
    
    var bottomPadding: some View {
        Color.clear.frame(height: useTallerMinHeight ? 280 : 130)
    }
    
    var sheet: some BottomSheetView {
        BottomSheet(
            isExpanded: $isExpanded,
            minHeight: useTallerMinHeight ? .points(300) : .points(150),
            maxHeight: useShorterMaxHeight ? .percentage(0.5) : .available,
            style: sheetStyle) {
            DemoSheetContent(style: sheetStyle)
        }
    }
    
    func listButton(_ text: String, action: @escaping () -> Void) -> some View {
        Button(action: action) {
            HStack {
                Text(text)
                Spacer()
            }.background(Color.white.opacity(0.0001))
        }
    }
    
    func sheetStyleButton(_ text: String, style: BottomSheetStyle) -> some View {
        listButton(text) {
            sheetStyle = style
        }
    }
    
    func sheetHandleStyleButton(_ text: String, style: BottomSheetHandleStyle) -> some View {
        listButton(text) {
            sheetStyle = BottomSheetStyle(handleStyle: style)
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

@digitalheir digitalheir changed the title Can ScrollViews play nice with a bottom TabView? Can ScrollViews play nice with content inset? Aug 1, 2021
@digitalheir
Copy link
Contributor Author

digitalheir commented Aug 1, 2021

Digging deeper, it's not particular to TabView but more apparent.

Trying to manipulate BottomSheet directly:

image

image

I guess it's a SwiftUI thing, but still kind of curious how to solve it.

This question on StackOverflow suggests there's no real concept of content inset yet in SwiftUI, because the answers all suggest adding a bottom padding with a magical number of 300.

I guess a thorough solution would attempt to measure the inset of the safe areas, but maybe that's beyond the scope of my question.

@digitalheir
Copy link
Contributor Author

digitalheir commented Aug 1, 2021

It seems the bottom sheet doesn't get the edge insets from GeometryReader as it would have as a top-level view because of the modifier .edgesIgnoringSafeArea(.bottom).

Instead of using the modifier, I've tried to use frame height geo.size.height + geo.safeAreaInsets.bottom, and padding(.bottom, geo.safeAreaInsets.bottom) on the sheet content.

This seems to work for both List and ScrollView. I'll make a pull request tomorrow, sleep now.

image

image

digitalheir added a commit to digitalheir/BottomSheet that referenced this issue Aug 2, 2021
digitalheir added a commit to digitalheir/BottomSheet that referenced this issue Aug 2, 2021
digitalheir added a commit to digitalheir/BottomSheet that referenced this issue Aug 2, 2021
@danielsaidi danielsaidi added the adjustment Changes to existing functionality label Aug 2, 2021
@danielsaidi
Copy link
Owner

Thanks for testing this out! I have yet to use this library in one of my apps, so there may very well be cases where the current implementation doesn't behave that well.

Let me look at the problem you describe and try to adjust the demo so that it occurs there as well, then try your fix. I'm quite busy atm, but I will try to get around to it soon 👍

@digitalheir
Copy link
Contributor Author

I've added previews in 66401a5 so it's easier to verify!

@danielsaidi
Copy link
Owner

@digitalheir I merged your PR, thanks! Can you verify that master behaves as you expect it to, and I'll close this and push a new release.

@digitalheir
Copy link
Contributor Author

Works well for me!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
adjustment Changes to existing functionality
Projects
None yet
Development

No branches or pull requests

2 participants