标签: viewbuilder

如何在 SwiftUI 视图中执行非视图代码

我一次又一次地为此苦苦挣扎,所以我想我错过了一些东西。我需要做数学、进行设置、分配值或任何一系列简单操作来响应某些用户操作,例如此处显示的示例,而 SwiftUI 需要一个视图,而我不需要视图。必须有一种方法可以绕过 ViewBuilder 的规则。我通过创建一个不必要的视图并在视图的 init() 内执行我需要的代码来解决这个问题,但这看起来非常尴尬。

import SwiftUI

struct ContentView: View
{
    @State var showStuff = false

    var body: some View
    {
        VStack
        {
            Toggle(isOn: $showStuff)
            {
                Text("Label")
            }
            if showStuff
            {
                UserDefaults.standard.set(true, forKey: "Something")
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

swiftui viewbuilder

11
推荐指数
2
解决办法
5750
查看次数

有什么方法可以在 SwiftUI 中使用 @ViewBuilder 创建/提取视图数组

我正在尝试创建一个简单的struct,它接受一组视图并返回一个VStack包含这些视图的普通视图,除了它们都是对角堆叠的。

代码:

struct LeaningTower<Content: View>: View {
    var views: [Content]
    var body: some View {
        VStack {
            ForEach(0..<views.count) { index in
                self.views[index]
                    .offset(x: CGFloat(index * 30))
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在这很好用,但每当我不得不调用它时,我总是很生气:

LeaningTower(views: [Text("Something 1"), Text("Something 2"), Text("Something 3")])
Run Code Online (Sandbox Code Playgroud)

在这样的数组中列出视图对我来说似乎非常奇怪,所以我想知道是否有一种方法可以像这样@ViewBuilder调用我的LeaningTower结构:

LeaningTower {  // Same way how you would create a regular VStack
    Text("Something 1")
    Text("Something 2")
    Text("Something 3")
    // And then have all of these Text's in my 'views' array
}
Run Code Online (Sandbox Code Playgroud)

如果有一种方法可以@ViewBuilder …

arrays ios swift swiftui viewbuilder

7
推荐指数
3
解决办法
1432
查看次数

如何在 SwiftUI 中循环视图构建器内容子视图

所以我试图创建一个视图,它接受 viewBuilder 内容,循环内容的视图并在每个视图和另一个视图之间添加分隔符

struct BoxWithDividerView<Content: View>: View {
    let content: () -> Content
    init(@ViewBuilder content: @escaping () -> Content) {
        self.content = content
    }
    var body: some View {
        VStack(alignment: .center, spacing: 0) {
            // here
            
        }
        .background(Color.black)
        .cornerRadius(14)
    }
}
Run Code Online (Sandbox Code Playgroud)

所以在我写“here”的地方,如果有意义的话,我想遍历内容的视图。我将编写一个不起作用的代码,但它解释了我想要实现的目标:

ForEach(content.subviews) { view  in
     view
     Divider()
}
Run Code Online (Sandbox Code Playgroud)

怎么做?

custom-view swiftui viewbuilder

6
推荐指数
2
解决办法
778
查看次数

SwiftUI,在 @Viewbuilder 中将视图作为参数传递

我的好奇心促使我将View类型作为参数传递给@ViewBuilder. 将模型/基元类型作为参数传递@ViewBuilder是完全有效的。

如下代码所示。

struct TestView<Content: View>: View {
    
    let content: (String) -> Content
    
    init(@ViewBuilder content: @escaping (String) -> Content) {
        self.content = content
    }
    
    var body: some View {
        content("Some text")
    }
}

struct ContentTestView: View {
    
    var body: some View {
        TestView {
            Text("\($0)")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

代替String

let content: (String) -> Content
Run Code Online (Sandbox Code Playgroud)

如果我尝试传递 SwiftUIView类型,则编译器对此不满意。

let content: (View) -> Content
Run Code Online (Sandbox Code Playgroud)

尽管 params for@ViewBuilder接受自定义协议类型Searchable,但不接受View协议。 …

struct ios swift-protocols swiftui viewbuilder

6
推荐指数
1
解决办法
4672
查看次数

在 SwiftUI 中使用 @ViewBuilder 单独修改传递到容器的子视图

在 SwiftUI 中,您可以将多个视图作为一个参数传递给另一个视图,这要归功于@ViewBuilder. 每个子视图都是单独处理的,因此在传递后,可以包含在 等中VStackHStack

我的问题是:这个容器视图是否可以单独修改传递给它的每个子视图?例如,通过Spacer在每个子视图之间添加一个。

这是我正在寻找的等效功能:

struct SomeContainerView<Content: View> {
    
    init(@ViewBuilder content: @escaping () -> Content) {
        self.content = content()
    }
    
    let content: Content
    
    var body: some View {
        HStack {
            ForEach(content.childViews, id: \.id) { child in
                // Give each child view a background
                // Add a Spacer in between each child view
                // Conditional formatting
                // Etc.
            }
        }
    }
    
}
Run Code Online (Sandbox Code Playgroud)

我相信这是可能的,因为标准 SwiftUI 容器视图可以影响传递给它们的子视图的外观和布局。除非这是通过 SwiftUI 的内部功能实现的?

解决这个问题的一种方法可能是传递多个视图参数而不是一个,尽管如果需要传递许多视图,这会不灵活且混乱。视图数组似乎也没有意义,因为我在 SwiftUI 中的任何地方都没有注意到这种模式。

ios swift swiftui viewbuilder

6
推荐指数
1
解决办法
1102
查看次数

SwiftUI View:两个不同的初始值设定项:无法将“Text”类型的值转换为闭包结果类型“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), …
Run Code Online (Sandbox Code Playgroud)

initializer ios swift swiftui viewbuilder

6
推荐指数
2
解决办法
5406
查看次数

包含控制流语句的闭包不能与结果生成器“CommandsBuilder”一起使用

我制作了一个按钮样式来在我的应用程序中创建圆形同形按钮,如下所示:

struct NeumorphicCircleButtonStyle: ButtonStyle {
    var startPoint: UnitPoint
    var endPoint: UnitPoint
    var padding: CGFloat?
    var bgColor: Color?
    var bgColorOffset: Color?
    
    func makeBody(configuration: Configuration) -> some View {
        
        configuration.label
            .padding(padding ?? 30)
            .contentShape(Circle())
            .background(
                Group{
                    if configuration.isPressed {
                        Circle()
                            .fill(bgColor ?? Color.backgroundColor)
                            .overlay(
                                Circle()
                                    .stroke(Color.black.opacity(0.7), lineWidth: 4)
                                    .blur(radius: 4)
                                    .offset(x: 2, y: 2)
                                    .mask(Circle().fill(LinearGradient(colors: [Color.black, Color.clear], startPoint: startPoint, endPoint: endPoint)))
                            )
                            .overlay(
                                Circle()
                                    .stroke(bgColorOffset ?? Color.backgroundColorOffset, lineWidth: 8)
                                    .blur(radius: 4)
                                    .offset(x: -2, y: -2)
                                    .mask(Circle().fill(LinearGradient(colors: [Color.clear, Color.black], startPoint: startPoint, endPoint: endPoint))) …
Run Code Online (Sandbox Code Playgroud)

xcode ios swift swiftui viewbuilder

5
推荐指数
1
解决办法
7882
查看次数

如何使 SwiftUI ViewBuilder 只接受特定协议的视图作为输入块?

我正在尝试使用 SwiftUI@ViewBuilder来允许我的包的用户动态指定视图的正文内容。但是,我试图将可用作输入的可能视图限制为我实现的几个默认视图(出于简化目的)。

这是一个例子:

public protocol PopupBodyView: View { } // every one of my default views conforms to this protocol

func generateChildView(@ViewBuilder items: () -> PopupBodyView)
-> some PopupBodyView {
    return menuItems()
}
Run Code Online (Sandbox Code Playgroud)

如果我现在调用generateChildView,我可以正确指定协议类型的一种PopupBodyView视图- 但是,如果我在结果生成器主体中指定多个视图,则会收到以下错误:

Instance method 'contextMenu(items:)' requires that 'TupleView<(Text, Text)>' conform to 'PopupBodyView'

extension Text: PopupBodyView { } // add protocol conformance

contextMenu {
    Text("Test")
    Text("Test") // Instance method 'contextMenu(items:)' requires that 'TupleView<(Text, Text)>' conform to 'PopupBodyView'
}
Run Code Online (Sandbox Code Playgroud)

我现在如何调整默认值@ViewBuilder以仅接受符合我的自定义 …

generics swift swift-protocols swiftui viewbuilder

5
推荐指数
0
解决办法
350
查看次数

SwiftUI 自定义视图的 ViewBuilder 不会在子类 ObservedObject 更新上重新渲染/更新

我已经研究了几天,搜索了 Swift 和 SwiftUI 文档、SO、论坛等,但似乎找不到答案。

这是问题所在;

我有一个 SwiftUI 自定义视图,它对远程资源的自定义 API 请求类进行一些状态确定。View 处理显示加载状态和失败状态,以及它的主体内容通过 ViewBuilder 传递,这样如果来自 API 的状态成功并且资源数据被加载,它将显示页面的内容。

问题是,当子类 ObservedObject 更新时,ViewBuilder 内容不会重新渲染。对象更新以响应 UI(当按下按钮时等),但 UI 永远不会重新渲染/更新以反映子类 ObservedObject 内的更改,例如,子类 ObservedObject 中数组后面的 ForEach 在以下情况下不会刷新数组内容改变。如果我将它移出自定义视图,ForEach 将按预期工作。

我可以确认代码编译并运行。Observers 和debugPrint()'s 始终显示ApiObject正在正确更新状态,并且视图ApiState完全正确地反映了更改。它只是ContentViewBuilder 的。我假设是因为 ViewBuilder 只会被调用一次。

编辑:上面的段落应该是提示,ApiState更新正确,但是在将大量日志记录到应用程序之后,UI 没有监听子类 ObservedObject 的发布。属性在变化,状态也在变化,但 UI 并没有对其做出反应。另外,下一句被证明是错误的,我在 VStack 中再次测试,组件仍然没有重新渲染,这意味着我找错了地方!

如果是这种情况,VStack其他此类元素如何解决此问题?还是因为我ApiObjectView在状态更改时被重新渲染,导致子视图“重置”?尽管在这种情况下,我希望它能够接受新数据并按预期工作,但它永远不会重新渲染。

有问题的代码是在CustomDataList.swiftApiObjectView.swift下方。我已经发表评论指出正确的方向。

这是示例代码;

// ApiState.swift
// Stores the API state for where the request and data parse …
Run Code Online (Sandbox Code Playgroud)

ios swift swiftui observedobject viewbuilder

2
推荐指数
1
解决办法
3130
查看次数