SwiftUI - 带列表的可拖动幻灯片

SwiftUI - Draggable Slides with List

我有点难以构建包含列表的可拖动幻灯片。受到 的启发,下面是我所拥有的 MRE。

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()
    }
}

使用此示例制作的幻灯片有效,但请注意,我注释掉了几行包含列表的内容。取消注释这些行后,滑块将无法使用。

两个明显的问题:(1) 为什么会这样,以及 (2) 关于如何解决它的任何建议? :)

您遇到的问题是 List 是一个贪婪的观点。它占据了它可能占据的所有 space,这让你的身高变得不正常。简单的解决方案是将它放在一个框架中,当卡片一直向下时该框架为零。既然我们有了这些值,我们需要做的就是:

List {
    Text("The Fellowship of the Ring")
    Text("The Two Towers")
    Text("The Return of the King")
}
.frame(height: currentHeight - DraggableSlides.kMinHeight)

在您的代码中,您仅指定卡片内矩形的高度。如果只有矩形存在,这不是问题。但是:

这里的问题是 List 包装了自己的滚动行为,因此它会扩展以占用所有它可以占用的 space 。不要只限制卡内的矩形,而是将卡的高度限制为 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
    }