UIKit嵌套SwiftUI登录页面实练

在UIkit框架中嵌套部分swiftUI之UIViewController中添加SwiftUI视图
系统适配最低版本:iOS13

将swiftUI视图添加至UIViewController中

1.需要使用UIHostingController
2.计算出swiftUI视图的尺寸
3.如果有导航栏隐藏,注意处理
代码:

  @discardableResult
    func addSwiftUIView<Content: View>(_ rhs: Content) -> UIHostingController<Content> {
        let vc = UIHostingController(rootView: rhs)
        vc.view.backgroundColor = .clear
        vc.edgesForExtendedLayout = []
        self.addChild(vc)
        
        self.view.addSubview(vc.view)
       
//        vc.view.sizeToFit()
        
        printLog("之前计算出来的size = \(vc.view.frame.size)")
        /// 使用该方法 计算swiftUI部分的高度,便于在UIKit中进行布局
        let targetSize = CGSize(width: view.bounds.width, height: UIView.layoutFittingCompressedSize.height)
        let size = vc.sizeThatFits(in: targetSize)
        printLog("计算出来的size = \(size)")
        vc.view.frame.size = size
        
        vc.view.translatesAutoresizingMaskIntoConstraints = false
        self.navigationController?.setNavigationBarHidden(true, animated: false)
  
        vc.didMove(toParent: self)
        return vc
    }

登录页面其他登录方式部分的SwiftUI实现代码

1.同样需要注意如果导航栏隐藏需要进行处理
2.iOS13上,给Button设置图片时,注意渲染模式

struct AppLoginWayView: View {
    var wayAction: (AppLogiWayType) -> Void
    
    var ways: [AppLogiWayType] = [.password, .qq, .mobile]
    
    var body: some View {
        
        HStack(spacing: 30.baobao.less, content: {
            ForEach(ways) { way in
                Button {
                    wayAction(way)
                } label: {
                    VStack(spacing: 4, content: {
                        Image(way.image_name)
                            .resizable()
                            .renderingMode(.original)
                            .scaledToFit()
                            .frame(width: 46.baobao.less, height: 46.baobao.less, alignment: .center)
                        
                        Text(way.title)
                            .font(.custom(AppFontName.regular.rawValue, size: 12.baobao.less))
                            .foregroundColor(Color("text_main", bundle: nil))
                    }).padding(0)
                }
                .background(Color.clear)
                

            }
        })
        .padding(0)
        .edgesIgnoringSafeArea(.all)
        .navigationBarHidden(true)
        .onAppear(perform: {
            if let nav = UIApplication.shared.baobao.getCurrentVC()?.navigationController {
                 nav.isNavigationBarHidden = true
                 nav.navigationItem.hidesBackButton = true
                 nav.navigationBar.isHidden = true
             }
            
        })
    }
}

UIViewController与SwiftUI的状态记录与交互问题

1.ObservableObject 管理状态
2.Toggle使用
3.自定义ToggleStyle

class AgreementState: ObservableObject {
    @Published var isAgreed: Bool

    init(isAgreed: Bool) {
        self.isAgreed = isAgreed
    }
}

// ObservableObject 管理状态
    private var agreementState = AgreementState(isAgreed: App.Config.shared.is_agree_login_protocol)


    private lazy var agreementView = LoginAgreementView(state: agreementState, clickAction: {[weak self] agreement in
        self?.didAgreementClicked(agreement)
    }, onToggle: { [weak self] isOn in
        guard let self = self else { return }

        self.agreementState.isAgreed = isOn
        App.Config.shared.is_agree_login_protocol = isOn
        baobaoLog(".isAgree = \(self.agreementState.isAgreed), app.agree = \(App.Config.shared.is_agree_login_protocol)")

    })
struct LoginAgreementView: View {
    @ObservedObject var state: AgreementState
//    @Binding var isAgreed: Bool
    var protocls: [ProtocolModel] = [ProtocolConfig.shared.user, ProtocolConfig.shared.privacy]
    var clickAction: (ProtocolModel) -> Void

    var onToggle: (Bool) -> Void

    var body: some View {
        HStack(spacing: 8.less, content: {

            Toggle(isOn: $state.isAgreed, label: {
                HStack(spacing: 0, content: {
                    Text("我已阅读并同意")
                        .font(.custom(getFontName(style: .regular), size: 12.less))
                        .foregroundColor(Color("text"))
                    ForEach(protocls, id: \.url) { agreement in
                        AgreementTextView(text: agreement.title, action: {
                            clickAction(agreement)
                        })
                    }

                })
            })
            .toggleStyle(CheckBoxToggleStyle(onToggle: onToggle))

        })
        .padding(0)
        .fixedSize()
        .edgesIgnoringSafeArea(.all)
        .navigationBarHidden(true)
        .onAppear(perform: {
            if let nav = UIApplication.topViewController()?.navigationController {
                nav.isNavigationBarHidden = true
                nav.setNavigationBarHidden(true, animated: false)
            }
        })
    }
}




//#Preview {
//    LoginAgreementView()
//}


struct AgreementTextView: View {
    let text: String
    let action: () -> Void

    var body: some View {
        Text(text)
            .foregroundColor(Color("agreement"))
            .font(.custom(getFontName(style: .regular), size: 12.less))
            .onTapGesture {
                action()
            }
    }
}


struct CheckBoxToggleStyle: ToggleStyle {
    let onToggle: (Bool) -> Void

    func makeBody(configuration: Configuration) -> some View {
        Button(action: {
            configuration.isOn.toggle()
            print("是否绑定 \(configuration.isOn)")
            onToggle(configuration.isOn)
        }) {
            HStack {
                Image(configuration.isOn ? .selectedBlack : .selectUnIcon)
                    .renderingMode(.original)
                configuration.label
            }
        }
        .buttonStyle(.plain)
        .padding(0)
        .background(Color.clear)

    }
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容