在一个位置更改图像时,如何在SwiftUI中反映其他位置的更改?

时间:2019-11-27 19:03:13

标签: swiftui

我有2个问题。

  1. 我有一个图像作为按钮,因此当您点击它时,可以从图像胶卷中选择一个图像。当我转到另一个视图然后回来时,图像消失了。在SwiftUI中更改视图时,如何防止其消失?
  2. 如何将其链接到应用程序中的其他UIImage,以便当您在一个位置更改图像时,它可以反映其他位置的更改?目前,最上面的图片已经过硬编码,但我希望它能反映出较小的图片所显示的内容。我在下面添加了一张图片,以显示我在说什么,或者您可以观看其中的视频here

Profile

这是我的代码:

import SwiftUI

struct ImagePicker: View {

    @State var isShowingImagePicker = false

    @State var imageInBlackCircle = UIImage()

    var body: some View {
        VStack {
            Button(action: {
                self.isShowingImagePicker.toggle()
            }) {
                Image(uiImage: imageInBlackCircle)
                    .renderingMode(.original)
                    .resizable()
                    .scaledToFill()
                    .clipShape(Circle())
                    .overlay(Circle() .stroke(Color.black, lineWidth: 1))
                    .shadow(color: .black, radius: 3, x: 0, y: 3)
                    .frame(width: 60.0, height: 70.0)
                    .padding(.trailing, 20)

                    .sheet(isPresented: $isShowingImagePicker, content: {
                        ImagePickerView(isPresented: self.$isShowingImagePicker, selectedImage: self.$imageInBlackCircle)
                    })
            }
        }
    }

    struct ImagePickerView: UIViewControllerRepresentable {

        @Binding var isPresented: Bool
        @Binding var selectedImage: UIImage

        func makeUIViewController(context:
            UIViewControllerRepresentableContext<ImagePickerView>) ->
            UIViewController {
                let controller = UIImagePickerController()
                controller.delegate = context.coordinator
                return controller
        }

        func makeCoordinator() -> ImagePickerView.Coordinator {
            return Coordinator(parent: self)
        }

        class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {

            let parent: ImagePickerView
            init(parent: ImagePickerView) {
                self.parent = parent
            }

            func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
                if let selectedImageFromPicker = info[.originalImage] as? UIImage {
                    print(selectedImageFromPicker)
                    self.parent.selectedImage = selectedImageFromPicker
                }

                self.parent.isPresented = false
            }
        }


        func updateUIViewController(_ uiViewController: ImagePickerView.UIViewControllerType, context: UIViewControllerRepresentableContext<ImagePickerView>) {

        }
    }

    struct ImagePicker_Previews: PreviewProvider {
        static var previews: some View {
            ImagePicker()
        }
    }
}

1 个答案:

答案 0 :(得分:0)

因此,您现在知道@State的用法。它们是特殊类型的属性,可以帮助SwiftUI视图重新加载,以防其值发生任何更改。这样可以确保同步。因此,如果您还需要将此属性链接到其他位置,则需要传递该属性,对吗?但根据设计:

  

@State非常适合属于特定视图且从不在该视图之外使用的简单属性,因此,将这些属性标记为私有很重要,以强化这种状态是专门为避免脱离其观点而设计的。


那我们有什么?注意:

  

对于更复杂的属性-当您要使用可能具有多个属性和方法的自定义类型时,或者可能在多个视图之间共享 –您应改用@ObservedObject

您可以从What’s the difference between @ObservedObject, @State, and @EnvironmentObject?

阅读更多内容

以上内容有意义吗?如果是,则需要此@ObservedObject。让我们看看我们如何实现这一目标。

您声明一个符合ObservableObject的对象。您用@Published包装器标记了这些属性,以便使所说的ObservableObject的任何实例都收到对该属性所做的更改的通知。

import Combine
import UIKit

class UserViewModel: ObservableObject {
    @Published var image = UIImage()
}

现在,您需要在某处此对象的实例,以便可以观察其状态。那就是您将使用@ObservedObject包装器的地方。

struct ImagePicker: View {
    @State private var isShowingImagePicker = false // make this private
    @State private var isShowingDetailView = false // make this private

    @ObservedObject var viewModel = UserViewModel() // either you initialize this here, 
                                                    // or inject this from somewhere else
}

然后,当您初始化其他视图以进行显示/演示时,只需绕过@ObservedObject属性。喜欢:

NavigationLink(destination: DetailView(userViewModel: viewModel), isActive: $isShowingDetailView) {
    Text("Detail")
}

您的DetailView类似于:

struct DetailView: View {
    var userViewModel: UserViewModel // you may need to declare this as @ObservedObject as well if you are required to manipulate state of UserViewModel from this view
    var body: some View {
        Image(uiImage: userViewModel.image)
            .navigationBarTitle(Text("Detail"), displayMode: .inline)
    }
}

对于您的简单情况,这应该足够了。但是,如果需要从视图层次结构中的任何位置访问有状态对象,则可能需要查看@EnvironmentObject