| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent e7c91eb commit 0946fff
1 file changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,218 @@ | |||
| 1 | + This is from the Apple UIKit docs | ||
| 2 | + (https://developer.apple.com/documentation/uikit): | ||
| 3 | + | ||
| 4 | + "UIKit works seamlessly with the SwiftUI framework, so you can implement parts of | ||
| 5 | + your UIKit app in SwiftUI or mix interface elements between the two frameworks. | ||
| 6 | + For example, you can place UIKit views and view controllers inside SwiftUI | ||
| 7 | + views, and vice versa." | ||
| 8 | + | ||
| 9 | + Could you show me how to do this? | ||
| 10 | + | ||
| 11 | + --- | ||
| 12 | + | ||
| 13 | + Sure, I can help with that. You can use UIKit views in SwiftUI by conforming to | ||
| 14 | + the `UIViewRepresentable` protocol, and you can use SwiftUI views in UIKit by | ||
| 15 | + wrapping them in a `UIHostingController`. Here's an example of each. | ||
| 16 | + | ||
| 17 | + ## UIKit views in SwiftUI | ||
| 18 | + | ||
| 19 | + First, let's show how to use a UIKit view in a SwiftUI view. We'll use a | ||
| 20 | + `UISlider` as an example: | ||
| 21 | + | ||
| 22 | + ```swift | ||
| 23 | + import SwiftUI | ||
| 24 | + import UIKit | ||
| 25 | + | ||
| 26 | + struct UIKitSlider: UIViewRepresentable { | ||
| 27 | + @Binding var value: Float | ||
| 28 | + | ||
| 29 | + func makeUIView(context: Context) -> UISlider { | ||
| 30 | + let slider = UISlider(frame: .zero) | ||
| 31 | + slider.value = value | ||
| 32 | + slider.addTarget(context.coordinator, action: #selector(Coordinator.valueChanged(_:)), for: .valueChanged) | ||
| 33 | + return slider | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + func updateUIView(_ uiView: UISlider, context: Context) { | ||
| 37 | + uiView.value = value | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + func makeCoordinator() -> Coordinator { | ||
| 41 | + Coordinator(value: $value) | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + class Coordinator: NSObject { | ||
| 45 | + var value: Binding<Float> | ||
| 46 | + | ||
| 47 | + init(value: Binding<Float>) { | ||
| 48 | + self.value = value | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + @objc func valueChanged(_ sender: UISlider) { | ||
| 52 | + self.value.wrappedValue = sender.value | ||
| 53 | + } | ||
| 54 | + } | ||
| 55 | + } | ||
| 56 | + ``` | ||
| 57 | + | ||
| 58 | + You can then use `UIKitSlider` in your SwiftUI views like this: | ||
| 59 | + | ||
| 60 | + ```swift | ||
| 61 | + struct ContentView: View { | ||
| 62 | + @State private var sliderValue: Float = 0.5 | ||
| 63 | + | ||
| 64 | + var body: some View { | ||
| 65 | + VStack { | ||
| 66 | + Text("Slider Value: \(sliderValue)") | ||
| 67 | + UIKitSlider(value: $sliderValue) | ||
| 68 | + } | ||
| 69 | + } | ||
| 70 | + } | ||
| 71 | + ``` | ||
| 72 | + | ||
| 73 | + ## SwiftUI views in UIKit | ||
| 74 | + | ||
| 75 | + You can also embed SwiftUI views in your UIKit code by using a | ||
| 76 | + UIHostingController. Here's an example of how to do that: | ||
| 77 | + | ||
| 78 | + ```swift | ||
| 79 | + import SwiftUI | ||
| 80 | + import UIKit | ||
| 81 | + | ||
| 82 | + struct SwiftUIView: View { | ||
| 83 | + var body: some View { | ||
| 84 | + Text("Hello, SwiftUI!") | ||
| 85 | + .padding() | ||
| 86 | + .background(Color.green) | ||
| 87 | + .foregroundColor(.white) | ||
| 88 | + .cornerRadius(10) | ||
| 89 | + } | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | + class ViewController: UIViewController { | ||
| 93 | + override func viewDidLoad() { | ||
| 94 | + super.viewDidLoad() | ||
| 95 | + | ||
| 96 | + let hostingController = UIHostingController(rootView: SwiftUIView()) | ||
| 97 | + addChild(hostingController) | ||
| 98 | + hostingController.view.translatesAutoresizingMaskIntoConstraints = false | ||
| 99 | + view.addSubview(hostingController.view) | ||
| 100 | + | ||
| 101 | + NSLayoutConstraint.activate([ | ||
| 102 | + hostingController.view.centerXAnchor.constraint(equalTo: view.centerXAnchor), | ||
| 103 | + hostingController.view.centerYAnchor.constraint(equalTo: view.centerYAnchor), | ||
| 104 | + ]) | ||
| 105 | + } | ||
| 106 | + } | ||
| 107 | + ``` | ||
| 108 | + | ||
| 109 | + In this example, `SwiftUIView` is embedded in a `ViewController`. It will | ||
| 110 | + display a text "Hello, SwiftUI!" with a green background in the center of the | ||
| 111 | + screen. | ||
| 112 | + | ||
| 113 | + --- | ||
| 114 | + | ||
| 115 | + Could you show me how to place a UIViewController (instead of just a UIView) | ||
| 116 | + inside SwiftUI views? | ||
| 117 | + | ||
| 118 | + --- | ||
| 119 | + | ||
| 120 | + ## UIKit UIViewControllers in SwiftUI | ||
| 121 | + | ||
| 122 | + Yes, absolutely! In order to use a `UIViewController` in a SwiftUI view, you | ||
| 123 | + need to use the `UIViewControllerRepresentable` protocol. Here's an example of | ||
| 124 | + how to use a `UIImagePickerController` (which is a subclass of | ||
| 125 | + `UIViewController`) inside a SwiftUI view: | ||
| 126 | + | ||
| 127 | + ```swift | ||
| 128 | + import SwiftUI | ||
| 129 | + import UIKit | ||
| 130 | + | ||
| 131 | + struct ImagePicker: UIViewControllerRepresentable { | ||
| 132 | + @Binding var selectedImage: UIImage? | ||
| 133 | + @Environment(\.presentationMode) private var presentationMode | ||
| 134 | + | ||
| 135 | + class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate { | ||
| 136 | + var parent: ImagePicker | ||
| 137 | + | ||
| 138 | + init(_ parent: ImagePicker) { | ||
| 139 | + self.parent = parent | ||
| 140 | + } | ||
| 141 | + | ||
| 142 | + func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { | ||
| 143 | + if let uiImage = info[.originalImage] as? UIImage { | ||
| 144 | + parent.selectedImage = uiImage | ||
| 145 | + } | ||
| 146 | + | ||
| 147 | + parent.presentationMode.wrappedValue.dismiss() | ||
| 148 | + } | ||
| 149 | + } | ||
| 150 | + | ||
| 151 | + func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController { | ||
| 152 | + let picker = UIImagePickerController() | ||
| 153 | + picker.delegate = context.coordinator | ||
| 154 | + return picker | ||
| 155 | + } | ||
| 156 | + | ||
| 157 | + func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePicker>) { | ||
| 158 | + // update function implementation | ||
| 159 | + } | ||
| 160 | + | ||
| 161 | + func makeCoordinator() -> Coordinator { | ||
| 162 | + Coordinator(self) | ||
| 163 | + } | ||
| 164 | + } | ||
| 165 | + ``` | ||
| 166 | + | ||
| 167 | + You can then use `ImagePicker` in your SwiftUI views like this: | ||
| 168 | + | ||
| 169 | + ```swift | ||
| 170 | + struct ContentView: View { | ||
| 171 | + @State private var isShowingImagePicker = false | ||
| 172 | + @State private var selectedImage: UIImage? | ||
| 173 | + | ||
| 174 | + var body: some View { | ||
| 175 | + VStack { | ||
| 176 | + Button(action: { | ||
| 177 | + isShowingImagePicker = true | ||
| 178 | + }) { | ||
| 179 | + Text("Open Image Picker") | ||
| 180 | + } | ||
| 181 | + | ||
| 182 | + selectedImage.map { Image(uiImage: $0).resizable().scaledToFit() } | ||
| 183 | + } | ||
| 184 | + .sheet(isPresented: $isShowingImagePicker) { | ||
| 185 | + ImagePicker(selectedImage: $selectedImage) | ||
| 186 | + } | ||
| 187 | + } | ||
| 188 | + } | ||
| 189 | + ``` | ||
| 190 | + | ||
| 191 | + In this example, when you press the "Open Image Picker" button, it opens up an | ||
| 192 | + image picker. Once an image is selected, it is displayed on the screen. | ||
| 193 | + | ||
| 194 | + --- | ||
| 195 | + | ||
| 196 | + Does SwiftUI render to UIKit on mobile and AppKit on desktop? | ||
| 197 | + | ||
| 198 | + --- | ||
| 199 | + | ||
| 200 | + In essence, yes. SwiftUI operates at a higher level of abstraction than UIKit or | ||
| 201 | + AppKit. When you define interfaces in SwiftUI, you describe them in a | ||
| 202 | + platform-agnostic way, but when those interfaces are rendered on a particular | ||
| 203 | + platform, SwiftUI uses the native rendering engine of that platform. | ||
| 204 | + | ||
| 205 | + On iOS and iPadOS, SwiftUI uses UIKit (more specifically, underlying | ||
| 206 | + technologies like Core Animation and Core Graphics) for rendering. On macOS, | ||
| 207 | + SwiftUI uses AppKit. Similarly, on watchOS, it uses WatchKit, and on tvOS, it | ||
| 208 | + uses TVUIKit. | ||
| 209 | + | ||
| 210 | + However, it's important to note that SwiftUI doesn't directly convert your | ||
| 211 | + SwiftUI views into UIKit or AppKit components. Instead, SwiftUI works directly | ||
| 212 | + with the underlying rendering and layout engines to create UIs that match the | ||
| 213 | + capabilities and conventions of each platform. | ||
| 214 | + | ||
| 215 | + This means, for instance, that a SwiftUI `Button` does not become a `UIButton` | ||
| 216 | + on iOS or a `NSButton` on macOS. It remains a SwiftUI `Button`, but it is drawn | ||
| 217 | + and behaves appropriately for the platform it's running on, thanks to the | ||
| 218 | + rendering done by SwiftUI using the native technologies. | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments