Ios UIKit中的可扩展SwiftUI视图垂直居中

Ios UIKit中的可扩展SwiftUI视图垂直居中,ios,uikit,swiftui,Ios,Uikit,Swiftui,我正在将一些新的SwiftUI视图集成到UIKit应用程序中,但遇到了一个问题。我已经研究了以下问题很长一段时间,但尚未找到原因和解决方案。在UIKit中集成视图时,会出现此问题。我试图创建一个简单的可点击视图,点击时垂直展开/折叠 这就是SwiftUI视图预览的样子(以及它应该如何工作): 以下是我在UIKit中实现SwiftUI视图时得到的结果: 看起来,即使我将UIHostingController视图的顶部约束到父视图,UIHostingController视图仍然垂直居中 如评

我正在将一些新的SwiftUI视图集成到UIKit应用程序中,但遇到了一个问题。我已经研究了以下问题很长一段时间,但尚未找到原因和解决方案。在UIKit中集成视图时,会出现此问题。我试图创建一个简单的可点击视图,点击时垂直展开/折叠

这就是SwiftUI视图预览的样子(以及它应该如何工作):

以下是我在UIKit中实现SwiftUI视图时得到的结果:

看起来,即使我将UIHostingController视图的顶部约束到父视图,UIHostingController视图仍然垂直居中

如评论中所述,我可以将HostController视图的底部约束到其父视图的底部,但这会使下面的内容变得不可理解

我要寻找的是HostController视图约束(特别是高度)与SwiftUI视图框架匹配的解决方案

SwiftUI视图的代码:

import SwiftUI

struct ColorView: View {
  @State var isCollapsed = true

  var body: some View {
    VStack {
      VStack(spacing: 5) {
        HStack {
          Spacer()
          Text("Title")
          Spacer()
        }
        .frame(height: 100)

        if !isCollapsed {
          HStack {
            Spacer()
            Text("description")
            Spacer()
          }
          .padding(40)
        }
      }
      .background(Color(isCollapsed ? UIColor.red : UIColor.blue))
      .onTapGesture {
        withAnimation {
          self.isCollapsed.toggle()
        }
      }

      Spacer()
    }
  }
}

struct ColorView_Previews: PreviewProvider {
  static var previews: some View {
    return ColorView()
  }
}
struct ViewControllerRepresentable: UIViewControllerRepresentable {
  typealias UIViewControllerType = ViewController

  func makeUIViewController(context: UIViewControllerRepresentableContext<ViewControllerRepresentable>) -> ViewControllerRepresentable.UIViewControllerType {
    return ViewController()
  }

  func updateUIViewController(_ uiViewController: ViewControllerRepresentable.UIViewControllerType, context: UIViewControllerRepresentableContext<ViewControllerRepresentable>) { }
}

class ViewController: UIViewController {
  override func viewDidLoad() {
    super.viewDidLoad()

    let colorView = ColorView()
    let colorController = UIHostingController(rootView: colorView)

    addChild(colorController)
    view.addSubview(colorController.view)
    colorController.didMove(toParent: self)

    colorController.view.translatesAutoresizingMaskIntoConstraints = false
    colorController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
    colorController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
    colorController.view.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
  }
}

struct ViewControllerRepresentable_Previews: PreviewProvider {
  static var previews: some View {
    Group {
      ViewControllerRepresentable()
    }
  }
}
以及上述SwiftUI视图的ViewController中的UIKit实现:

import SwiftUI

struct ColorView: View {
  @State var isCollapsed = true

  var body: some View {
    VStack {
      VStack(spacing: 5) {
        HStack {
          Spacer()
          Text("Title")
          Spacer()
        }
        .frame(height: 100)

        if !isCollapsed {
          HStack {
            Spacer()
            Text("description")
            Spacer()
          }
          .padding(40)
        }
      }
      .background(Color(isCollapsed ? UIColor.red : UIColor.blue))
      .onTapGesture {
        withAnimation {
          self.isCollapsed.toggle()
        }
      }

      Spacer()
    }
  }
}

struct ColorView_Previews: PreviewProvider {
  static var previews: some View {
    return ColorView()
  }
}
struct ViewControllerRepresentable: UIViewControllerRepresentable {
  typealias UIViewControllerType = ViewController

  func makeUIViewController(context: UIViewControllerRepresentableContext<ViewControllerRepresentable>) -> ViewControllerRepresentable.UIViewControllerType {
    return ViewController()
  }

  func updateUIViewController(_ uiViewController: ViewControllerRepresentable.UIViewControllerType, context: UIViewControllerRepresentableContext<ViewControllerRepresentable>) { }
}

class ViewController: UIViewController {
  override func viewDidLoad() {
    super.viewDidLoad()

    let colorView = ColorView()
    let colorController = UIHostingController(rootView: colorView)

    addChild(colorController)
    view.addSubview(colorController.view)
    colorController.didMove(toParent: self)

    colorController.view.translatesAutoresizingMaskIntoConstraints = false
    colorController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
    colorController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
    colorController.view.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
  }
}

struct ViewControllerRepresentable_Previews: PreviewProvider {
  static var previews: some View {
    Group {
      ViewControllerRepresentable()
    }
  }
}
struct ViewControllerRepresentable:UIViewControllerRepresentable{
typealias UIViewControllerType=ViewController
func makeUIViewController(上下文:UIViewControllerRepresentableContext)->ViewControllerRepresentable.UIViewControllerType{
返回ViewController()
}
func updateUIViewController(uUIViewController:ViewControllerRepresentable.UIViewControllerType,上下文:UIViewControllerRepresentableContext){}
}
类ViewController:UIViewController{
重写func viewDidLoad(){
super.viewDidLoad()
让colorView=colorView()
让colorController=UIHostingController(根视图:colorView)
addChild(颜色控制器)
view.addSubview(colorController.view)
colorController.didMove(toParent:self)
colorController.view.translatesAutoresizingMaskIntoConstraints=false
colorController.view.leadingAnchor.constraint(等式:view.leadingAnchor).isActive=true
colorController.view.trailingAnchor.constraint(equalTo:view.trailingAnchor).isActive=true
colorController.view.topAnchor.constraint(equalTo:view.topAnchor).isActive=true
}
}
结构ViewControllerRepresentable\u预览:PreviewProvider{
静态var预览:一些视图{
团体{
ViewControllerRepresentable()
}
}
}

非常感谢您的帮助。

以下是在iOS单视图游乐场(Xcode 11.2)中测试的代码快照。原始的
ColorView
没有更改,因此下面没有重复

UIKit UIViewController中集成的SwiftUI视图的行为与纯SwiftUI环境中的行为相同

import UIKit
import PlaygroundSupport
import SwiftUI

class MyViewController : UIViewController {
    override func loadView() {
        let view = UIView()
        view.backgroundColor = .white
        self.view = view
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        let child = UIHostingController(rootView: ColorView())
        addChild(child)
        self.view.addSubview(child.view)
        child.didMove(toParent: self)

        child.view.translatesAutoresizingMaskIntoConstraints = false
        child.view.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
        child.view.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
        child.view.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
        child.view.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
    }
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()

你好谢谢你尝试一下。您的方法(将hostcontroller视图的底部约束到父视图)的问题是父视图的内容不再可交互,因为另一个视图在它前面(即使hostcontroller视图不一定与父视图具有相同的高度)。这是不同的问题)