You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI自定义布局添加垂直滚动遇问题:ProposedViewSize为0

SwiftUI自定义布局添加垂直滚动的问题

我希望为SwiftUI中的自定义布局添加垂直滚动功能,目前不知该如何实现。以下是我的参考代码:

struct TokenData {
    let email: String
}

let gradientColor = LinearGradient(colors: [Color(red: 0/255, green: 204/255, blue: 172/255), Color(red: 1/255, green: 99/255, blue: 240/255)], startPoint: .top, endPoint: .bottom)

struct TokenView: View {
    @Binding var dataSource: [TokenData]
    @Binding var tokenData: TokenData
    var body: some View {
        HStack {
            Text(tokenData.email)
                .foregroundStyle(.white)
            Button(action: {
                if let index = self.dataSource.firstIndex(where:  { $0.email == tokenData.email }) {
                    self.dataSource.remove(at: index)
                } else {
                    assertionFailure("Should not come here.. ")
                }
            }, label: {
                Image(systemName: "multiply")
                    .renderingMode(.template)
            })
            .buttonStyle(.plain)
            .foregroundStyle(.white)
        }
        .padding(3)
        .background(gradientColor)
        .clipShape(RoundedRectangle(cornerRadius: 4))
        
    }
}

struct TokenFieldView: View {
    @State var resultData: [TokenData] = []
    @State var inputData: String = ""
    @State var layout: AnyLayout = AnyLayout(CustomTokenFieldLayout())

    var body: some View {
        VStack(alignment: .center) {
            HStack(alignment: .center) {
                TextField("Enter mail Ids..", text: $inputData)
                    .onSubmit {
                        resultData.append(TokenData(email: inputData))
                    }
                Button {
                    self.resultData.removeAll()
                } label: {
                    Text("clear")
                }
            }
            Divider()
            ScrollView(.vertical) {
                layout {
                    ForEach(resultData.indices, id: \.self) { index in
                        TokenView(dataSource: $resultData, tokenData: self.$resultData[index])
                    }
                }
            }
        }
        .onAppear(perform: {
            let window = NSApplication.shared.windows.first
            window?.level = .floating
        })
    }
}

struct CustomTokenFieldLayout: Layout {
    func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {
        return CGSize(width: proposal.width!, height: proposal.height!)
    }
    
    func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {
        guard !subviews.isEmpty else {
            return
        }
        
        var point = bounds.origin
        let hSpacing: Double = 5
        let vSpacing: Double = 5
        point.x += hSpacing
        point.y += vSpacing
        for subview in subviews {
            if (point.x + subview.dimensions(in: .unspecified).width + hSpacing) > bounds.width {
                point.y += (subview.dimensions(in: .unspecified).height + vSpacing)
                point.x = hSpacing
            }
            subview.place(at: point, anchor: .leading, proposal: proposal)
            point.x += (subview.dimensions(in: .unspecified).width + hSpacing)
        }
    }
}

UI示例图

当我尝试将自定义布局放入ScrollView时,Layout定义中的ProposedViewSize的width和height均为0,请问有人能解释这是为什么吗?

以下是修改后的TokenFieldView代码:

struct TokenFieldView: View {
    @State var resultData: [TokenData] = []
    @State var inputData: String = ""
    @State var layout: AnyLayout = AnyLayout(CustomTokenFieldLayout())

    var body: some View {
        VStack(alignment: .center) {
            HStack(alignment: .center) {
                TextField("Enter mail Ids..", text: $inputData)
                    .onSubmit {
                        resultData.append(TokenData(email: inputData))
                    }
                Button {
                    self.resultData.removeAll()
                } label: {
                    Text("clear")
                }
            }
            Divider()
            ScrollView {
                layout {
                    ForEach(resultData.indices, id: \.self) { index in
                        TokenView(dataSource: $resultData, tokenData: self.$resultData[index])
                    }
                }
            }
        }
        .onAppear(perform: {
            let window = NSApplication.shared.windows.first
            window?.level = .floating
        })
    }
}

内容的提问来源于stack exchange,提问作者Vandijk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 03:15:03