Easy methods to management how a View is moved/resized when its content material is just too massive?

0
1
Easy methods to management how a View is moved/resized when its content material is just too massive?


I’ve create a StickyHeaderScrollView utilizing a ZStack to overlay MyScrollView with a header view.

MyScrollView is a UIViewControllerRepresentable holding an UIScrollView which permits setting the contentInset and gives contentOffset updates on scrolling.

The StickyHeaderScrollView units the scroll contentInset to the defaultHeaderHeight, in order that the whole scroll content material is seen under the header. When the scroll view is scrolled up, the header view shrinks up till minHeaderHeight is reached. At this level the scroll content material begins to scroll under the header.

This works as supposed, so long as the header content material isn’t bigger than minHeaderHeight. If that is so, the header content material must be clipped.

Easy methods to I management this?

As a substitute of this anticipated behaviour (clipping), the header view strikes up to create space for the content material.

Within the demo code under the defaultHeaderHeight is 200px and the minHeaderHeight is 100px. This works superb, so long as the header content material accommodates solely two 50px rects. However when a 3rd 50px rect is added, the content material top of 150px exceeds the minHeaderHeight of 100px.

Whereas I perceive why this breaks the format, I wish to know if/how I can management how that is dealt with (clipping as a substitute of transferring).


Easy methods to management how a View is moved/resized when its content material is just too massive?

struct StickyHeaderScrollView<Header: View, Physique: View>: View {
    let contentHeader: () -> Header
    let contentBody: Physique
    
    non-public var minHeaderHeight: CGFloat
    non-public var defaultHeaderHeight: CGFloat
    @State non-public var headerHeight: CGFloat = 1
    
    init(
        headerHeight: CGFloat = 200,
        minHeaderHeight: CGFloat = 50,
        @ViewBuilder header: @escaping () -> Header,
        @ViewBuilder physique: () -> Physique
    ) {
        self.defaultHeaderHeight = headerHeight
        self.minHeaderHeight = minHeaderHeight
        
        self.contentHeader = header
        self.contentBody = physique()
    }
    
    
    var physique: some View {
        ZStack(alignment: .prime) {
            // MyScrollView is a UIViewControllerRepresentable holding an UIScrollView. Used
            // as a substitute of SwiftUI ScrollView have the ability to set the contentOffset and get
            // scroll place updates
            MyScrollView(
                content material: { contentBody },
                topContentOffset: defaultHeaderHeight,
                onScroll: { contentOffset in
                    self.headerHeight = max(minHeaderHeight, -contentOffset.y)
                }
            )
            .onAppear {
                headerHeight = defaultHeaderHeight
            }
            .ignoresSafeArea(edges: .backside)
            

            VStack(spacing: 0) {
                contentHeader()
            }
            .body(top: headerHeight)
        }
    }
}


struct SomeView: View {
    var physique: some View {
        StickyHeaderScrollView(
            headerHeight: 200,
            minHeaderHeight: 100,
            header: {
                ZStack {
                    // Navbar
                    VStack {
                        HStack {
                            Button("Cancel") {}
                            Spacer()
                            Button("Save") {}
                        }
                        .padding(.prime)
                        .padding(.backside, 16)
                        .background(.inexperienced)
                    }
                    .body(maxHeight: .infinity, alignment: .prime)
                    .background(.yellow)
                    
                    
                    // Some Header Content material
                    // Complete top: 3 rect * 50 = 150  >  minHeaderHeight: 100
                    VStack(spacing: 0) {
                        Rectangle().fill(.blue).body(width: 50, top: 50)
                        Rectangle().fill(.purple).body(width: 50, top: 50)
                        Rectangle().fill(.cyan).body(width: 50, top: 50)
                    }
                    //.clipped() No impact
                }
                //.clipped() No impact + header background is now not robotically extendet into protected space
                .padding(.horizontal)
                .background(.grey)
            },
            physique: {
                VStack {
                    // Some ScrollContent
                    Colour.pink.body(top: 200)
                    Colour.blue.body(top: 200)
                    Colour.inexperienced.body(top: 200)
                    Colour.purple.body(top: 200)
                    Colour.orange.body(top: 200)
                }
            }
        )
    }
}

LEAVE A REPLY

Please enter your comment!
Please enter your name here