次のコントローラー階層を考慮してください。
UINavigationController
UIViewController
UITableViewController
UIViewController
の存在がレイアウトに影響しています。これがないと、UITableViewController
はUINavigationController
の境界全体を占有します。
ただし、UIViewController
とUINavigationController
の間にVanilla UITableViewController
を追加すると、UIViewController
の上部とUITableViewController
の上部の間に20pxのギャップが表示されます。
コードを可能な限り単純なものに減らしても、この動作は観察されます。このアプリ委任コードを検討してください。
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;
}
上記のstillは、UIView
の上部とUITableView
の上部との間に20pxのギャップを示しています。
somethingが誤ってステータスバーにスペースを割り当てていることを理解しています。 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;
}
UIViewController
? UITableViewController
?ViewDidLayoutSubviews
をオーバーライドすると、View Controllerがビジュアルツリーのどこに表示されるかについての期待に結び付けられます。コントローラースタックの上位でホストされる場合、物事は正しく見えません。このカップリングを回避して再利用性を高める方法はありますか?表示されている動作はバグではなく、ビューを階層に追加するという誤用の副作用にすぎません。
TableViewをビューに追加するとき、そのtableViewを親に対して相対的にどのようにサイズ設定するかをUIKitに伝える必要があります。次の2つのオプションがあります。 自動レイアウト または自動サイズ変更マスク。ビューのレイアウト方法を説明せずに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の外観は次のとおりです。
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;
}
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
}
注最近投稿 スーパービューを満たすようにビューを構成する方法を説明しました
あなたの問題は、UITableViewController
が別の子コントローラとして直接追加されるという根本的な問題に関連しているようです。
これを見回すことは新しい問題ではありません: iOS 7:ステータスバーの下にUITableViewが表示されます
その記事に関連して、私はあなたのコードを取り、次のオプションを試しました(C#8 ^にあることに気づいたとき):
UITableViewController
を使用する代わりに、UIViewController
を追加してから、UITableView
の子としてUIViewController
を追加します。これを行うと、20ptの問題はありません。これは、問題がUITableViewController
クラスにあることを強調しています。
このアプローチは、比較的クリーンな回避策であり、既にあるものに対するいくつかの追加手順のみです。
元のコードに制約を追加してUITableViewControllerフレームを最上部に強制してみましたが、これを機能させることができませんでした。繰り返しになりますが、これはテーブルコントローラーが物事をオーバーライドすることになる可能性があります。
ストーリーボードを使用してデモを作成すると、すべてが機能します。これは、IB自体がコンテナビューを使用して新しいView Controllerを埋め込むという事実にあると考えています。したがって、ストーリーボードを使用する場合、Appleは、使用する制約のフレームを設定できるビューを追加し、そのビュー内にUITableViewController
を埋め込みますセグエを埋め込みます。
したがって、1)のように、中央のビューを使用すると問題が解決するようであり、中央のビューframe
を制御することが重要であると思われます。
あなたの唯一の実行可能な回避策で、フレームを変更することが答えだということに気付きました。ただし、iOS7以降、フレームを変更することは、フレームを操作したい制約と競合する可能性があるため、推奨されないようです。
edgesForExtendedLayout
のような他のオプションを試してみると、すべて失敗したようです。これらはコンテナビューコントローラのヒントのようで、UITableViewControllerはそれらを無視します。私見は、オプション1)がレイアウトを完全に制御し、後で問題を引き起こす可能性のあるフレームオーバーライドでシステムと戦っていないため、最も安全なアプローチだと思います。オプション2)ストーリーボードを使用する場合にのみ本当に機能します。自分で同じことを手動で行うこともできますが、埋め込みセグエで何が起こっているかは誰が知っていますか?.
[〜#〜] edit [〜#〜]
Arkadiusz Holkoの回答で強調されているように、欠落しているステップがあり、テーブルビューのフレームを明示的に設定すると問題が解決するようです。
子View Controllerを追加するときに、1つのステップを見逃しました-ビューのフレームを設定します。
2番目のステップを参照してください。
- (void) displayContentController: (UIViewController*) content;
{
[self addChildViewController:content]; // 1
content.view.frame = [self frameForContentController]; // 2
[self.view addSubview:self.currentClientView];
[content didMoveToParentViewController:self]; // 3
}
ステータスバーには20ピクセルが使用されます。自動レイアウトでxibファイルまたはストーリーボードを使用している場合は、上部の制約を上部レイアウトガイドに設定して、20ピクセルの差異を処理できます。
私の目標を達成するためのきれいな(より)方法はありますか?
フレームを変更するだけです。
tableView.View.Frame = intermediateView.View.Bounds;
tableView.View.AutoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
実際に20pxのギャップを追加する責任は?UIViewController?UITableViewController?
UIViewController
を新しく作成したら、UIViewController.view.frame
を記録できます。 UITableViewController.view.frame
には常に20pxのギャップがあることがわかります。どうして? Appleは、UITableViewController.view
を20pxの上部パディングで画面サイズで初期化するだけです。
View Controllerをさまざまなコンテキストで引き続き使用できるようにするためのベストプラクティスは何ですか?...
UIViewController.view
を別のUIViewController.view
に追加する場合は、ストーリーボードを使用してContainer View
を使用するのが最善の方法です。
ストーリーボードを使用したくない、または使用できない場合。サブクラスUIView
のみをお勧めします。 addChildViewController
には、ライフサークルとレイアウトに迷惑な問題がある場合があります。