Ria*_*ian 19 autolayout swift swiftui uihostingcontroller ios15
我正在尝试使用 UIHostingController 将 SwiftUI 视图添加到 UIKit 视图,并且它显示额外的间距(此示例是为了模拟生产应用程序上的问题而制作的)。这是屏幕截图。

布局概览:
View
UIStackView
UIImageView
UIView(red)
UIHostingController
UIView(blue)
Run Code Online (Sandbox Code Playgroud)
问题: 快速 UI 视图 (UIHostingController) 显示在红色和蓝色视图之间,它在分隔线之后显示额外的间距。间距根据 SwiftUI 视图的大小而变化。
如果我减少行数(Hello World 文本)或减少间距,它似乎工作正常。
这是完整的源代码(https://www.sendspace.com/file/ux0xt7):
ViewController.swift(主视图)
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var mainStackView: UIStackView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
addView()
}
private func addView() {
mainStackView.spacing = 0
mainStackView.alignment = .fill
let imageView = UIImageView()
imageView.image = UIImage(named: "mountain")
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
imageView.heightAnchor.constraint(equalToConstant: 260).isActive = true
mainStackView.addArrangedSubview(imageView)
let redView = UIView()
redView.backgroundColor = .red
redView.heightAnchor.constraint(equalToConstant: 100).isActive = true
mainStackView.addArrangedSubview(redView)
let sampleVC = SampleViewController()
//let size = sampleVC.view.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)
//sampleVC.view.heightAnchor.constraint(equalToConstant: size.height).isActive = true
mainStackView.addArrangedSubview(sampleVC.view)
let blueView = UIView()
blueView.backgroundColor = .blue
blueView.heightAnchor.constraint(equalToConstant: 100).isActive = true
mainStackView.addArrangedSubview(blueView)
}
}
Run Code Online (Sandbox Code Playgroud)
SampleView.swift
import SwiftUI
struct SampleView: View {
var body: some View {
VStack(spacing: 0) {
Text("Title")
VStack (alignment: .leading, spacing: 30) {
Text("Hello World1")
Text("Hello World2")
Text("Hello World3")
Text("Hello World4")
Text("Hello World5")
Text("Hello World6")
Text("Hello World7")
Text("Hello World8")
Text("Hello World9")
Text("Hello World10")
}
Divider()
}
}
}
struct SampleView_Previews: PreviewProvider {
static var previews: some View {
Group {
SampleView()
}
}
}
Run Code Online (Sandbox Code Playgroud)
SampleViewController.swift
import UIKit
import SwiftUI
class SampleViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
addView()
}
private func addView() {
let hostingController = UIHostingController(rootView: SampleView())
hostingController.view.backgroundColor = .clear
hostingController.view.translatesAutoresizingMaskIntoConstraints = false
addChild(hostingController)
view.addSubview(hostingController.view)
hostingController.didMove(toParent: self)
NSLayoutConstraint.activate([
hostingController.view.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
hostingController.view.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
hostingController.view.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 0),
hostingController.view.bottomAnchor.constraint(equalTo: self.view.bottomAnchor)
])
}
}
Run Code Online (Sandbox Code Playgroud)
提前致谢!
Ale*_*lex 21
我遇到了类似的问题,就像 @Asperi提到的那样,由于将额外的安全区域插入应用于 SwiftUI 视图。
edgesIgnoringSafeArea()遗憾的是,仅仅添加到 SwiftUI 视图是行不通的。
相反,您可以使用以下UIHostingController扩展来修复此问题:
extension UIHostingController {
convenience public init(rootView: Content, ignoreSafeArea: Bool) {
self.init(rootView: rootView)
if ignoreSafeArea {
disableSafeArea()
}
}
func disableSafeArea() {
guard let viewClass = object_getClass(view) else { return }
let viewSubclassName = String(cString: class_getName(viewClass)).appending("_IgnoreSafeArea")
if let viewSubclass = NSClassFromString(viewSubclassName) {
object_setClass(view, viewSubclass)
}
else {
guard let viewClassNameUtf8 = (viewSubclassName as NSString).utf8String else { return }
guard let viewSubclass = objc_allocateClassPair(viewClass, viewClassNameUtf8, 0) else { return }
if let method = class_getInstanceMethod(UIView.self, #selector(getter: UIView.safeAreaInsets)) {
let safeAreaInsets: @convention(block) (AnyObject) -> UIEdgeInsets = { _ in
return .zero
}
class_addMethod(viewSubclass, #selector(getter: UIView.safeAreaInsets), imp_implementationWithBlock(safeAreaInsets), method_getTypeEncoding(method))
}
objc_registerClassPair(viewSubclass)
object_setClass(view, viewSubclass)
}
}
}
Run Code Online (Sandbox Code Playgroud)
并像这样使用它:
let hostingController = UIHostingController(rootView: SampleView(), ignoreSafeArea: true)
Run Code Online (Sandbox Code Playgroud)
解决方案来源:https://defagos.github.io/swiftui_collection_part3/#fixing-cell-frames
Hen*_*rix 10
虽然亚历山大的解决方案:/sf/answers/4923759711/对我有用。在运行时调整/更改内容总是让我在生产环境中感到有点紧张。
因此,我采用了 UIHostingController 子类的方法,当底部安全区域插入更改时,我可以使用 extraSafeAreaInsets 来“添加”当前底部 SafeArea Inset 的负数。通过检查仅在以下情况下执行此操作safeAreaInsets.bottom > 0。
class OverrideSafeAreaBottomInsetHostingController<ContentView: SwiftUI.View>: UIHostingController<ContentView> {
override func viewSafeAreaInsetsDidChange() {
super.viewSafeAreaInsetsDidChange()
if view.safeAreaInsets.bottom > 0 {
additionalSafeAreaInsets = .init(top: 0, left: 0, bottom: -view.safeAreaInsets.bottom, right: 0)
}
}
}
Run Code Online (Sandbox Code Playgroud)
use*_*ser -2
相反,UIView(red)您可以简单地使用Color.red相同的UIView(blue):
struct SampleView: View {
var body: some View {
VStack(spacing: .zero) {
Color.red
Text("Title")
VStack (alignment: .leading, spacing: 30) {
Text("Hello World1")
Text("Hello World2")
Text("Hello World3")
Text("Hello World4")
Text("Hello World5")
Text("Hello World6")
Text("Hello World7")
Text("Hello World8")
Text("Hello World9")
Text("Hello World10")
}
Divider()
Color.blue.opacity(0.1)
}
}
}
Run Code Online (Sandbox Code Playgroud)
结果:
| 归档时间: |
|
| 查看次数: |
6566 次 |
| 最近记录: |