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

时间:2020-07-25 15:46:21

标签: swiftui viewbuilder

我一直在为此苦苦挣扎,所以我想我缺少了一些东西。我需要进行数学运算,进行设置,分​​配值或许多简单操作来响应某些用户操作,例如此处显示的示例,而SwiftUI则需要一个不需要视图的View。必须有一种方法来绕过ViewBuilder的规则。我通过创建一个不必要的视图并在View的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")
            }
        }
    }
}

3 个答案:

答案 0 :(得分:0)

您无法做您想做的事情,因为实际上body内的每个视图块都是一个ViewBuidler.buildBlock函数参数。就是您在函数参数空间中。希望您不要期望像这样的表情

foo(Toggle(), if showStuff { ... } )

会工作(假设foofunc foo(args: View...)。但这就是您在body中尝试做的事情。

因此,SwiftUI中的表达式必须 ViewBuilder 块之外(ViewBuilder本身支持视图的某些例外情况)。

以下是您的解决方案:

SwiftUI 2.0

struct ContentView: View {
    @AppStorage("Something") var showStuff = false

    var body: some View {
        VStack {
            Toggle(isOn: $showStuff) {
                Text("Label")
            }
        }
    }
}

SwiftUI 1.0

查找已经解决的SwiftUI toggle switches

注意:View.body(不包括某些动作修饰符)等效于UIView.draw(_ rect:) ...您不将UserDefaults存储在draw(_ rect :)中,对吗?

答案 1 :(得分:0)

在SwiftUI 2.0中,有一个新的ViewModifier onChange(of:perform:),可让您对值的更改做出反应。

但是,您可以通过使用X1 <- gsub('<br/>', '\n', X) xTabs <- XML::readHTMLTable(X1) 方法扩展Binding来创建与之类似的巧妙技巧(我忘了看到它的地方,所以很遗憾我无法留下适当的归属):

onChange

您可以像这样使用它:

extension Binding {
   func onChange(perform action: @escaping (Value, Value) -> Void) -> Self {
      .init(
         get: { self.wrappedValue },
         set: { newValue in
            let oldValue = self.wrappedValue
            DispatchQueue.main.async { action(newValue, oldValue) }
            self.wrappedValue = newValue
         })
   }
}

答案 2 :(得分:0)

struct ExecuteCode : View {
    init( _ codeToExec: () -> () ) {
        codeToExec()
    }
    
    var body: some View {
        return EmptyView()
    }
}

用法:

HStack{
    SomeView1()

    Spacer()

    ExecuteCode { print("SomeView1 was re-drawn!") }
}
相关问题