2

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.

Mikael Weiss
  • 839
  • 2
  • 14
  • 25

2 Answers2

1
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.

cookednick
  • 1,025
  • 9
  • 16
  • If I completely get rid of the all stacks and just have the list with the modifier .offset(y: 100) (((So the code would be: struct ListView: View { var body: some View { List { Text("Some Text")}.offset(y: 100)}}and then scroll, then the cells still disappear under something. (that's what you're seeing in the second picture. – Mikael Weiss May 08 '20 at 16:41
  • What I'm trying to do is make it so that you can sort of see the text as it disappears. This design is demonstrated with both the tab bar and the nav bar in the music app. – Mikael Weiss May 08 '20 at 16:43
  • I think that there is a way to do this with a normal tab bar/navigation bar (https://medium.com/@mycroftservicer/swiftui-hack-navigationview-and-tabviews-appearance-cd9c4b6ffb53) but I want to do the same thing with a custom view because my screen does not require either a tab bar or a navigation bar. Also, with a normal navigation bar, when I would scroll up, it would interfere with the rest of my UI. – Mikael Weiss May 08 '20 at 17:00
  • I've been following along with the Design+Code courses, and in part 2 of the SwiftUI courses, video 19, he shows how to make the blur effect. As far as I understand, the blur effect is something that is in UIKit, but not yet in SwiftUI. In order to solve for this, he makes a UIViewRepresentable with the blur effect. This solves for how to make something transparent, but it still doesn't explain why the list is being clipped. – Mikael Weiss May 13 '20 at 18:16
  • Sorry. I didn't understand what you meant. I get it now. Where would I call that? – Mikael Weiss May 16 '20 at 23:34
  • Okay, according to this answer: https://stackoverflow.com/questions/20449256/how-does-clipstobounds-work You would call that in "viewDidLoad" which I understand to be a UIKit function. Is there a way to change the clipsToBounds equal to false without setting it in viewDidLoad? SwiftUI doesn't use the "viewDidLoad" function because there's no view controller with SwiftUI. At least that's how I understand it. – Mikael Weiss May 16 '20 at 23:48
  • @MikaelWeiss Yes. Sorry! Stick it in the body of AppDelegate.swift -> applicationDidFinishLaunchingWithOptions(). Comes with every Xcode project. – cookednick May 17 '20 at 18:12
  • 1
    I tried both UITableView.appearance().clipsToBounds = false and UIScrollView.appearance().clipsToBounds = false, and both didn't change anything. I also tried changing both to true and that also didn't change anything. Maybe it's a bug with SwiftUI. – Mikael Weiss May 26 '20 at 20:58
  • 1
    @MikaelWeiss Hello! I'm diving through my answer history and I'd like to clarify that there is a way to do this now using the `.safeAreaInset(edge: .top) { // content }` modifier. Just put that on your list and have the buttons/blur/whatever be within that block. – cookednick Dec 07 '22 at 02:09
0

Using LazyHStack instead of HStack solves the clipping problem.

Jeremy Caney
  • 7,102
  • 69
  • 48
  • 77
arthas
  • 680
  • 1
  • 8
  • 16