jcd*_*cdl 12 ios swift swiftui
我正在尝试创建一个自定义 SwiftUI 视图,它的作用类似于默认视图,我可以在其中使用方法或可选的初始值设定项参数向视图添加额外的内容。
SomeCustomView(title: "string argument") {
// some view
}
SomeCustomView(title: "hello") {
// some view
}.sideContent {
// another view
}
// This style is acceptable too
SomeCustomView(title: "hello", sideContent: { /* another view */ }) {
// some view
}
Run Code Online (Sandbox Code Playgroud)
如何修改此视图结构以使其行为类似于上述示例?
struct SomeCustomView<Content>: View where Content: View {
let title: String
let content: Content
init(title: String, @ViewBuilder content: () -> Content) {
self.title = title
self.content = content()
}
var body: some View {
VStack {
Text(title)
content
}
}
}
Run Code Online (Sandbox Code Playgroud)
理想情况下,我有两个不同的主体“模板”,我可以根据sideContent调用方法或sideContent设置参数在它们之间进行切换。例如,
var body: some View {
VStack {
Text(title)
content
}
}
// or
var otherBody: some View {
HStack {
VStack {
Text(title)
content
}
sideContent
}
}
Run Code Online (Sandbox Code Playgroud)
jcd*_*cdl 18
编辑为在 Xcode 11.6 中工作
经过一些思考和一些反复试验,我想通了。事后看来似乎有点明显。
struct SomeCustomView<Content>: View where Content: View {
let title: String
let content: Content
init(title: String, @ViewBuilder content: @escaping () -> Content) {
self.title = title
self.content = content()
}
func sideContent<SideContent: View>(@ViewBuilder side: @escaping () -> SideContent) -> some View {
HStack {
body // body is just a View, so we can compose with this View
side()
}
}
var body: some View {
VStack {
Text(title)
content
}
}
}
Run Code Online (Sandbox Code Playgroud)
它可以在有或没有方法调用的情况下工作。
SomeCustomView(title: "string argument") {
// some view
}
SomeCustomView(title: "hello") {
// some view
}.sideContent {
// another view
}
Run Code Online (Sandbox Code Playgroud)
我对容器视图遵循的模式是使用条件扩展一致性来支持不同变体的初始化程序。
这是一个带有可选页脚的简单面板视图的示例。
struct Panel<Content: View, Footer: View>: View {
let content: Content
let footer: Footer?
init(@ViewBuilder content: () -> Content, footer: (() -> Footer)? = nil) {
self.content = content()
self.footer = footer?()
}
var body: some View {
VStack(spacing: 0) {
content
// Conditionally check if footer has a value, if desirable.
footer
}
}
}
// Support optional footer
extension Panel where Footer == EmptyView {
init(@ViewBuilder content: () -> Content) {
self.content = content()
self.footer = nil
}
}
Run Code Online (Sandbox Code Playgroud)
我相信这类似于 Apple 为支持内置类型的所有变体所做的工作。例如,这是Button.
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
extension Button where Label == PrimitiveButtonStyleConfiguration.Label {
/// Creates an instance representing the configuration of a
/// `PrimitiveButtonStyle`.
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
public init(_ configuration: PrimitiveButtonStyleConfiguration)
}
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
extension Button where Label == Text {
/// Creates an instance with a `Text` label generated from a localized title
/// string.
///
/// - Parameters:
/// - titleKey: The key for the localized title of `self`, describing
/// its purpose.
/// - action: The action to perform when `self` is triggered.
public init(_ titleKey: LocalizedStringKey, action: @escaping () -> Void)
/// Creates an instance with a `Text` label generated from a title string.
///
/// - Parameters:
/// - title: The title of `self`, describing its purpose.
/// - action: The action to perform when `self` is triggered.
public init<S>(_ title: S, action: @escaping () -> Void) where S : StringProtocol
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6083 次 |
| 最近记录: |