Search code examples
swiftswiftui-listswiftuiswiftui-form

SwiftUI List/Form/ScrollView being clipped when offset


I changed the y offset of a list, and now it's being clipped.
I am trying to make it so that when you scroll, you can partially see the text underneath the Title and buttons at the top of the view. In other words, I want the top section of the screen to be slightly transparent.

I added the offset to the list, so that it didn't overlap with the information at the top.

list image

The image above is with the VStack in my code showing. I thought that the VStack might be getting in the way, so I commented it out and the image below was the result:

list without VStack at top

Here's my code:

var body: some View {
    ZStack {

        VStack {
            HStack {

                Button(action: {self.showAccountView.toggle()}) {
                    Image(systemName: "person.fill")
                        .renderingMode(.original)
                        .font(.system(size: 20, weight: .bold))
                        .frame(width: 44, height: 44)
                        .modifier(NavButtons())
                }
                .sheet(isPresented: $showAccountView) {
                    AccountView()
                }
                Spacer()
                Button(action: { self.showHelpCenter.toggle()}) {
                    Image(systemName: "questionmark")
                        .renderingMode(.original)
                        .font(.system(size: 20, weight: .bold))
                        .modifier(NavButtons())
                }
                .sheet(isPresented: $showHelpCenter) {
                    HelpCenter()
                }
            }
            .frame(maxWidth: .infinity)
            .padding(.horizontal)
            Spacer()
        }
        List {
            ForEach (store.allLogs) { thing in
                VStack (alignment: .leading) {
                    HStack {
                        Text("\(thing.date) , \(thing.time)")
                    }
                    Text(thing.notes)
                        .multilineTextAlignment(.leading)
                }
            }
        }.offset(y: 50)

    }
}

EDIT:

This is one possible solution:

struct MyList: UIViewRepresentable {
    func makeUIView(context: Context) -> UITableView {
        let view = UITableView()
        view.clipsToBounds = false

        return view
    }

    func updateUIView(_ uiView: UITableView, context: Context) {

    }
}

and then you would use makeUIView and updateUIView to update the cells. This is just messy and it's not really using SwiftUI at that point.

Second Edit
I've found this issue with a scrollView as well as a form:
ScrollView, Form, and List all being clipped when offset
The black is the background. Here's the code for all three:

Group {
        List ((0 ... 10), id: \.self) {
            Text("Row \($0)")
        }
        .offset(y: 200)
        .border(Color.blue, width: 3)
        .background(Color.black)

        ScrollView {
            Text("Text")
        }
        .foregroundColor(.white)
        .offset(y: 200)
        .border(Color.blue, width: 3)
        .background(Color.black)

        Form {
            Text("Text")
        }
        .offset(y: 200)
        .border(Color.blue, width: 3)
        .background(Color.black)
    }

Here are the wireframes of a List:
Wireframes of list

Here are the names of frames that are the same height as the List/Form/ScrollView:

List:
PlainList.BodyContent
ListCore.Container
ListRepresentable
View Host
TableWrapper
UpdateCoalescingTableView

Form:
GroupList.BodyContent
ListCore.Container
ListRepresentable
View Host
TableWrapper
UpdateCoalescingTableView

ScrollView:
ScrollViewBody
SystemScrollView
View Host
HostingScrollView

I guess that my question has changed from "how do I do this..." to "Why is this happening?" I'm pretty confused about what exactly is going on.


Solution

  • UIScrollView.appearance().clipsToBounds = false
    

    Stick this in the body of AppDelegate.swift -> applicationDidFinishLaunchingWithOptions(). It will make all scroll views across your application unclipped by default.

    The problem is that a list has a table view (which is a scroll view) underneath. Scroll views by default are clipped. We just need to change that default.