โœจTestIdealSizeView

โฌ†๏ธ ้œ€่ฆ๏ผš .shadowedBorder()

// 2022.02.14 / (refactor)
import SwiftUI

/// a view to test frame's (min/ideal/max) behaviors.
struct TestIdealSizeView: View {
    
    // view state
    @State private var width: CGFloat = 50    // offered width
    @State private var fixed = false          // fixed at ideal width
    
    // computed property
    var intWidth: Int { Int(width) }          // integral width
    
    var body: some View {
        HStack(alignment: .top) {
            // subviews with explicitly offered width
            VStack {
                subviewsWithOfferdWidth
                controls
            }
            // subviews without explicitly offered width
            VStack {
                childviews.padding()
            }
        }
    }
}

extension TestIdealSizeView {
    
    /// subviews to test frame's behaviors.
    var subviewsWithOfferdWidth: some View {
        childviews
        // โญ๏ธ parent's offered size
            .frame(width: width)
        // โญ๏ธ show frame's border
            .shadowedBorder(.white.opacity(0.8))    // ๐ŸŒ€View+.shadowedBorder()
            .padding()
    }
    
    /// child views
    var childviews: some View {
        Group {
            // โญ๏ธ subviews with `idealWidth` undefined.
            IdealWidthView(minWidth: 100)
            IdealWidthView(minWidth: 100, maxWidth: 200)
            
            // โญ๏ธ subviews with defined `idealWidth`
            Group {
                IdealWidthView(idealWidth: 150, color: .orange)
                IdealWidthView(minWidth: 100, idealWidth: 150, color: .orange)
            }
            // ------------------------------------------------------
            // โญ๏ธ fixed at ideal width?
            .fixedSize(horizontal: fixed, vertical: false)
            // ------------------------------------------------------
        }
        .frame(height: 50)
    }
    
    /// controls to change view states 
    var controls: some View {
        VStack(spacing: 20) {
            // ๐ŸŽ› `Toggle` to switch on `fixed` state.
            Toggle(isOn: $fixed.animation()) {           // toggle with animation
                Text("fixed ideal width").fixedSize()    // text no wrap
                    .foregroundColor(.primary) 
            }
            // ๐ŸŽ› `Slider` to control the offered width
            Slider(value: $width, in: 20...300, step: 1)
            // label for offered width
            Text("offered width: \(intWidth)")
                .font(.system(.caption, design: .monospaced))
                .foregroundColor(.secondary)
        }
        .padding()
    }
}

/// โญ๏ธ adaptive view that can declare its min/ideal/max width.
struct IdealWidthView: View {
    
    var minWidth: CGFloat?
    var idealWidth: CGFloat?
    var maxWidth: CGFloat?
    
    var label: String {
        var strs = [String]()
        if let min = minWidth { strs.append("min: \(Int(min))") }
        if let ideal = idealWidth { strs.append("ideal: \(Int(ideal))") }
        if let max = maxWidth { strs.append("max: \(Int(max))") }
        return strs.joined(separator: ", ")
    }
    
    var color: Color = .yellow
    
    var body: some View {
        color
            // ------------------------------------------------------
            // โญ๏ธ declare min/ideal/max width
            .frame(minWidth: minWidth, idealWidth: idealWidth, maxWidth: maxWidth)
            // ------------------------------------------------------
            .overlay {
                Text(label).font(.caption).fixedSize()  // โญ๏ธ no wrap
                    .shadow(radius: 2)
                    .foregroundColor(.black)
            }
            // โญ๏ธ show frame visually
            .dimension(arrow: .blue, label: .orange)    // ๐ŸŒ€ View+.dimension()
    }
}

struct TestIdealSizeView_Previews: PreviewProvider {
    static var previews: some View {
        TestIdealSizeView()
    }
}

History

  1. 2022.02.14

Last updated