Mixed development
At the current stage, SwiftUI is difficult to independently develop a powerful App. It still needs to cooperate with UIKit to form mixed development nested with UIKit’s mature and complete knowledge system.
UIKit in SwiftUI
UIKit | SwiftUI |
---|---|
UIView | UIViewRepresentable |
UIViewController | UIViewControllerRepresentable |
UIViewRepresentable
- To make UIView available in SwiftUI, you need to use
UIViewRepresentable
Wrap UIView. UIViewRepresentable
There are two main methods to implement:makeUIView
: createView
.updateUIView
: Set based on conditions and service logicView
In the state.
- Case a
import SwiftUI
import UIKit
struct ActivityIndicator: UIViewRepresentable {
var isAnimating: Bool
func makeUIView(context: Context) -> UIActivityIndicatorView {
let v = UIActivityIndicatorView()
v.color = .orange
return v
}
func updateUIView(_ uiView: UIActivityIndicatorView, context: Context) {
if isAnimating {
uiView.startAnimating()
} else {
uiView.stopAnimating()
}
}
}
struct ContentView : View {
var isAnimating: Bool = true
var body: some View {
ActivityIndicator(isAnimating: isAnimating)
}
}
Copy the code
- Case 2
import UIKit
import SwiftUI
import MapKit
struct Map: UIViewRepresentable {
var locationManager:CLLocationManager = CLLocationManager(a)func setupManager(a){
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
locationManager.requestAlwaysAuthorization()
}
func makeUIView(context: Context) -> MKMapView {
self.setupManager()
let map = MKMapView(frame: UIScreen.main.bounds)
map.showsUserLocation = true
map.userTrackingMode = .followWithHeading
return map
}
func updateUIView(_ uiView: MKMapView, context: Context){}}struct ContentView : View {
var body: some View {
Map()}}Copy the code
- Case 3
// Define a class that implements the proxy
class TextFieldDelegate: NSObject.UITextFieldDelegate {
func textFieldDidBeginEditing(_ textField: UITextField) {
print("Start editing")}}/ / define UIViewRepresentable
struct MyTextField: UIViewRepresentable {
var text: String
var placeholder: String
private let delegate = TextFieldDelegate(a)func makeUIView(context: UIViewRepresentableContext<MyTextField>) -> UITextField {
let tmpView = UITextField()
tmpView.text = text
tmpView.borderStyle = .roundedRect
tmpView.placeholder = placeholder
tmpView.delegate = delegate
return tmpView
}
func updateUIView(_ uiView: UITextField, context: UIViewRepresentableContext<MyTextField>){}}/ / SwiftUI use
struct ContentView : View {
var body: some View {
MyTextField(text: "", placeholder: "Please enter the content").frame(height: 40).padding()
}
}
Copy the code
- If you want to bridge UIKit’s data binding (Delegate, Target/Action), use
Coordinator
Coordinate.
import SwiftUI
import UIKit
// Define a SegmentControl
struct SegmentControl: UIViewRepresentable {@Binding var selectedSegmentIndex: Int
// The following two methods are UIKit related
func makeUIView(context: Context) -> UISegmentedControl {
let segmentControl = UISegmentedControl()
segmentControl.insertSegment(withTitle: "Red", at: 0, animated: true)
segmentControl.insertSegment(withTitle: "Yellow", at: 1, animated: true)
segmentControl.insertSegment(withTitle: "Blue", at: 2, animated: true)
segmentControl.selectedSegmentIndex = selectedSegmentIndex
// Note the parameter here, which is related to Coordinator
segmentControl.addTarget(
context.coordinator,
action: #selector(Coordinator.updateCurrentPage(sender:)),
for: .valueChanged)
return segmentControl
}
func updateUIView(_ uiView: UISegmentedControl, context: Context) {
uiView.selectedSegmentIndex = selectedSegmentIndex
}
// one of the methods of the protocol, returns a coordinator
func makeCoordinator(a) -> Coordinator {
Coordinator(self)}// Custom coordinator, where UIKit interacts with SwiftUI
class Coordinator: NSObject {
var control: SegmentControl
init(_ control: SegmentControl) {
self.control = control
}
@objc func updateCurrentPage(sender: UISegmentedControl) {
control.selectedSegmentIndex = sender.selectedSegmentIndex
}
}
}
struct ContentView : View {@State private var selectedSegmentIndex: Int = 1
var body: some View {
SegmentControl(selectedSegmentIndex: $selectedSegmentIndex)
}
}
Copy the code
UIViewControllerRepresentable
- To make UIViewController available in SwiftUI, you need to use
UIViewControllerRepresentable
Wrap UIViewController. UIViewControllerRepresentable
There are two main methods to implement:makeUIViewController
: createUIViewController
.updateUIViewController
: Set based on conditions and service logicUIViewController
In the state.
- case
import SwiftUI
import UIKit
struct NavigationViewController: UIViewControllerRepresentable {
var vc: UIViewController
var title: String
func makeUIViewController(context: Context) -> UINavigationController {
let nvc = UINavigationController(rootViewController: vc)
return nvc
}
func updateUIViewController(_ navigationController: UINavigationController, context: Context) {
navigationController.viewControllers[0].title = title
}
}
struct ContentView : View {
var body: some View {
NavigationViewController(vc: UIViewController(), title: "UIViewControllerRepresentable")}}Copy the code
SwiftUI in UIKit
The View in SwiftUI needs to be wrapped with UIHostingController before it can be used by UIKit.
UIHostingController
Chapter in the development of the iOS project has been analyzed to start the process, it is through the UIHostingController packaging ContentView, then assigned to the window. The rootViewController.
// It can be a complex ContentView
let vc = UIHostingController(rootView: ContentView())
Copy the code
// It can also be a simple Text or other View
let vc = UIHostingController(rootView: Text("Hello SwiftUI"))
Copy the code