3つのタブにまたがるフォームを作成しようとしています。下のスクリーンショットで、タブが配置される場所を確認できます。ユーザーがタブをタップすると、コンテナービューが更新され、使用している特定のビューコントローラーが表示されます。
タブ1 =ビューコントローラ1
タブ2 =ビューコントローラー2
タブ3 =ビューコントローラー3
上に示したビューコントローラのクラスはPPAddEntryViewController.mです。このクラス内にコンテナビューのアウトレットを作成し、コンテナビュープロパティを作成しました。
@property (weak, nonatomic) IBOutlet UIView *container;
タブ用のIBActionも用意しています。
- (IBAction)tab1:(id)sender {
//...
}
- (IBAction)tab2:(id)sender {
//...
}
- (IBAction)tab3:(id)sender {
//...
}
これらのIBActionsでコンテナを設定して、コンテナビューが保持するビューコントローラを変更するにはどうすればよいですか?
他のいくつかのことの中で、これが私が試したことです:
UIViewController *viewController1 = [self.storyboard instantiateViewControllerWithIdentifier:@"vc1"];
_container.view = viewController1;
...しかし、それは機能しません。前もって感謝します。
私は最近、私がやろうとしていたことのperfectサンプルコードを見つけました。これには、ストーリーボードの実装と、関連するすべてのセグエとコードが含まれています。本当に助かりました。
コンテナビューをビューに追加し、子ビューコントローラを「切り替える」ボタンを押すと、適切なセグエが起動され、正しいセットアップ作業が実行されます。
ストーリーボードでは、1つの埋め込みセグエのみをコンテナビューに接続できます。したがって、中間処理コントローラを作成します。埋め込みセグエを作成し、EmbededSegueIdentifierなどの識別子を付けます。
親ビューコントローラーでボタンを配線するか、必要なものを何でも接続して、準備セグエの子ビューコントローラーを参照します。親ビューコントローラがロードされるとすぐに、セグエが起動されます。
@property (weak, nonatomic) MyContainerViewController *myContainerViewController;
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:@"EmbeddedSegueIdentifier"]) {
self.myContainerViewController = segue.destinationViewController;
}
}
ボタンが押すのをコンテナコントローラーに委任するのはかなり簡単なはずです。
この次のコードは、いくつかのソースから部分的に借用されましたが、重要な変更点は、明示的なフレームではなく自動レイアウトが使用されていることです。単に行を変更することを妨げるものは何もありません[self addConstraintsForViewController:]
にとって viewController.view.frame = self.view.bounds
。ストーリーボードでは、このコンテナビューコントローラは、宛先の子ビューコントローラにセグエする以上のことは何もしません。
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(@"%s", __PRETTY_FUNCTION__);
[self performSegueWithIdentifier:@"FirstViewControllerSegue" sender:nil];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
UIViewController *destinationViewController = segue.destinationViewController;
if ([self.childViewControllers count] > 0) {
UIViewController *fromViewController = [self.childViewControllers firstObject];
[self swapFromViewController:fromViewController toViewController:destinationViewController];
} else {
[self initializeChildViewController:destinationViewController];
}
}
- (void)initializeChildViewController:(UIViewController *)viewController
{
[self addChildViewController:viewController];
[self.view addSubview:viewController.view];
[self addConstraintsForViewController:viewController];
[viewController didMoveToParentViewController:self];
}
- (void)swapFromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController
{
[fromViewController willMoveToParentViewController:nil];
[self addChildViewController:toViewController];
[self transitionFromViewController:fromViewController toViewController:toViewController duration:0.2f options:UIViewAnimationOptionTransitionCrossDissolve animations:nil completion:^(BOOL finished) {
[self addConstraintsForViewController:toViewController];
[fromViewController removeFromParentViewController];
[toViewController didMoveToParentViewController:self];
}];
}
- (void)addConstraintsForViewController:(UIViewController *)viewController
{
UIView *containerView = self.view;
UIView *childView = viewController.view;
[childView setTranslatesAutoresizingMaskIntoConstraints:NO];
[containerView addSubview:childView];
NSDictionary *views = NSDictionaryOfVariableBindings(childView);
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[childView]|"
options:0
metrics:nil
views:views]];
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[childView]|"
options:0
metrics:nil
views:views]];
}
#pragma mark - Setters
- (void)setSelectedControl:(ViewControllerSelectionType)selectedControl
{
_selectedControl = selectedControl;
switch (self.selectedControl) {
case kFirstViewController:
[self performSegueWithIdentifier:@"FirstViewControllerSegue" sender:nil];
break;
case kSecondViewController:
[self performSegueWithIdentifier:@"SecondViewControllerSegue" sender:nil];
break;
default:
break;
}
}
最後に必要なのは、何もしないカスタムセグエで、Container ViewControllerから呼び出される適切なセグエ識別子を使用して各宛先に移動します。空のperformメソッドを入力しないと、アプリがクラッシュします。通常、ここでカスタム遷移アニメーションを実行できます。
@implementation SHCDummySegue
@interface SHCDummySegue : UIStoryboardSegue
@end
- (void)perform
{
// This space intentionally left blank
}
@end
Update:先に知ったように、UITabBarControllerが推奨される方法です。カスタムの高さをご希望の場合は、ここから始めてください: ITabBarControllerのタブバーをカスタマイズする私の方法-Stackoverflowの回答
IOS 5以降では、このAPIを介して外観をカスタマイズするためのアクセス権があります。 IAppearanceプロトコルリファレンス 。これはそのための素晴らしいチュートリアルです: タブバーの背景と外観をカスタマイズする方法
探しているものを実現する最も明白な方法は、3つの異なるコンテナー(単純なUIView)を管理し、各タブに必要なコンテンツビューを保持するようにそれぞれを実装することです(コンテナーの非表示プロパティを使用します)。
さまざまなコンテナで実現できることの例を次に示します。
もちろん、これらのコンテナの「スワッピング」はアニメーション化できます。あなたの自己回答について、あなたはおそらくそれをする正しい方法を選んだでしょう。
viewControllerを保持するためのメンバー変数があります。
UIViewController *selectedViewController;
iBActionsで、それとビューを切り替えます。例えば.
- (IBAction)tab1:(id)sender {
UIViewController *viewController1 = [self.storyboard instantiateViewControllerWithIdentifier:@"vc1"];
_container.view = viewController1.view;
selectedViewController = viewController1;
}
ビューを起動するために表示され、removeChildViewController、didMoveToParent、addChildViewController、didMoveToParentを呼び出します。
UITabBarControllerを使用してこれを機能させました。カスタムタブを使用するには、TabBarControllerをサブクラス化し、コードでボタンをコントローラーに追加する必要がありました。次に、ボタンのタップイベントをリッスンし、各タブにselectedIndex
を設定します。
それはかなり簡単でしたが、3つのタブのような単純なもののために私のストーリーボードにはたくさんのがらくたです。