如何基于可选的 Binding<Image> 在此 SwiftUI @ViewBuilder 中初始化 Bool?

问题描述

我的目标是使用三元运算符为图像添加阴影,但如果视图使用认图像,则添加阴影。

这是我的代码

import SwiftUI

struct Imagedisplay: View {
    @State private var defaultimage: Image = Image(systemName: "person.crop.circle.fill")
    private var defaultText: String = "Add picture"
    private var hasShadow: Bool = true
    private var text: String?
    private var image: Binding<Image>?
    
    public init(_ text: String,image: Binding<Image>) {
        self.init(
            text: .some(text),image: image
        )
    }
    
    public init(image: Binding<Image>) {
        self.init(
            text: nil,image: image
        )
    }
    
    public init() {
        self.init(
            text: nil,image: nil
        )
    }
    
    private init(text: String?,image: Binding<Image>?) {
        self.text = text
        self.image = image
    }
    
    private struct InternalImagedisplay: View {
        var text: String
        var hasShadow: Bool  /// NOT CERTAIN WHERE THIS BELONGS,OR IF IT GOES HERE ...
        @Binding var image: Image
        
        @viewbuilder
        var body: some View {
                        
            vstack {
                image
                    .imagedisplayStyle()
                    .shadow(radius: hasShadow ? 4.0 : 0.0) /// HERE IS WHERE I'LL USE IT...
                
                Button(action: {
                    
                    //Todo: - Code to present image picker.
                    
                },label: {
                    Text(text)
                })
            }
        }
    }
    
    var body: some View {
        InternalImagedisplay(
            text: text ?? defaultText,hasShadow: false,/// THIS IS NOT WORKING IN ANY IMPLEMENTATION ...
            image: image ?? $defaultimage
        )
    }
}

我也有 Image 的扩展:

import SwiftUI

extension Image {
    func imagedisplayStyle() -> some View {
        return self
            .resizable()
            .scaledToFill()
            .frame(maxWidth: .infinity,maxHeight: .infinity,alignment: .center)
            .aspectRatio(contentMode: .fit)
            .clipShape(Circle())
            .foregroundColor(.gray)
   }
}

我正在尝试让看起来像这样的代码运行良好,而且非常棒,除了 shadow bool:

struct ContentView: View {
    
    @State private var image = Image("img1")
    
    @State private var defaultimage: Bool = true
    
    var body: some View {
        vstack (spacing: 48) {
            // no binding
            Imagedisplay()
            // binding
            Imagedisplay("Select image",image: $image)
            Imagedisplay(image: $image)
        }
        .frame(width: 190)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}


解决方法

在初始值设定项中,您可以根据是否传入图像参数来设置 hasShadow

然后,您可以将其传递给您的 InternalImageDisplay

为了测试目的,我使阴影更明显一些:


struct ImageDisplay: View {
    @State private var defaultImage: Image = Image(systemName: "person.crop.circle.fill")
    private var defaultText: String = "Add picture"
    private var hasShadow: Bool = true
    private var text: String?
    private var image: Binding<Image>?
    
    public init(_ text: String,image: Binding<Image>) {
        self.init(
            text: text,image: image,hasShadow: true //<-- Here
        )
    }
    
    public init(image: Binding<Image>) {
        self.init(
            text: nil,hasShadow: true //<-- Here
        )
    }
    
    public init() {
        self.init(
            text: nil,image: nil,hasShadow: false //<-- Here
        )
    }
    
    private init(text: String?,image: Binding<Image>?,hasShadow : Bool) {  //<-- Here
        self.text = text
        self.image = image
        self.hasShadow = hasShadow  //<-- Here
    }
    
    private struct InternalImageDisplay: View {
        var text: String
        var hasShadow: Bool   //<-- This gets passed in as a prop
        @Binding var image: Image
        
        @ViewBuilder
        var body: some View {
                        
            VStack {
                image
                    .imageDisplayStyle()
                    .shadow(color: Color.green,radius: hasShadow ? 10.0 : 0)  //<-- Here (now it's green for testing)
                
                Button(action: {
                    
                    //TODO: - Code to present image picker.
                    
                },label: {
                    Text(text)
                })
            }
        }
    }
    
    var body: some View {
        InternalImageDisplay(
            text: text ?? defaultText,hasShadow: hasShadow,//<-- Here
            image: image ?? $defaultImage
        )
    }
}