skip to Main Content

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? 🙂

2

Answers


  1. The problem you are having is the List is a greedy view. It is taking up ALL of the space it possibly can, which throws your height out of whack. The simple solution is to put it in a frame, that is zero when the card is all the way down. Since we have those values, all we need to do is this:

    List {
        Text("The Fellowship of the Ring")
        Text("The Two Towers")
        Text("The Return of the King")
    }
    .frame(height: currentHeight - DraggableSlides.kMinHeight)
    
    Login or Signup to reply.
  2. 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
        }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search