提问人:Tristian 提问时间:11/23/2019 最后编辑:Tristian 更新时间:11/23/2019 访问量:305
如何在不中断响应器链的情况下将 UIViewController 的视图嵌入到另一个视图中
How to embed a UIViewController's view into another view without breaking responder chain
问:
我正在尝试为视图控制器实现一个基类,该基类将添加一个顶部横幅,该横幅根据特定状态显示和隐藏。因为我扩展了这个基类,所以在我必须将原始属性嵌入到以编程方式创建的新属性中时,该属性已经加载。UIViewController
view
view
view
嵌入工作正常(UI 方面),视图会适当地自行调整,但是我看到的问题是,在嵌入它之后,嵌入的视图不再响应触摸事件,在我最初嵌入的控制器中,我有一个包含 16 行和一个按钮的表视图,在嵌入它之前,它们都正确响应点击和滚动事件。
我只能在IB中使用分屏视图控制器来实现双视图分屏。
这是我目前的实现,似乎无法弄清楚我错过了什么来传播事件,我尝试使用自定义视图,该视图覆盖了两者和变量都无济于事。hitTest()
newRootView
contentView
非常感谢任何帮助或见解,谢谢!
class BaseViewController: UIViewController {
var isInOfflineMode: Bool {
didSet { if isInOfflineMode { embedControllerView() }}
}
var offlineBanner: UIView!
var contentView: UIView!
private func embedControllerView() {
guard let currentRoot = viewIfLoaded else { return }
currentRoot.translatesAutoresizingMaskIntoConstraints = false
let newRootView = UIView(frame: UIScreen.main.bounds)
newRootView.backgroundColor = .yellow // debugging
newRootView.isUserInteractionEnabled = true
newRootView.clipsToBounds = true
view = newRootView
offlineBanner = createOfflineBanner() // returns a button that I've verified to be tapable.
view.addSubview(offlineBanner)
contentView = UIView(frame: .zero)
contentView.backgroundColor = .cyan // debugging
contentView.translatesAutoresizingMaskIntoConstraints = false
contentView.isUserInteractionEnabled = true
view.addSubview(contentView)
contentView.addSubview(currentRoot)
let bannerHeight: CGFloat = 40.00
var topAnchor: NSLayoutYAxisAnchor
var bottomAnchor: NSLayoutYAxisAnchor
var trailingAnchor: NSLayoutXAxisAnchor
var leadingAnchor: NSLayoutXAxisAnchor
if #available(iOS 11.0, *) {
topAnchor = view.safeAreaLayoutGuide.topAnchor
bottomAnchor = view.safeAreaLayoutGuide.bottomAnchor
leadingAnchor = view.safeAreaLayoutGuide.leadingAnchor
trailingAnchor = view.safeAreaLayoutGuide.trailingAnchor
} else {
topAnchor = view.topAnchor
bottomAnchor = view.bottomAnchor
leadingAnchor = view.leadingAnchor
trailingAnchor = view.trailingAnchor
}
NSLayoutConstraint.activate([
offlineBanner.heightAnchor.constraint(equalToConstant: bannerHeight),
offlineBanner.topAnchor.constraint(equalTo: topAnchor),
offlineBanner.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 0),
offlineBanner.trailingAnchor.constraint(equalTo: trailingAnchor, constant: 0),
])
NSLayoutConstraint.activate([
contentView.topAnchor.constraint(equalTo: topAnchor, constant: bannerHeight),
contentView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: 0),
contentView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 0),
contentView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: 0),
])
OfflineViewController.migrateViewContraints(from: currentRoot, to: contentView)
view.setNeedsUpdateConstraints()
offlineBanner.setNeedsUpdateConstraints()
currentRoot.setNeedsUpdateConstraints()
}
private func unembedControllerView() {
let v = contentView.subviews[0]
v.removeFromSuperview()
view = v
OfflineViewController.migrateViewContraints(from: contentView, to: v)
}
/**
Replaces any constraints associated with the current root's safe area`UILayoutGuide` or with the actual
current root view.
*/
private static func migrateViewContraints(from currentRoot: UIView, to newRoot: UIView) {
for ct in currentRoot.constraints {
var firstItem: Any? = ct.firstItem
var secondItem: Any? = ct.secondItem
if #available(iOS 11.0, *) {
if firstItem as? UILayoutGuide == currentRoot.safeAreaLayoutGuide {
debugPrint("Migrating firstItem is currentLayoutGuide")
firstItem = newRoot.safeAreaLayoutGuide
}
if secondItem as? UILayoutGuide == currentRoot.safeAreaLayoutGuide {
debugPrint("Migrating secondItem is currentLayoutGuide")
secondItem = newRoot.safeAreaLayoutGuide
}
}
if firstItem as? UIView == currentRoot {
debugPrint("Migrating firstItem is currentRoot")
firstItem = newRoot
}
if secondItem as? UIView == currentRoot {
debugPrint("Migrating secondItem is currentRoot")
secondItem = newRoot
}
NSLayoutConstraint.deactivate([ct])
NSLayoutConstraint.activate([
NSLayoutConstraint(item: firstItem as Any,
attribute: ct.firstAttribute,
relatedBy: ct.relation,
toItem: secondItem,
attribute: ct.secondAttribute,
multiplier: ct.multiplier,
constant: ct.constant)
])
}
}
}
在这个特定视图中,绿色按钮确实会获取事件,这是我以编程方式创建的按钮:
下面是一个不响应事件的视图,一个带有按钮的表视图:
答:
0赞
Tristian
11/23/2019
#1
我已经弄清楚问题出在哪里了;我缺少(新的根视图)和原始视图之间的限制。这些约束实质上使原始视图占据了以下全部空间:contentView
self.view
currentRoot
contentView
NSLayoutConstraint.activate([
currentRoot.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 0),
currentRoot.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: 0),
currentRoot.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 0),
currentRoot.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: 0),
])
评论
userInteraction