Я испытываю досадная проблема тестирования новой iOS 11 на iPhone симулятор.
У меня есть UITabBarController и внутри каждой вкладки есть UINavigationController
, каждый UINavigationBar
определены также в нижней панели инструментов (setToolbarHidden:
), и по умолчанию они появляются внизу, прямо над вкладками.
Он до сих пор работает нормально, и, кажется, работает нормально и в предстоящие iPhone 8 и 8 моделей плюс, но на iPhone Х есть промежуток между панелью инструментов и вкладками. Мое предположение заключается в том, что панели инструментов не'т понимаете, что будет отображаться в панели вкладок, а затем покидает вмещающее пространство внизу.
Я думаю, единственный способ отремонтировать его будет использовать пользовательскую панель инструментов и дисплей/анимировать сам вместо того, чтобы использовать UINavigationBar по умолчанию, но хотелось бы услышать другие варианты :)
Я подал это как radr://проблемы/34421298, который был закрыт, так как является дубликатом проблемы radr:///34462371. Однако, в последней бета-версии Xcode версии 9.2 (9C32c) с iOS 11.2, это, кажется, быть исправлены. Здесь'ы пример мое приложение работает в симуляторе каждого устройства, без каких-либо изменений между ними.
Это'т действительно решение проблемы, кроме того, что немного терпения, возможно, решить ее без необходимости прибегать к ИП хитрости. Мое предположение, что iOS 11.2 будет до конца года, поскольку она'ы, необходимые для поддержки HomePod.
Если вы Don'т считаю оборотов можно попробовать манипулировать слой панели как очень замысловато, но быстрое решение.
class FixNavigationController: UINavigationController
{
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
updateTollbarPosition()
}
func updateTollbarPosition() {
guard let tabbarFrame = tabBarController?.tabBar.frame else {
return
}
let gapHeight = tabbarFrame.origin.y-toolbar.frame.origin.y-toolbar.frame.size.height
var
frame = toolbar.layer.frame
frame.origin.y += gapHeight
toolbar.layer.frame = frame
}
}
К сожалению, анимации не'т выглядеть хорошо, когда дело доходит до такого подхода. В таком случае, добавление пользовательской панели инструментов вместо стандартного будет лучшим решением.
выпустила iOS 11.1 и iPhone Х и этот баг/особенность, это'т еще. Так я реализовал этот метод. Этот код работает в iOS 9.0+.
Просто установите этот класс В вашей раскадровке, как навигационный контроллер'S-класса. Он будет использовать пользовательскую панель инструментов в iPhone X с правильной ограничения макета, и возвращается к родным в другие устройства. Пользовательская панель инструментов добавляется к навигации контроллер's посмотреть, а не ваш контроллер представления, чтобы сделать переходы более плавными.
toolbarItems вашего контроллера представления, чтобы обновить интерфейс. Если вы установите
toolbarItems` собственность навигационный контроллер, вы можете игнорировать этот шаг.Он имитирует все родное панели инструментов поведения (включая изменение высоты панели в портретном/ландшафтном режимах), кроме пуш/поп-анимации.
import UIKit
class FixNavigationController: UINavigationController {
private weak var alterToolbarHeightConstraint: NSLayoutConstraint?
private var _alterToolbar: UIToolbar?
private func initAlretToolbar() {
_alterToolbar = UIToolbar()
_alterToolbar!.isTranslucent = true
_alterToolbar!.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(_alterToolbar!)
if view.traitCollection.verticalSizeClass == .compact {
alterToolbarHeightConstraint = _alterToolbar!.heightAnchor.constraint(equalToConstant: 32.0)
} else {
alterToolbarHeightConstraint = _alterToolbar!.heightAnchor.constraint(equalToConstant: 44.0)
}
let bottomAnchor: NSLayoutConstraint
if #available(iOS 11.0, *) {
bottomAnchor = _alterToolbar!.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
} else {
bottomAnchor = _alterToolbar!.bottomAnchor.constraint(equalTo: bottomLayoutGuide.topAnchor)
}
NSLayoutConstraint.activate([
_alterToolbar!.leadingAnchor.constraint(equalTo: view.leadingAnchor),
_alterToolbar!.trailingAnchor.constraint(equalTo: view.trailingAnchor),
bottomAnchor,
alterToolbarHeightConstraint!
])
self.view.updateFocusIfNeeded()
self.view.layoutIfNeeded()
}
private var alterToolbarInSuper: UIToolbar? {
var superNavigationController = self.navigationController as? FixNavigationController
while superNavigationController != nil {
if superNavigationController?._alterToolbar != nil {
return superNavigationController?._alterToolbar
}
superNavigationController = superNavigationController?.navigationController as? FixNavigationController
}
return nil
}
private var alterToolbar: UIToolbar! {
get {
if let t = alterToolbarInSuper {
return t
}
if _alterToolbar == nil {
initAlretToolbar()
}
return _alterToolbar
}
}
// This is the logic to determine should use custom toolbar or fallback to native one
private var shouldUseAlterToolbar: Bool {
// return true if height is iPhone X's one
return UIScreen.main.nativeBounds.height == 2436
}
/// Manually call it after setting toolbar items in child view controllers
func updateItems(animated: Bool = false) {
if shouldUseAlterToolbar {
(_alterToolbar ?? alterToolbarInSuper)?.setItems(viewControllers.last?.toolbarItems ?? toolbarItems, animated: animated)
}
}
override var isToolbarHidden: Bool {
get {
if shouldUseAlterToolbar {
return _alterToolbar == nil && alterToolbarInSuper == nil
} else {
return super.isToolbarHidden
}
}
set {
if shouldUseAlterToolbar {
if newValue {
super.isToolbarHidden = newValue
_alterToolbar?.removeFromSuperview()
_alterToolbar = nil
self.view.updateFocusIfNeeded()
self.view.layoutIfNeeded()
// TODO: Animation when push/pop
alterToolbarHeightConstraint = nil
var superNavigationController = self.navigationController as? FixNavigationController
while let superNC = superNavigationController {
if superNC._alterToolbar != nil {
superNC._alterToolbar?.removeFromSuperview()
superNC._alterToolbar = nil
superNC.view.updateFocusIfNeeded()
superNC.view.layoutIfNeeded()
}
superNavigationController = superNC.navigationController as? FixNavigationController
}
} else {
alterToolbar.setItems(viewControllers.last?.toolbarItems ?? toolbarItems, animated: false)
}
} else {
super.isToolbarHidden = newValue
}
}
}
override func setToolbarItems(_ toolbarItems: [UIBarButtonItem]?, animated: Bool) {
super.setToolbarItems(toolbarItems, animated: animated)
updateItems(animated: animated)
}
override var toolbarItems: [UIBarButtonItem]? {
get {
return super.toolbarItems
}
set {
super.toolbarItems = newValue
updateItems()
}
}
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
guard let _alterToolbar = _alterToolbar else {
return
}
self.alterToolbarHeightConstraint?.isActive = false
let height: CGFloat = (view.traitCollection.verticalSizeClass == .compact) ? 32.0 : 44.0
let alterToolbarHeightConstraint = _alterToolbar.heightAnchor.constraint(equalToConstant: height)
alterToolbarHeightConstraint.isActive = true
self.alterToolbarHeightConstraint = alterToolbarHeightConstraint
}
}
Apple до сих пор еще не исправили этот баг в iOS 11.2. Происходит от Хусейн мусавиан'ы решение, вот простой подход, который я взял.
Я взял этот подход, потому что у меня только один UITableViewController, где эта ошибка происходит. Так что в моем случае, я просто добавил следующий код, перечисленных ниже, чтобы мой файл ViewController (который является UITableViewController), где эта ошибка происходит.
Преимущества:
И вот код:
1.Добавить startFixIPhoneXToolbarBug в свой viewWillAppear как это:
override func viewWillAppear(_ animated: Bool)
{
super.viewWillAppear(animated)
startFixIPhoneXToolbarBug()
}
2.Добавить endFixIPhoneXToolbarBug в свой viewWillDisappear как это:
override func viewWillDisappear(_ animated: Bool)
{
super.viewWillDisappear(animated)
endFixIPhoneXToolbarBug()
}
3.Реализации пуск/endFixIPhoneXToolbarBug в файле ViewController как это:
private var alterToolbarHeightConstraint: NSLayoutConstraint? = nil
private var alterToolbar: UIToolbar? = nil
func startFixIPhoneXToolbarBug()
{
// Check if we are running on an iPhone X
if UIScreen.main.nativeBounds.height != 2436
{
return // No
}
// See if we have a Toolbar
if let tb:UIToolbar = self.navigationController?.toolbar
{
// See if we already added our own
if alterToolbar == nil
{
// Should always be the case
if let tbView = tb.superview
{
// Create a new Toolbar and apply correct constraints
alterToolbar = UIToolbar()
alterToolbar!.isTranslucent = true
alterToolbar!.translatesAutoresizingMaskIntoConstraints = false
tb.isHidden = true
tbView.addSubview(alterToolbar!)
if tbView.traitCollection.verticalSizeClass == .compact
{
alterToolbarHeightConstraint = alterToolbar!.heightAnchor.constraint(equalToConstant: 32.0)
}
else
{
alterToolbarHeightConstraint = alterToolbar!.heightAnchor.constraint(equalToConstant: 44.0)
}
let bottomAnchor: NSLayoutConstraint
if #available(iOS 11.0, *)
{
bottomAnchor = alterToolbar!.bottomAnchor.constraint(equalTo: tbView.safeAreaLayoutGuide.bottomAnchor)
}
else
{
bottomAnchor = alterToolbar!.bottomAnchor.constraint(equalTo: bottomLayoutGuide.topAnchor)
}
NSLayoutConstraint.activate([
alterToolbar!.leadingAnchor.constraint(equalTo: tbView.leadingAnchor),
alterToolbar!.trailingAnchor.constraint(equalTo: tbView.trailingAnchor),
bottomAnchor,
alterToolbarHeightConstraint!
])
tbView.updateFocusIfNeeded()
tbView.layoutIfNeeded()
}
}
// Add the original items to the new toolbox
alterToolbar!.setItems(tb.items, animated: false)
}
}
func endFixIPhoneXToolbarBug()
{
if alterToolbar != nil
{
alterToolbar!.removeFromSuperview()
alterToolbar = nil
alterToolbarHeightConstraint = nil
if let tb:UIToolbar = self.navigationController?.toolbar
{
tb.isHidden = false
}
}
}