gpt4 book ai didi

swiftui - @ViewBuilder 关闭的默认值?

转载 作者:行者123 更新时间:2023-12-02 02:38:01 26 4
gpt4 key购买 nike

我们可以给 @ViewBuilder 闭包参数一个默认值吗?

在做一些实验的时候出现了这个问题:

import SwiftUI
import PlaygroundSupport

// MyView
struct MyView<S:View, T:View>: View {

let groove: S
let bar : T
let p : CGFloat = 10 // padding

// ⭐️ no default values
init(@ViewBuilder groove: () -> S, @ViewBuilder bar: () -> T) {
self.groove = groove()
self.bar = bar()
}

var body: some View {
ZStack {
groove
bar.padding(p)
}.frame(height: 80)
}
}

// content view
struct ContentView: View {
var body: some View {
// using MyView
MyView(groove: {
Gradient.down(.gray, .white) // ⭐️ my custom LinearGradient extension
}, bar: {
Gradient.right(.purple, .yellow, .pink) // ⭐️ my custom extension
})
}
}

PlaygroundPage.current.setLiveView(ContentView())

(⭐️ 我的自定义 Gradient 扩展被提及 here 。)

结果还不错:

enter image description here

当我尝试更进一步并为那些 @ViewBuilder 闭包提供默认值时,一切都变糟了:

import SwiftUI
import PlaygroundSupport

struct MyView<S:View, T:View>: View {

let groove: S
let bar : T
let p : CGFloat = 10 // padding

// ⭐️ try to give @ViewBuilder closures default values
init(
@ViewBuilder
groove: () -> S = { Gradient.down(.gray, .white) } as! () -> S,
@ViewBuilder
bar: () -> T = { Gradient.right(.purple, .yellow, .pink) } as! () -> T
) {
self.groove = groove()
self.bar = bar()
}

var body: some View {
ZStack {
groove
bar.padding(p)
}.frame(height: 80)
}
}

struct ContentView: View {
var body: some View {
VStack {
// ❌ can't infer `T`
MyView(groove: {
Gradient.down(.gray, .white)
})
}
}
}

PlaygroundPage.current.setLiveView(ContentView())

类型参数 T 不能从上面的代码中推断出来。有什么想法吗?

----[编辑]----

我已经对我的问题做了一些努力,这是我到目前为止所得到的:

import SwiftUI
import PlaygroundSupport

// default values for @ViewBuilder parameters
@ViewBuilder var defaultGroove: some View {
Gradient.down(.gray, .white)
}

@ViewBuilder var defaultBar: some View {
Gradient.right(.purple, .yellow, .pink)
}

// MyView
struct MyView<S:View, T:View>: View {

let groove: S
let bar : T

// ⭐️ try to give @ViewBuilder parameters default value
init(
@ViewBuilder groove: () -> S = { defaultGroove as! S },
@ViewBuilder bar : () -> T = { defaultBar as! T }
) {
self.groove = groove()
self.bar = bar()
}

var body: some View {
ZStack {
groove
bar.padding(10)
}.frame(height: 80)
}
}

// Content View
struct ContentView: View {
var body: some View {
VStack {

// `bar` omitted
MyView<LinearGradient, LinearGradient>(groove: {
Gradient.bottomRight(.white, .gray, .white)
})
// `groove` omitted
MyView<LinearGradient, Color>(bar: {
Color.pink
})
// both omitted
MyView<LinearGradient, LinearGradient>()

// ❌ can't infer `S`
// ⭐️ it would be perfect if `S` can be inferred.
// MyView(bar: {
// Gradient.right(.purple, .white)
// })
}
}
}

PlaygroundPage.current.setLiveView(ContentView())

结果是:

my view too

如果两个参数都可以自动推断就完美了。

----[再次编辑]----

根据@Asperi 的 previous advise ,我已经进行了第三次尝试:

import SwiftUI
import PlaygroundSupport

// default values for @ViewBuilder parameters

@ViewBuilder var defaultGroove: some View {
Gradient.down(.gray, .white)
}

@ViewBuilder var defaultBar: some View {
Gradient.right(.purple, .yellow, .pink)
}

// MyView
struct MyView<S:View, T:View>: View {

let groove: S
let bar : T

// default value for @ViewBuilder parameters
init(
@ViewBuilder groove: () -> S = { defaultGroove as! S },
@ViewBuilder bar: () -> T = { defaultBar as! T }
) {
self.groove = groove()
self.bar = bar()
}

var body: some View {
ZStack {
groove
bar.padding(10)
}.frame(height: 80)
}
}

// ⭐️ conditional extensions for convenience inits

extension MyView where T == LinearGradient {
/// MyView(groove:)
init(@ViewBuilder groove: () -> S){
self.init(
groove: groove,
bar : { defaultBar as! T }
)
}
}

extension MyView where S == LinearGradient {
/// MyView(bar:)
init(@ViewBuilder bar: () -> T){
self.init(
groove: { defaultGroove as! S },
bar : bar
)
}
}

extension MyView where S == LinearGradient, T == LinearGradient {
/// MyView()
init(){
self.init(
groove: { defaultGroove as! S },
bar : { defaultBar as! T }
)
}
}

// Content View
struct ContentView: View {
var body: some View {
VStack {

// ⭐️ `S`, `T` are both inferred in the following cases

MyView(groove: {
Gradient.bottomRight(.white, .yellow, .green)
}, bar: {
Color(white: 0.8)
.shadow(color: .black, radius: 3, x: 3, y: 3)
.shadow(color: .white, radius: 3, x: -3, y: -3)
})

// `bar` omitted
MyView(groove: {
Gradient.right(.red, .purple)
})

// `groove` omitted
MyView(bar: {
Gradient.right(.purple, .white)
.shadow(color: .black, radius: 3, x: 0, y: 2)
})

// `groove`, `bar` both omitted
MyView()
}
}
}

PlaygroundPage.current.setLiveView(ContentView())

结果是:

my view 3

我已经为那些方便的初始化器实现了所有需要的扩展,它可以工作,但如果我们能找到一种方法来首先避免这些扩展,那就太完美了。

这可能吗?

最佳答案

这里是一个可能的方法演示(您可以替换您的 Gradient 类型)- 您需要使用默认初始化来扩展特定类型。

经测试可与 Xcode 12/iOS 14 一起使用

extension MyView where S == Text, T == Button<Text> {
init() {
self.init(groove: { Text("Hello") },
bar: { Button("World", action: { }) })
}
}

然后您可以使用 MyView() 生成您的默认凹槽和小节。

关于swiftui - @ViewBuilder 关闭的默认值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64047904/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com