Почему 20px пробел в верхней части моего UIViewController?
Проблема
Рассмотрим следующую иерархию контроллера:
Присутствие UIViewController
влияет на макет. Без него UITableViewController
занимает все границы UINavigationController
:
![enter image description here]()
Однако, если я добавлю ваниль UIViewController
между UINavigationController
и UITableViewController
, между вершиной UIViewController
и вершиной UITableViewController
появится зазор 20px:
![enter image description here]()
Даже если я уменьшу свой код до самой простой вещи, я все еще наблюдаю за этим поведением. Рассмотрим этот код делегирования приложения:
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
window = new UIWindow(UIScreen.MainScreen.Bounds);
var tableView = new UITableViewController();
var intermediateView = new UIViewController();
var navigation = new UINavigationController(intermediateView);
navigation.View.BackgroundColor = UIColor.Red;
intermediateView.View.BackgroundColor = UIColor.Green;
tableView.View.BackgroundColor = UIColor.Blue;
intermediateView.AddChildViewController(tableView);
intermediateView.View.AddSubview(tableView.View);
tableView.DidMoveToParentViewController(intermediateView);
window.RootViewController = navigation;
window.MakeKeyAndVisible();
return true;
}
Вышеприведенный выше показывает 20px зазор между вершиной UIView
и вершиной UITableView
.
Мое понимание проблемы
Я понимаю, что что-то ошибочно выделяет пространство для строки состояния. Используя Reveal, я вижу, что Frame
для UITableViewController
имеет значение Y
20
.
Вещи, которые я пробовал
Неудачный
- Установите
WantsFullScreenLayout
в true
на UIViewController
, UITableViewController
, и оба
- Игра с
EdgesForExtendedLayout
и ExtendedLayoutIncludesOpaqueBars
для UIViewController
и UITableViewController
- Играется с
AutomaticallyAdjustsScrollViewInsets
на UIViewController
- Играется с
PreservesSuperviewLayoutMargins
в UITableView
- Исправлено переопределение
PrefersStatusBarHidden
и возврат true
в UIViewController
и UITableViewController
Успешные
Переопределение ViewDidLayoutSubviews
в моем UITableViewController
таким образом:
public override void ViewDidLayoutSubviews()
{
base.ViewDidLayoutSubviews();
this.View.Frame = this.View.Superview.Bounds;
}
Вещи, которые я хочу знать
- Есть ли чистый (er) способ достижения моей цели?
- что на самом деле отвечает за добавление 20px-пробелов?
UIViewController
? UITableViewController
?
- Каковы наилучшие методы для обеспечения того, чтобы мои контроллеры отображались в разных контекстах? Предположительно переопределение
ViewDidLayoutSubviews
связывает мой контроллер представления с ожиданиями относительно того, где он будет отображаться в визуальном дереве. Если бы он был размещен выше стека контроллера, все выглядело бы неправильно. Есть ли способ избежать этой связи и, следовательно, увеличить повторное использование?
Ответы
Ответ 1
Поведение, которое вы видите, не является ошибкой, а просто побочным эффектом вашего неправильного использования добавления представлений в иерархию.
Когда вы добавляете tableView в представление, вам нужно сообщить UIKit, как вы хотите, чтобы tableView имел размер относительно его родителя. У вас есть два варианта: "Автомакет" или "Авторезистировать маски". Без описания того, как вы хотите, чтобы ваш вид в макете UIKit
просто выталкивал его в иерархию, и реализация по умолчанию будет зависеть от вашего представления под верхним руководством по макете (которое просто является высотой строки состояния). Что-то простое, как это могло бы сделать трюк:
tableVC.View.Frame = rootVC.View.Bounds
tableVC.View.Autoresizingmask = UIViewAutoresizing.FlexibleWidth
tableVC.View.TranslatesAutoresizingMaskIntoConstraints = true// always nice to explicitly use auto layout
Это поведение на самом деле не исключение для UITableViewController
, но также и для UICollectionViewController
. Я считаю, что их реализация viewLoading по умолчанию вставляет представление в строку состояния. Если мы сделаем наш childController простым подклассом UIViewController
, ни одно из этих действий не будет показано. Не рассматривайте это как ошибку, хотя, если вы явно заявляете, как вы хотите, чтобы их соответствующие представления были изложены, у вас не будет этой проблемы. Естественно, это основная функция контроллера контейнера.
Вот как выглядит ваш appDelegate:
Xamarin
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
window = new UIWindow(UIScreen.MainScreen.Bounds);
var tableVC = new UITableViewController();
var rootVC = new UIViewController();
var navigationVC = new UINavigationController(intermediateView);
navigationVC.View.BackgroundColor = UIColor.Red;
rootVC.View.BackgroundColor = UIColor.Green;
tableVC.View.BackgroundColor = UIColor.Blue;
rootVC.AddChildViewController(tableVC);
rootVC.View.AddSubview(tableVC.View);
//YOU NEED TO CONFIGURE THE VIEWS FRAME
//If you comment this out you will see the green view under the status bar
tableVC.View.Frame = rootVC.View.Bounds
tableVC.View.Autoresizingmask = UIViewAutoresizing.FlexibleWidth
tableVC.View.TranslatesAutoresizingMaskIntoConstraints = true
tableVC.DidMoveToParentViewController(rootVC);
window.RootViewController = navigationVC;
window.MakeKeyAndVisible();
return true;
}
Swift
var window: UIWindow?
var navigationControlller: UINavigationController!
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let rootVC = UIViewController(nibName: nil, bundle: nil)
let tableVC = UITableViewController(style: .Plain)
let navVC = UINavigationController(rootViewController: rootVC)
navVC.navigationBarHidden = true
navVC.view.backgroundColor = UIColor.redColor()
rootVC.view.backgroundColor = UIColor.greenColor()
rootVC.view.addSubview(tableVC.view)
//YOU NEED TO CONFIGURE THE VIEWS FRAME
//If you comment this out you will see the green view under the status bar
tableVC.view.frame = rootVC.view.bounds
tableVC.view.autoresizingMask = .FlexibleWidth | .FlexibleHeight
tableVC.view.setTranslatesAutoresizingMaskIntoConstraints(true)
rootVC.addChildViewController(tableVC)
tableVC.didMoveToParentViewController(rootVC)
window = UIWindow(frame: UIScreen.mainScreen().bounds)
window?.rootViewController = navVC
window?.makeKeyAndVisible()
return true
}
Примечание Недавно я написал сообщение , описывающее способы настройки представления, чтобы заполнить его супервизор
Ответ 2
Ваша проблема, по-видимому, связана с некоторыми фундаментальными проблемами, когда UITableViewController
непосредственно добавляется как дочерний контроллер другого.
Оглядываясь, это не новая проблема: iOS 7: UITableView отображается в строке состояния
Относительно этой статьи я взял ваш код и попробовал следующие параметры (однажды понял, что это было в С# 8 ^)):
-
Вместо использования UITableViewController
добавьте UIViewController
а затем добавьте UITableView
в качестве дочернего элемента UIViewController
.
Если вы это сделаете, тогда не будет проблемы с 20pt. Это подчеркивает, что
проблема заключается в классе UITableViewController
.
Этот подход является относительно чистым обходным решением, и только пара
дополнительные шаги на то, что у вас уже есть.
Я попытался добавить ограничения в ваш исходный код, чтобы заставить
Рамка UITableViewController вверху, но не могла это сделать
Работа. Опять же, это может привести к переопределению контроллера таблицы
вещи сами.
-
Если вы создадите свою демоверсию с помощью раскадровки, все будет работать. Это я
полагают, что сам ИБ использует вид контейнера для
встройте новый контроллер представления. Поэтому, если вы используете раскадровку,
apple делает это, чтобы добавить представление, которое вы можете установить кадр использования
ограничений и затем вставляет UITableViewController
внутрь
это представление через встроенный Segue.
Следовательно, согласно 1), использование обзора в середине, похоже, решает проблему
и снова кажется, что контроль над средними представлениями frame
является ключевым.
Я заметил в вашем единственном жизнеспособном обходном пути, что изменение рамки было
ответ. Однако post iOS7, изменяя фрейм, не кажется
рекомендуется из-за проблем, с которыми он может столкнуться
ограничения, которые также хотят манипулировать фреймом.
- Попытка других опций, таких как
edgesForExtendedLayout
, показалась
потерпеть неудачу. Кажется, это подсказки для контроллеров контейнеров и
UITableViewController игнорирует их.
IMHO Я думаю, что вариант 1) кажется самым безопасным подходом, поскольку у вас есть полный контроль над макетом и не борются с системой с переопределениями фреймов, которые могут вызывать проблемы позже. Вариант 2) действительно работает, только если вы используете раскадровки. Вы можете попробовать сделать то же самое вручную самостоятельно, но кто знает, что происходит в встроенном Segue.
ИЗМЕНИТЬ
Казалось бы, в его ответе был отмечен отсутствующий шаг, который был выделен Аркадиусом Холько, и установка рамки явно для представления таблицы устраняет проблему.
Ответ 3
Вы пропустили один шаг при добавлении контроллера детского представления - настройка его рамок представления.
См. второй шаг:
- (void) displayContentController: (UIViewController*) content;
{
[self addChildViewController:content]; // 1
content.view.frame = [self frameForContentController]; // 2
[self.view addSubview:self.currentClientView];
[content didMoveToParentViewController:self]; // 3
}
Источник: https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/CreatingCustomContainerViewControllers/CreatingCustomContainerViewControllers.html
Ответ 4
20 пикселей берутся в строке состояния. Если вы используете xib файл или раскадровку с автоматическим расположением макета, вы можете установить верхнее ограничение на руководство по началу макета, чтобы обрабатывать разницу в 20 пикселей
Ответ 5
Есть ли чистый (er) способ достижения моей цели?
Просто измените рамку.
tableView.View.Frame = intermediateView.View.Bounds;
tableView.View.AutoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
, что на самом деле отвечает за добавление пробела 20px? UIViewController? UITableViewController?
Вы можете записать UIViewController.view.frame
после нового a UIViewController
.
Вы можете видеть, что UITableViewController.view.frame
всегда имеет пробел 20px. Зачем? Я думаю, что Apple просто инициализирует UITableViewController.view
размером экрана с верхним дополнением 20px.
Каковы наилучшие методы для обеспечения того, чтобы мои контроллеры просмотра оставались пригодными для использования в разных контекстах?...
Если вы хотите добавить UIViewController.view
в другой UIViewController.view
. Лучший способ - использовать панель с рассказами и использовать Container View
.
Если вы не хотите или не можете использовать панель рассказов. Я предлагаю только подкласс UIView
. addChildViewController
иногда имеют раздражающие проблемы с кругом жизни и компоновкой.