Проблема с UITabBarController заключается в том, что его TabBar добавляется без использования NSLayoutConstraints (или, точнее, он переводит маску автоматического изменения размера в ограничения). По этой причине вы можете использовать два вида подхода:
1) Используйте UITabBarController так, как вы это делаете сейчас, но для его скрытия нужны некоторые хаки - в основном используйте UITabBarController внутри UINavigationController, чтобы получить sh представление поверх него (но переход будет виден, даже если вы сделаете sh без анимации (клавиатура начнет скрываться), или вы можете скрыть TabBar и изменить размер фрейма представления содержимого TabBar вручную, как показано на рисунке { ссылка }).
В этом последнем случае вы также должны запомнить кадр представления содержимого перед его изменением (или рассчитать его перед повторным отображением TabBar). Кроме того, поскольку это не является официальным API, вы должны принять во внимание, что порядок подпредставлений внутри UITabBarController может измениться, а эффекты могут выглядеть очень странно (или просто создать sh приложение)
2) use " обычный "UIViewController с UITabBar и его элементы, добавленные вручную с ограничениями. Это может быть также пользовательский подкласс UIView и несколько кнопок, созданных из XIB. Здесь вы создаете ограничения напрямую, поэтому у вас есть лучший контроль. Но этот также не будет go без некоторых хаков, потому что UITabBar, добавленный к одному UIViewController, идет вместе с этим UIViewController с каждым переходом (учитывая, что у вас есть UINavigationController в каждом UIViewController, это будет очень часто).
Так в этом случае основной проблемой является создание единой нижней панели и ее передача в UIWindow в viewDidAppear вида, где создается ваша единственная нижняя панель - рекомендуется из раскадровки или из файла xib. Для следующего просмотра вы только передадите ссылку на него или сохраните этот указатель в одном классе для этого. Не забудьте также создать представление, охватывающее безопасную область под панелью вкладок.
Это будет выглядеть так:
private var firstRun = false
override func viewDidLoad() {
super.viewDidLoad()
firstRun = true
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
guard firstRun else {
bottomBar.superview?.bringSubviewToFront(bottomBar)
bottomSafeAreaView.superview?.bringSubviewToFront(bottomSafeAreaView)
return
}
guard let window = UIApplication.shared.windows.first, let bottomB = bottomBar, let bottomSafeArea = bottomSafeAreaView else { return }
if bottomB.superview != window {
bottomB.deactivateConstrainsToSuperview()
bottomSafeArea.deactivateConstrainsToSuperview()
window.addSubview(bottomSafeArea)
window.addSubview(bottomB)
let bottomLeft = NSLayoutConstraint(item: bottomSafeArea, attribute: .leading, relatedBy: .equal, toItem: window, attribute: .leading, multiplier: 1, constant: 0)
let bottomRight = NSLayoutConstraint(item: bottomSafeArea, attribute: .trailing, relatedBy: .equal, toItem: window, attribute: .trailing, multiplier: 1, constant: 0)
let bottomBottom = NSLayoutConstraint(item: bottomSafeArea, attribute: .bottom, relatedBy: .equal, toItem: window, attribute: .bottom, multiplier: 1, constant: 0)
let leftConstraint = NSLayoutConstraint(item: bottomB, attribute: .leading, relatedBy: .equal, toItem: window, attribute: .leading, multiplier: 1, constant: 0)
let rightConstraint = NSLayoutConstraint(item: bottomB, attribute: .trailing, relatedBy: .equal, toItem: window, attribute: .trailing, multiplier: 1, constant: 0)
let bottomConstraint = NSLayoutConstraint(item: bottomB, attribute: .bottom, relatedBy: .equal, toItem: bottomSafeArea, attribute: .top, multiplier: 1, constant: 0)
NSLayoutConstraint.activate([bottomLeft, bottomRight, bottomBottom, leftConstraint, rightConstraint, bottomConstraint])
}
window.layoutIfNeeded()
DispatchQueue.main.async(execute: {
bottomB.superview?.bringSubviewToFront(bottomB)
bottomSafeArea.superview?.bringSubviewToFront(bottomSafeArea)
})
firstRun = false
}
Плюс один вспомогательный метод, созданный в расширении:
extension UIView {
func deactivateConstrainsToSuperview() {
guard let superview = self.superview else {return}
NSLayoutConstraint.deactivate(self.constraints.filter({
return ($0.firstItem === superview || $0.secondItem === superview)
}))
}
}
Итак, немного кода для написания, но только один раз. После этого у вас будет TabBar, который легко отобразить или скрыть при необходимости, используя ограничение между «представлением содержимого» и безопасной областью таким образом
private func hideBottomBar() {
UIView.animate(withDuration: Constants.appAnimation.duration, animations: { [weak self] in
guard let self = self else { return }
self.bottomBar.isHidden = true
self.bottomBarHeightConstraint.constant = 0
self.bottomBar.superview?.layoutIfNeeded()
})
}
и
private func showBottomBar() {
UIView.animate(withDuration: Constants.appAnimation.duration, animations: { [weak self] in
guard let self = self else { return }
self.bottomBar.isHidden = false
self.bottomBarHeightConstraint.constant = Constants.appConstraintsConstants.bottomBarHeight
self.bottomBar.superview?.layoutIfNeeded()
})
}
, как для высота обзора, охватывающего безопасную область (между нижней частью tabBar и верхней частью BottomLayoutGuide)
if #available(iOS 11.0, *) {
self.bottomSafeAreaViewHeightConstraint.constant = self.view.safeAreaInsets.bottom
} else {
self.bottomSafeAreaViewHeightConstraint.constant = 0
}
Надеюсь, это будет полезно, удачи!