SwiftUI:强制更新

zzoitvuj  于 2022-12-02  发布在  Swift
关注(0)|答案(3)|浏览(185)

通常情况下,我们被限制在讨论苹果的预发布的东西,但我已经看到了大量的SwiftUI的讨论,所以我怀疑这是确定的;就这一次。
我是在驾驶到杂草的过程中对其中一个教程(我这样做)。
我在“与UIKit交互”教程中的可滑动屏幕下方添加了一对按钮:https://developer.apple.com/tutorials/swiftui/interfacing-with-uikit
这些是“下一个”和“上一个”按钮。当在一端或另一端时,相应的按钮隐藏。我有这个工作正常。
我遇到的问题是访问由PageViewController表示的UIPageViewController示例。
我更改了currentPage属性(通过使PageViewController成为UIPageViewController的委托),但我需要强制UIPageViewController以编程方式进行更改。
我知道我可以通过重绘PageView主体来“强制”显示,反映一个新的currentPage,但我不确定如何做到这一点。

struct PageView<Page: View>: View {
    var viewControllers: [UIHostingController<Page>]
    @State var currentPage = 0

    init(_ views: [Page]) {
        self.viewControllers = views.map { UIHostingController(rootView: $0) }
    }

    var body: some View {
        VStack {
            PageViewController(controllers: viewControllers, currentPage: $currentPage)

            HStack(alignment: .center) {
                Spacer()

                if 0 < currentPage {
                    Button(action: {
                        self.prevPage()
                    }) {
                        Text("Prev")
                    }

                    Spacer()
                }

                Text(verbatim: "Page \(currentPage)")

                if currentPage < viewControllers.count - 1 {
                    Spacer()

                    Button(action: {
                        self.nextPage()
                    }) {
                        Text("Next")
                    }
                }

                Spacer()
            }
        }
    }

    func nextPage() {
        if currentPage < viewControllers.count - 1 {
            currentPage += 1
        }
    }

    func prevPage() {
        if 0 < currentPage {
            currentPage -= 1
        }
    }
}

我知道答案应该是显而易见的,但我很难弄清楚如何以编程方式刷新VStack或主体。

yeotifhr

yeotifhr1#

2021 SWIFT 1和2均为:

重要的事情!如果你搜索这个黑客,可能你做错了什么!请,阅读这个块之前,你读黑客解决方案!!!!!!!!!!
您的UI未自动更新,因为您遗漏了一些重要内容。

  • ViewModel必须是 Package 到ObservableObject/ObservedObject中的class
  • ViewModel中的任何字段都必须是STRUCT。不是CLASS!!!Swift UI不支持类!
  • 必须正确使用修饰符(状态、可观察对象/observedObject、已发布、绑定等)
  • 如果您在视图模型中需要一个class属性(出于某种原因)-您需要将其标记为ObservableObject/Observed对象,并将它们分配到视图的对象中!!!!!!!!!Viewinit()内部。!!!!!!!
  • 有时需要使用黑客。但这是真的真的真的独家情况!**在大多数情况下这是错误的方式!**一次:请使用struct s代替类!

如果正确使用了上面所写的所有内容,您的UI将自动刷新。
正确用法示例:

struct SomeView : View {
    @ObservedObject var model : SomeViewModel
    @ObservedObject var someClassValue: MyClass
    
    init(model: SomeViewModel) {
        self.model = model
    
        //as this is class we must do it observable and assign into view manually
        self.someClassValue = model.someClassValue
    }

    var body: some View {
         //here we can use model.someStructValue directly

         // or we can use local someClassValue taken from VIEW, BUT NOT value from model

    }

}

class SomeViewModel : ObservableObject {
    @Published var someStructValue: Bool = false
    var someClassValue: MyClass = MyClass() //myClass : ObservableObject

}

以及主题问题的答案。

(黑客解决方案-首选不使用此)
方式1:在视图内部声明:

@State var updater: Bool = false

你需要更新的只是toogle():updater.toogle()
方式2:从ViewModel刷新
适用于SwiftUI 2

public class ViewModelSample : ObservableObject
    func updateView(){
        self.objectWillChange.send()
    }
}

方式3:从ViewModel刷新:
适用于SwiftUI 1

import Combine
import SwiftUI

class ViewModelSample: ObservableObject {
    private let objectWillChange = ObservableObjectPublisher()

    func updateView(){
        objectWillChange.send()
    }
}
u0njafvf

u0njafvf2#

这是另一个对我有用的解决方案,使用id()标识符。基本上,我们并没有真正刷新视图。我们用一个新的视图替换了这个视图。

import SwiftUI

struct ManualUpdatedTextField: View {
    @State var name: String
    
    var body: some View {
        VStack {
            TextField("", text: $name)
            Text("Hello, \(name)!")
        }
    }
}

struct MainView: View {
    
    @State private var name: String = "Tim"
    @State private var theId = 0

    var body: some View {
        
        VStack {
            Button {
                name += " Cook"
                theId += 1
            } label: {
                Text("update Text")
                    .padding()
                    .background(Color.blue)
            }
            
            ManualUpdatedTextField(name: name)
                .id(theId)
        }
    }
}
rjee0c15

rjee0c153#

设置currentPage,因为它是@State,将重新加载整个主体。

相关问题