12

この問題は私を夢中にさせています。viewControllerユーザーがセグメント化されたコントロールの選択された「タブ」を変更したときに変更しようとしています。私は調査に数時間を費やしましたが、うまくいく、またはストーリーボードを介して行われる答えを見つけることができませんでした.

タブアプリケーションの設定はとても簡単なので、本当に気になりますが、タブアプリケーションのようにセグメント化されたコントロールを使用しようとすると、うまくいきません。セグメント化されたコントロールで選択されているインデックスを検出する方法は既に知っています。どうすればこれを達成できますか?

どうもありがとうございました。

4

4 に答える 4

42

注: @interface セクションを含む iOS 5 以降の View Controller 封じ込めコードで回答を更新

私のアプリでは、ナビゲーションバーにセグメントコントロールを備えたビューコントローラーがあり、「タブ」をクリックするとビューコントローラーが切り替わります。基本的な考え方は、View Controller の配列を用意し、Segment Index (および indexDidChangeForSegmentedControl IBAction.

私のアプリのサンプル コード (iOS 5 以降) (これは 2 つのビュー コントローラー用ですが、複数のビュー コントローラーに簡単に拡張できます)。コードは iOS 4 よりもわずかに長くなりますが、オブジェクト グラフはそのまま維持されます。また、ARC を使用します。

@interface MyViewController ()
// Segmented control to switch view controllers
@property (weak, nonatomic) IBOutlet UISegmentedControl *switchViewControllers;

// Array of view controllers to switch between
@property (nonatomic, copy) NSArray *allViewControllers;

// Currently selected view controller
@property (nonatomic, strong) UIViewController *currentViewController;
@end

@implementation UpdateScoreViewController
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
    [super viewDidLoad];

    // Create the score view controller
    ViewControllerA *vcA = [self.storyboard instantiateViewControllerWithIdentifier:@"ViewControllerA"];

    // Create the penalty view controller
    ViewControllerB *vcB = [self.storyboard instantiateViewControllerWithIdentifier:@"ViewControllerB"];

    // Add A and B view controllers to the array
    self.allViewControllers = [[NSArray alloc] initWithObjects:vcA, vcB, nil];

    // Ensure a view controller is loaded
    self.switchViewControllers.selectedSegmentIndex = 0;
    [self cycleFromViewController:self.currentViewController toViewController:[self.allViewControllers objectAtIndex:self.switchViewControllers.selectedSegmentIndex]];
}

#pragma mark - View controller switching and saving

- (void)cycleFromViewController:(UIViewController*)oldVC toViewController:(UIViewController*)newVC {

    // Do nothing if we are attempting to swap to the same view controller
    if (newVC == oldVC) return;

    // Check the newVC is non-nil otherwise expect a crash: NSInvalidArgumentException
    if (newVC) {

        // Set the new view controller frame (in this case to be the size of the available screen bounds)
        // Calulate any other frame animations here (e.g. for the oldVC)
        newVC.view.frame = CGRectMake(CGRectGetMinX(self.view.bounds), CGRectGetMinY(self.view.bounds), CGRectGetWidth(self.view.bounds), CGRectGetHeight(self.view.bounds));

        // Check the oldVC is non-nil otherwise expect a crash: NSInvalidArgumentException
        if (oldVC) {

            // Start both the view controller transitions
            [oldVC willMoveToParentViewController:nil];
            [self addChildViewController:newVC];

            // Swap the view controllers
            // No frame animations in this code but these would go in the animations block
            [self transitionFromViewController:oldVC
                              toViewController:newVC
                                      duration:0.25
                                       options:UIViewAnimationOptionLayoutSubviews
                                    animations:^{}
                                    completion:^(BOOL finished) {
                                        // Finish both the view controller transitions
                                        [oldVC removeFromParentViewController];
                                        [newVC didMoveToParentViewController:self];
                                        // Store a reference to the current controller
                                        self.currentViewController = newVC;
                                    }];

        } else {

            // Otherwise we are adding a view controller for the first time
            // Start the view controller transition
            [self addChildViewController:newVC];

            // Add the new view controller view to the ciew hierarchy
            [self.view addSubview:newVC.view];

            // End the view controller transition
            [newVC didMoveToParentViewController:self];

            // Store a reference to the current controller
            self.currentViewController = newVC;
        }
    }
}

- (IBAction)indexDidChangeForSegmentedControl:(UISegmentedControl *)sender {

    NSUInteger index = sender.selectedSegmentIndex;

    if (UISegmentedControlNoSegment != index) {
        UIViewController *incomingViewController = [self.allViewControllers objectAtIndex:index];
        [self cycleFromViewController:self.currentViewController toViewController:incomingViewController];
    }

}
@end

元の例 (iOS 4 以前):

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
    [super viewDidLoad];

    // Create the score view controller
    AddHandScoreViewController *score = [self.storyboard instantiateViewControllerWithIdentifier:@"AddHandScore"];

    // Create the penalty view controller
    AddHandPenaltyViewController *penalty = [self.storyboard instantiateViewControllerWithIdentifier:@"AddHandPenalty"];

    // Add Score and Penalty view controllers to the array
    self.allViewControllers = [[NSArray alloc] initWithObjects:score, penalty, nil];

    // Ensure the Score controller is loaded
    self.switchViewControllers.selectedSegmentIndex = 0;
    [self switchToController:[self.allViewControllers objectAtIndex:self.switchViewControllers.selectedSegmentIndex]];
}

#pragma mark - View controller switching and saving

- (void)switchToController:(UIViewController *)newVC
{
    if (newVC) {
        // Do nothing if we are in the same controller
        if (newVC == self.currentViewController) return;

        // Remove the current controller if we are loaded and shown
        if([self.currentViewController isViewLoaded]) [self.currentViewController.view removeFromSuperview];

        // Resize the new view controller
        newVC.view.frame = CGRectMake(CGRectGetMinX(self.view.bounds), CGRectGetMinY(self.view.bounds), CGRectGetWidth(self.view.bounds), CGRectGetHeight(self.view.bounds));

        // Add the new controller
        [self.view addSubview:newVC.view];

        // Store a reference to the current controller
        self.currentViewController = newVC;
    }
}

- (IBAction)indexDidChangeForSegmentedControl:(UISegmentedControl *)sender {

    NSUInteger index = sender.selectedSegmentIndex;

    if (UISegmentedControlNoSegment != index) {
        UIViewController *incomingViewController = [self.allViewControllers objectAtIndex:index];
        [self switchToController:incomingViewController];
    }

}
于 2012-07-10T22:39:04.303 に答える
5

内でサブビューを変更する方がはるかに簡単だと思いUIViewControllerます。ストーリーボードでサブビューを設定し、それらをIBOuletsコントローラーに接続しhiddenて、クリックされたコントロールに応じてビューのプロパティを YES または NO に設定できます。

ここで、@Robotic Cat のアプローチを使用すると、これも優れたソリューションであり、私が提示したソリューションを使用してすべてのロジックを 1 つのコントローラーに配置する必要があることを考えると、アプリの動作にもう少しモジュール性を持たせることができます。

于 2012-07-10T22:40:09.703 に答える
0

UISegmentedControl はデリゲート プロトコルがないという点で少し異なります。「ターゲットの追加」スタイルを使用する必要があります。あなたの場合、あなたがしたいことは、 UISegmentedControl が変更されたときに通知されるターゲットを追加することです(これは親View Controllerである可能性があります)。その後、そのターゲットはタブの切り替えを処理できます。

例えば:

[self.mainSegmentedControl addTarget:self action:@selector(changedSegmentedControl:) forControlEvents:UIControlEventValueChanged];

この例では、セグメント化されたコントロールの変数にアクセスできるビュー/コントローラーからコードが呼び出されています。changedSegmentedControl: メソッドを呼び出すために自分自身を追加します。

次に、次のような別の方法があります。

- (void)changedSegmentedControl:(id)sender
{
   UISegmentedControl *ctl = sender;
   NSLog(@"Changed value of segmented control to %d", ctl.selectedSegmentIndex);
   // Code to change View Controller goes here
}

注: これは、メモリから書かれたテストされていないコードです。適宜、ドキュメントを参照してください。

于 2012-07-10T22:34:35.633 に答える