2012-07-10 170 views
11

這個問題讓我瘋狂。當用戶更改分段控件的選定「選項卡」時,我試圖更改viewController。我花了幾個小時的時間進行研究,一直未能找到可以通過故事板完成的答案。分段控制改變時更改視圖控制器

它真的很麻煩,因爲設置選項卡應用程序非常簡單,但試圖使用像Tab應用程序一樣的分段控件只是不起作用。我已經知道如何檢測在分段控制中選擇哪個索引。我怎樣才能做到這一點?

非常感謝。

+0

您是否想換出_view_或_view controller_?他們是兩回事。如果是後者,我建議將所有東西都放到一個視圖控制器中,並根據需要顯示或隱藏子視圖。 – 2012-07-10 22:29:36

+0

嗯,我真的是iOS新手,我想到的最簡單的事情就是改變viewController就像選項卡式應用程序一樣。您是否建議製作各種視圖並使用相同的視圖控制器來管理它們?如果是這樣,我該怎麼做?非常感謝 – 2012-07-10 22:33:56

回答

4

我會說這是多少卡如果要在UIViewController內更改子視圖,則可以在故事板中設置子視圖,並在控制器中將它們與IBOulets掛鉤,您可以將視圖的hidden屬性設置爲YES或NO,具體取決於所單擊的控件。

現在,如果您使用@Robotic Cat的方法,這也是一個很好的解決方案,您可以在應用程序的工作方式上有更多的模塊化,考慮到您必須使用我提供的解決方案將所有邏輯放在一個控制器中。

+0

我喜歡你的建議只是在Xcode上試用過,看起來不錯並且易於實現。我唯一擔心的是將背景隱藏在背景中效率低下嗎? – 2012-07-10 23:02:10

+1

我還沒有讀過te開發人員文檔中任何與此相反的內容,儘管您必須考慮如果添加了大量視覺元素,它會佔用內存,因此明智地做。爲了避免這種情況,您可以動態地灌輸所需的一切,儘管我相信已經設置好所有元素的開銷很小。例如,我只有4個子視圖,每個子視圖都有1或2個文本框。 – 8vius 2012-07-10 23:47:49

+1

在我的一個iPad應用程序中,我有一個視圖控制器,它有7個子視圖可以顯示或隱藏,每個子視圖都有自己的一組控件。總共有大約60個視圖和子視圖(標籤,按鈕等)。我沒有注意到任何緩慢或猶豫,並且Profier不會在內存或CPU中發現任何巨大的峯值。顯然,你應該徹底測試你自己的解決方案,但我懷疑你會遇到問題。 – 2012-07-11 00:04:23

0

UISegmentedControl有點不同,它沒有委託協議,你必須使用「添加目標」樣式。在你的情況下,你想要做的是添加一個目標,當UISegmentedControl改變時(這可能是父視圖控制器),然後該目標可以處理標籤切換。

例如:

[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 
} 

注:這是從內存中寫入未經測試的代碼 - 請相應參考文檔。

42

注:答案與iOS視圖控制器遏制碼5+包括@接口部分

更新在我的應用程序,我有在導航欄段控制,並單擊視圖控制器「標籤」切換視圖控制器。基本思想是有一個視圖控制器的數組,並使用段索引切換它們(以及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]; 
    } 

} 
+0

真的很好的解決方案。感謝分享這個。 – Mike 2013-03-13 06:23:35

+0

@Robotic Cat:我有點困惑,爲什麼你將子視圖控制器的框架設置爲與父視圖控制器相同。這個父視圖控制器不包含UISegmentedControl嗎?如果是這樣,孩子視圖控制器不會掩蓋它嗎? – Marplesoft 2013-08-10 22:32:06

+0

@Marplesoft:通常「UISegmentedControl」位於導航欄中。顯然,如果你的'UISegmentedControl'在你的視圖控制器中,你應該將你的自動佈局約束或框架設置爲你的應用的正確值。 – 2013-08-10 23:39:08