SwiftUI 视图:两个不同的初始值设定项:无法将类型 'Text' 的值转换为闭包结果类型 'Content'
SwiftUI View: two different initializers: cannot convert value of type 'Text' to closure result type 'Content'
代码:
import SwiftUI
public struct Snackbar<Content>: View where Content: View {
private var content: Content
// Works OK
public init(@ViewBuilder content: () -> Content) {
self.content = content()
}
init(_ text: String) {
self.init {
Text(text) // cannot convert value of type 'Text' to closure result type 'Content'
.font(.subheadline)
.foregroundColor(.white)
.multilineTextAlignment(.leading)
}
}
public var body: some View {
HStack {
VStack(alignment: .leading, spacing: 4) {
content
}
Spacer()
}
.frame(maxWidth: .infinity,
minHeight: 26)
.padding(.fullPadding)
.background(Color.black)
.clipShape(RoundedRectangle(cornerRadius: .defaultCornerRadius))
.shadow(color: Color.black.opacity(0.125), radius: 4, y: 4)
.padding()
}
}
我收到这个错误:
cannot convert value of type 'Text' to closure result type 'Content'
我想要实现的目标是有 2 个单独的初始化器,一个用于 View
类型的内容,另一个是字符串的快捷方式,它将放置一个预定义的 Text
用一些样式代替 Content
.
的组件
如果 Text
是 some View
并且我认为它应该编译,为什么我会收到此错误。
一种方法是使内容可选并使用另一个文本变量并基于 nil 值显示视图。
public struct Snackbar<Content>: View where Content: View {
private var content: Content? // <= Here
private var text: String = "" // <= Here
// Works OK
public init(@ViewBuilder content: () -> Content) {
self.content = content()
}
init(_ text: String) {
self.text = text // <= Here
}
public var body: some View {
HStack {
VStack(alignment: .leading, spacing: 4) {
if let content = content { // <= Here
content
} else {
Text(text)
.font(.subheadline)
.foregroundColor(.white)
.multilineTextAlignment(.leading)
}
}
Spacer()
}
// Other code
您也可以使用AnyView
public struct Snackbar: View {
private var content: AnyView // Here
// Works OK
public init<Content: View>(@ViewBuilder content: () -> Content) {
self.content = AnyView(content()) // Here
}
init(_ text: String) {
self.content = AnyView(Text(text)
.font(.subheadline)
.foregroundColor(.white)
.multilineTextAlignment(.leading)
) // Here
}
public var body: some View {
HStack {
VStack(alignment: .leading, spacing: 4) {
self.content
}
Spacer()
}
可以指定Content
的类型。
代码:
public struct Snackbar<Content>: View where Content: View {
private var content: Content
// Works OK
public init(@ViewBuilder content: () -> Content) {
self.content = content()
}
init(_ text: String) where Content == ModifiedContent<Text, _EnvironmentKeyWritingModifier<TextAlignment>> {
self.init {
Text(text)
.font(.subheadline)
.foregroundColor(.white)
.multilineTextAlignment(.leading) as! ModifiedContent<Text, _EnvironmentKeyWritingModifier<TextAlignment>>
}
}
/* ... */
}
这里唯一的区别是 init
之后的 where
和 init
里面的类型的 force-cast。
为了避免特定的类型,你可以把它抽象成一个单独的视图:
init(_ text: String) where Content == ModifiedText {
self.init {
ModifiedText(text: text)
}
}
/* ... */
struct ModifiedText: View {
let text: String
var body: some View {
Text(text)
.font(.subheadline)
.foregroundColor(.white)
.multilineTextAlignment(.leading)
}
}
general-purpose 的解决方案是提供一个在语义上等同于 some View
的包装器。 AnyView
是内置的,可用于此目的。
init(_ text: String) where Content == AnyView {
self.init {
AnyView(
Text(text)
.font(.subheadline)
.foregroundColor(.white)
.multilineTextAlignment(.leading)
)
}
}
此外,将您的代码更改为
private let content: () -> Content
public init(@ViewBuilder content: @escaping () -> Content) {
self.content = content
}
这样您就不必将 content
的结果包装在另一个闭包中。
VStack(alignment: .leading, spacing: 4, content: content)
代码:
import SwiftUI
public struct Snackbar<Content>: View where Content: View {
private var content: Content
// Works OK
public init(@ViewBuilder content: () -> Content) {
self.content = content()
}
init(_ text: String) {
self.init {
Text(text) // cannot convert value of type 'Text' to closure result type 'Content'
.font(.subheadline)
.foregroundColor(.white)
.multilineTextAlignment(.leading)
}
}
public var body: some View {
HStack {
VStack(alignment: .leading, spacing: 4) {
content
}
Spacer()
}
.frame(maxWidth: .infinity,
minHeight: 26)
.padding(.fullPadding)
.background(Color.black)
.clipShape(RoundedRectangle(cornerRadius: .defaultCornerRadius))
.shadow(color: Color.black.opacity(0.125), radius: 4, y: 4)
.padding()
}
}
我收到这个错误:
cannot convert value of type 'Text' to closure result type 'Content'
我想要实现的目标是有 2 个单独的初始化器,一个用于 View
类型的内容,另一个是字符串的快捷方式,它将放置一个预定义的 Text
用一些样式代替 Content
.
如果 Text
是 some View
并且我认为它应该编译,为什么我会收到此错误。
一种方法是使内容可选并使用另一个文本变量并基于 nil 值显示视图。
public struct Snackbar<Content>: View where Content: View {
private var content: Content? // <= Here
private var text: String = "" // <= Here
// Works OK
public init(@ViewBuilder content: () -> Content) {
self.content = content()
}
init(_ text: String) {
self.text = text // <= Here
}
public var body: some View {
HStack {
VStack(alignment: .leading, spacing: 4) {
if let content = content { // <= Here
content
} else {
Text(text)
.font(.subheadline)
.foregroundColor(.white)
.multilineTextAlignment(.leading)
}
}
Spacer()
}
// Other code
您也可以使用AnyView
public struct Snackbar: View {
private var content: AnyView // Here
// Works OK
public init<Content: View>(@ViewBuilder content: () -> Content) {
self.content = AnyView(content()) // Here
}
init(_ text: String) {
self.content = AnyView(Text(text)
.font(.subheadline)
.foregroundColor(.white)
.multilineTextAlignment(.leading)
) // Here
}
public var body: some View {
HStack {
VStack(alignment: .leading, spacing: 4) {
self.content
}
Spacer()
}
可以指定Content
的类型。
代码:
public struct Snackbar<Content>: View where Content: View {
private var content: Content
// Works OK
public init(@ViewBuilder content: () -> Content) {
self.content = content()
}
init(_ text: String) where Content == ModifiedContent<Text, _EnvironmentKeyWritingModifier<TextAlignment>> {
self.init {
Text(text)
.font(.subheadline)
.foregroundColor(.white)
.multilineTextAlignment(.leading) as! ModifiedContent<Text, _EnvironmentKeyWritingModifier<TextAlignment>>
}
}
/* ... */
}
这里唯一的区别是 init
之后的 where
和 init
里面的类型的 force-cast。
为了避免特定的类型,你可以把它抽象成一个单独的视图:
init(_ text: String) where Content == ModifiedText {
self.init {
ModifiedText(text: text)
}
}
/* ... */
struct ModifiedText: View {
let text: String
var body: some View {
Text(text)
.font(.subheadline)
.foregroundColor(.white)
.multilineTextAlignment(.leading)
}
}
general-purpose 的解决方案是提供一个在语义上等同于 some View
的包装器。 AnyView
是内置的,可用于此目的。
init(_ text: String) where Content == AnyView {
self.init {
AnyView(
Text(text)
.font(.subheadline)
.foregroundColor(.white)
.multilineTextAlignment(.leading)
)
}
}
此外,将您的代码更改为
private let content: () -> Content
public init(@ViewBuilder content: @escaping () -> Content) {
self.content = content
}
这样您就不必将 content
的结果包装在另一个闭包中。
VStack(alignment: .leading, spacing: 4, content: content)