Hành vi SwiftUI của .frame (height: nil)

Oct 26 2020

Vấn đề

Tôi đang gặp sự cố chuỗi có nội dung "Kích thước khung hình không hợp lệ (âm hoặc không hữu hạn)".

Đây là mã của tôi:

struct CellStyle: ViewModifier {
    func body (content: Nội dung) -> một số Chế độ xem {
        Nội dung
            .frame (width: .infinity, height: 56, alignment: .center)
            .padding (.horizontal, 16)
    }
}

Mã chạy tốt và tôi dường như làm những gì nó phải làm, vì vậy tôi bối rối không hiểu tại sao nó lại cho tôi vấn đề về luồng. Tại sao mã sẽ chạy mà không có chiều rộng / chiều cao hữu hạn, mâu thuẫn với tài liệu của Apple? (xem phần "Một số bài đọc" bên dưới)

Sự sửa chữa

Mã này khắc phục sự cố rất tốt, nhưng tôi vẫn ước mình hiểu tại sao mã trước đó không bị lỗi hoặc tạo ra lỗi.

struct CellStyle: ViewModifier {
    func body (content: Nội dung) -> một số Chế độ xem {
        Nội dung
            .frame (chiều cao: 56, căn chỉnh: .center)
            .frame (maxWidth: .infinity)
            .padding (.horizontal, 16)
    }
}

Theo như tôi có thể nói, nó mang lại cho tôi vấn đề về luồng đó bởi vì tôi nói .framerằng tôi muốn chiều rộng không hữu hạn và nó muốn chiều rộng là hữu hạn.

Các câu hỏi khác về tràn ngăn xếp

Tôi đã tìm thấy hai câu hỏi giống nhau:
iOS 14 Kích thước khung hình không hợp lệ (âm hoặc không hữu hạn)

SwiftUI iOS14 GeometryReader Kích thước khung hình không hợp lệ

Trong câu hỏi đầu tiên, vấn đề luồng có ý nghĩa vì với mã .frame(width: p.size.width - padding), không có gì đảm bảo rằng p.size.widthsẽ ít hơn padding. Theo như tôi có thể nói, đó là một vấn đề mà giá trị đã cho có thể âm.
Vấn đề này tôi đang gặp phải liên quan đến giá trị đã cho không phải là hữu hạn, vì vậy các câu hỏi không liên quan.
Câu hỏi thứ hai vẫn chưa được trả lời và hơi mơ hồ, vì vậy nó không hữu ích cho tôi lúc này. Có thể sau này ai đó sẽ trả lời với một câu trả lời hữu ích, nhưng hiện tại, nó không hữu ích.

Một số bài đọc

Nhìn vào tài liệu của Apple, tôi thấy điều này:

Sử dụng phương pháp này để chỉ định kích thước cố định cho chiều rộng, chiều cao hoặc cả hai của chế độ xem. Nếu bạn chỉ chỉ định một trong các thứ nguyên, thì chế độ xem kết quả sẽ giả định hành vi định kích thước của chế độ xem này trong thứ nguyên kia.

Vậy thì tại sao nó .frame(width: .infinity, height: 56, alignment: .center)thậm chí còn chạy?
Apple có nghĩa gì khi "chế độ xem kết quả giả định hành vi định kích thước của chế độ xem này trong không gian khác."? Nó sẽ luôn giả định rằng chế độ xem là một chế độ xem "đẩy ra", do đó sẽ cho kết quả tương tự như .infinity?

Tôi đã thử nghiệm điều này và chạy mã này:

struct CellStyle: ViewModifier {
    func body (content: Nội dung) -> một số Chế độ xem {
        Nội dung
            .frame (chiều cao: 56, căn chỉnh: .center)
            .padding (.horizontal, 16)
    }
} 

Nó dường như cho cùng một kết quả, vì vậy bây giờ tôi tò mò liệu có bao giờ xảy ra trường hợp "giả định" chiều rộng nhanh chóng sẽ dẫn đến một hành vi khác .infinitykhông?

Câu hỏi cuối cùng

Sự khác biệt về hành vi giữa .frame(width: .infinity)vs .frame(width: nil)(tương đương với việc phát ra chiều rộng hoặc chiều cao).

khung func (width: CGFloat? = nil, height: CGFloat? = nil, alignment: Alignment = .center) -> một số View

Tài liệu của Apple

Cảm ơn đã giúp đỡ!

Trả lời

1 Asperi Oct 26 2020 at 19:43

Bởi vì nó là hợp đồng giao diện được lập thành văn bản:

/// - Parameters:
///   - width: A fixed width for the resulting view. If `width` is `nil`,
///     the resulting view assumes this view's sizing behavior.
///   - height: A fixed height for the resulting view. If `height` is `nil`,
///     the resulting view assumes this view's sizing behavior.
///   - alignment: The alignment of this view inside the resulting view.
///     `alignment` applies if this view is smaller than the size given by
///     the resulting frame.
///
/// - Returns: A view with fixed dimensions of `width` and `height`, for the
///   parameters that are non-`nil`.
@inlinable public func frame(width: CGFloat? = nil, height: CGFloat? = nil, alignment: Alignment = .center) -> some View

trong khi loại bổ trợ với các đối số min / max cho phép các ràng buộc linh hoạt (không được sao chép ở đây - đọc trong mô-đun SwiftUI được tạo).

MikaelWeiss Oct 26 2020 at 22:32

.Frame (width: nil) làm gì

Về cơ bản .frame sẽ lấy các giá trị đã cho và trả về một chế độ xem khác được cập nhật với các giá trị bạn đặt.
Nếu bạn bỏ qua một trong các tham số hoặc đặt nó thành nil, thì nó sẽ lấy giá trị chiều rộng / chiều cao tương ứng của chế độ xem trước đó.

Mã kiểm tra:

struct ContentView: View {
    @State var keyValue = ""
    var body: some View {
        VStack(spacing: 10) {
            Text("Something")
                .background(Color.blue)
            
            Text("Something")
                .frame(width: 300, height: nil, alignment: .center)
                .background(Color.blue)
            
            Text("Something")
                .frame(width: nil, height: 200, alignment: .center)
                .background(Color.blue)
            
            Text("Something")
                .frame(width: nil, height: nil, alignment: .center)
                .background(Color.blue)
        }
    }
}

Tại sao .frame (width: .infinity) vẫn chạy

.infinity( Apple doc on .infinity ) thuộc loại này Float, vì vậy không có cách nào để .framekhông loại trừ nó, nhưng nó vẫn có thể tạo ra vấn đề. (Do đó, vấn đề chủ đề)

Cảm ơn Mark Moeykens đã giúp tôi giải đáp thắc mắc này!