[SOLVED] SwiftUI – Draggable Slides with List

Issue

I’m a bit stumped building a draggable slide containing a list. Inspired by this post, a MRE of what I have is below.

import SwiftUI


struct ContentView: View {
    
    static let kMinHeight: CGFloat = 100.0
    @State var currentHeight: CGFloat = kMinHeight // << any initial
    
    var body: some View {
        
        
        GeometryReader { g in // << for top container height limit
            ZStack(alignment: .bottom) {
                Rectangle().fill(Color.yellow) // << just for demo
                
                self.card()
                    .gesture(DragGesture()
                        .onChanged { value in
                            // as card is at bottom the offset is reversed
                            let newHeight = self.currentHeight - (value.location.y - value.startLocation.y)
                            if newHeight > Self.kMinHeight && newHeight < g.size.height {
                                self.currentHeight = newHeight
                            }
                        })
            }
        }
    }
    
    func card() -> some View {
        ZStack(alignment: .top){
            
            RoundedRectangle(cornerRadius: 16.0)
                .frame(height:currentHeight)
            VStack{
                RoundedRectangle(cornerRadius: Constants.radius)
                    .fill(Color.white)
                    .frame(
                        width: Constants.indicatorWidth,
                        height: Constants.indicatorHeight
                    )
                Text("Card")
                    .font(.title)
                    .fontWeight(.bold)
                    .foregroundColor(Color.white)
                    .multilineTextAlignment(.center)
                    .padding(.top)
                Text("LINE 2")
                    .foregroundColor(Color.white)
                
                // Uncomment the following lines, and the slides becomes unusable
                // List {
                //    Text("The Fellowship of the Ring")
                //    Text("The Two Towers")
                //    Text("The Return of the King")
                //}
            }
        }
    }
}

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

The slides built using this example works, but note that I’ve commented out a few lines containing a list. Once these lines are uncommented, the slider becomes unusable.

Two obvious questions: (1) Why is that, and (2) any suggestions on how to fix it? 🙂

Solution

In your code you are only specifying the height of the rectangle within the card. This isn’t an issue if only the rectangle is present. But:

The trouble here is that List wraps its own scrolling behavior, so it expands to take up all the space it can. Rather than capping only the rectangle inside card, cap the height of your card to currentHeight:

func card() -> some View {
        ZStack(alignment: .top){
            
            RoundedRectangle(cornerRadius: 16.0)
            VStack{
                RoundedRectangle(cornerRadius: 10)
                    .fill(Color.white)
                    .frame(
                        width: 20,
                        height: 20
                    )
                Text("Card")
                    .font(.title)
                    .fontWeight(.bold)
                    .foregroundColor(Color.white)
                    .multilineTextAlignment(.center)
                    .padding(.top)
                Text("LINE 2")
                    .foregroundColor(Color.white)
                
//                 Uncomment the following lines, and the slides becomes unusable
                 List {
                    Text("The Fellowship of the Ring")
                    Text("The Two Towers")
                    Text("The Return of the King")
                }
            }
        }
        .frame(maxHeight: currentHeight) // This line
    }

Answered By – atultw

Answer Checked By – Cary Denson (BugsFixing Admin)

Leave a Reply

Your email address will not be published.