美文网首页SwiftUI
SwiftUI-混合开发

SwiftUI-混合开发

作者: YungFan | 来源:发表于2020-03-05 14:41 被阅读0次

    在目前阶段,SwiftUI 很难独立开发一款功能强大的 App,还是需要与 UIKit 一起合作,借助 UIKit 成熟完善的知识体系,二者相互嵌套形成混合开发。

    UIKit in SwiftUI

    UIKit SwiftUI
    UIView UIViewRepresentable
    UIViewController UIViewControllerRepresentable

    UIViewRepresentable

    • 要使 UIView 在 SwiftUI 中可用,需要用UIViewRepresentable对 UIView 进行包装。
    • UIViewRepresentable中主要有两个方法需要实现:
      • makeUIView:创建View
      • updateUIView:根据条件和业务逻辑设置View的状态。
    • 案例一
    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)
        }
    }
    
    • 案例二
    import UIKit
    import SwiftUI
    import MapKit
    
    struct Map: UIViewRepresentable {
        
        var locationManager:CLLocationManager = CLLocationManager()
        
        func setupManager(){
            
            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()
        }
    }
    
    • 案例三
    // 定义一个类负责实现代理
    class TextFieldDelegate: NSObject, UITextFieldDelegate {
            
        func textFieldDidBeginEditing(_ textField: UITextField) {
            print("开始编辑")
        }
    }
    
    // 定义UIViewRepresentable
    struct MyTextField: UIViewRepresentable {
        
        var text: String
        var placeholder: String  
        private let delegate = TextFieldDelegate()
        
        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使用
    struct ContentView : View {
        
        var body: some View {        
            MyTextField(text: "", placeholder: "请输入内容").frame(height: 40).padding()
        }
    }
    
    • 如果要桥接 UIKit 的数据绑定(Delegate,Target/Action),需要使用Coordinator进行协调。
    import SwiftUI
    import UIKit
    
    // 自定义个SegmentControl控件
    struct SegmentControl: UIViewRepresentable {
        
        @Binding var selectedSegmentIndex: Int
    
        // 下面两个方法都是和 UIKit 相关
        func makeUIView(context: Context) -> UISegmentedControl {
            
            let segmentControl = UISegmentedControl()
            segmentControl.insertSegment(withTitle: "红", at: 0, animated: true)
            segmentControl.insertSegment(withTitle: "黄", at: 1, animated: true)
            segmentControl.insertSegment(withTitle: "蓝", at: 2, animated: true)
            segmentControl.selectedSegmentIndex = selectedSegmentIndex
            
            // 注意这里的参数,与Coordinator有关
            segmentControl.addTarget(
                context.coordinator,
                action: #selector(Coordinator.updateCurrentPage(sender:)),
                for: .valueChanged)
    
            return segmentControl
        }
    
        func updateUIView(_ uiView: UISegmentedControl, context: Context) {
            uiView.selectedSegmentIndex = selectedSegmentIndex
        }
    
        // 协议的方法之一,返回一个协调器
        func makeCoordinator() -> Coordinator {
            Coordinator(self)
        }
    
        // 自定义协调器,UIKit与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)
        }
    }
    

    UIViewControllerRepresentable

    • 要使 UIViewController 在 SwiftUI 中可用,需要用UIViewControllerRepresentable对 UIViewController 进行包装。
    • UIViewControllerRepresentable中主要有两个方法需要实现:
      • makeUIViewController:创建UIViewController
      • updateUIViewController:根据条件和业务逻辑设置UIViewController的状态。
    • 案例
    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")
        }
    }
    

    SwiftUI in UIKit

    SwiftUI 中的 View 需要使用UIHostingController包装以后才可以给 UIKit 使用。

    UIHostingController

    开发 iOS 项目章节已经分析过启动流程,就是通过UIHostingController包装 ContentView,然后赋值给window.rootViewController

    // 可以是复杂的ContentView
    let vc = UIHostingController(rootView: ContentView())
    
    // 也可以时简单的Text等其他View
    let vc = UIHostingController(rootView: Text("Hello SwiftUI"))
    

    相关文章

      网友评论

        本文标题:SwiftUI-混合开发

        本文链接:https://www.haomeiwen.com/subject/hqgxrhtx.html