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 useUIViewRepresentableWrap UIView.
  • UIViewRepresentableThere are two main methods to implement:
    • makeUIView: createView.
    • updateUIView: Set based on conditions and service logicViewIn 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), useCoordinatorCoordinate.
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 useUIViewControllerRepresentableWrap UIViewController.
  • UIViewControllerRepresentableThere are two main methods to implement:
    • makeUIViewController: createUIViewController.
    • updateUIViewController: Set based on conditions and service logicUIViewControllerIn 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