Подтвердить что ты не робот

Почему 20px пробел в верхней части моего UIViewController?

Проблема

Рассмотрим следующую иерархию контроллера:

  • UINavigationController
    • UIViewController
      • UITableViewController

Присутствие 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 связывает мой контроллер представления с ожиданиями относительно того, где он будет отображаться в визуальном дереве. Если бы он был размещен выше стека контроллера, все выглядело бы неправильно. Есть ли способ избежать этой связи и, следовательно, увеличить повторное использование?
4b9b3361

Ответ 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 иногда имеют раздражающие проблемы с кругом жизни и компоновкой.