【问题标题】:Switching ViewControllers with UISegmentedControl in iOS5在 iOS5 中使用 UISegmentedControl 切换 ViewController
【发布时间】:2012-02-25 00:05:00
【问题描述】:

我正在尝试一些非常简单的方法,但不知何故我无法让它工作。我所要做的就是使用 UISegmentedControl 在 2 个视图控制器之间切换,例如,您可以在 App Store 应用程序的 Highlights 选项卡中看到它。

我正在使用 iOS5 和 Storyboards。

这是我的故事板系列:

所以我有一个根视图控制器和两个 UITableViews - 这两个 TableViews 我想切换。

实现文件如下所示

#import "SegmentedLocationViewController.h"
#import "PastEventsLocationViewController.h"
#import "FutureEventsLocationViewController.h"

@interface SegmentedLocationViewController()
@property (weak, nonatomic) IBOutlet UISegmentedControl *segmentedControl;
@property (strong, nonatomic) NSArray *viewControllers;
@end


@implementation SegmentedLocationViewController

@synthesize segmentedControl = _segmentedControl;
@synthesize viewControllers = _viewControllers;

- (IBAction)indexDidChangeForSegmentedControl:(UISegmentedControl*)segmentedControl
{
    NSLog(@"index: %d", segmentedControl.selectedSegmentIndex);
}

- (void)setupViewControllers
{
    PastEventsLocationViewController *pastEventsLocationViewController = [[PastEventsLocationViewController alloc] initWithStyle:UITableViewStylePlain];
    FutureEventsLocationViewController *futureEventsLocationViewController = [[FutureEventsLocationViewController alloc] initWithStyle:UITableViewStylePlain];

    self.viewControllers = [NSArray arrayWithObjects:pastEventsLocationViewController, futureEventsLocationViewController, nil];
}

- (void)setupUI
{
    [self.segmentedControl addTarget:self action:@selector(indexDidChangeForSegmentedControl:) forControlEvents:UIControlEventValueChanged];
}

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

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return YES;
}

@end

我可以触发 switch 事件并且可以记录当前选择的索引。但我不知道从这里去哪里。

也许有人可以将我的注意力转向某个方向...?

【问题讨论】:

  • 你有没有想过只用不同的值重新加载 tableView?
  • 你是对的。我现在会检查一下。我可能觉得太复杂了……

标签: ios uiviewcontroller uikit uisegmentedcontrol


【解决方案1】:

我最终使用导航控制器来实现类似的功能。

import UIKit

class BaseViewController: UIViewController {

  var currentSegmentIndex = 0

  @IBOutlet weak var segmentedControl: UISegmentedControl!

  override func viewDidLoad() {
    super.viewDidLoad()

    segmentedControl.selectedSegmentIndex = currentSegmentIndex
  }

  @IBAction func segmentedControlChanged(_ sender: Any) {
    let idx = segmentedControl.selectedSegmentIndex
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    switch idx {
    case 0:
      let vc = storyboard.instantiateViewController(
        withIdentifier: "Foo") as! FooViewController
      vc.currentSegmentIndex = 0
      navigationController?.viewControllers = [vc]
      break
    case 1:
      let vc = storyboard.instantiateViewController(
        withIdentifier: "Bar") as! BarViewController
      vc.currentSegmentIndex = 1
      navigationController?.viewControllers = [vc]
      break
    default:
      break
    }
  }
}

【讨论】:

    【解决方案2】:

    A 是根视图控制器,B、C 是子视图控制器。 当你点击段时,添加子视图控制器。

    结果

    设计

    代码

    import UIKit
    
    class SegmentViewController: UIViewController {
    
        @IBOutlet weak var containerView: UIView!
    
        var leftViewController: LeftViewController!
        var rightViewController: RightViewController!
    
    
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view, typically from a nib.
    
            if let sb = storyboard {
                leftViewController = sb.instantiateViewControllerWithIdentifier("leftViewController") as! LeftViewController
    
                switchViewController(from: nil, to: leftViewController)
            } else {
                print("storyboard is nil")
            }
        }
    
        func switchViewController(from fromVC: UIViewController?, to toVC: UIViewController?) {
            if let from = fromVC {
                from.willMoveToParentViewController(nil)
                from.view.removeFromSuperview()
                from.removeFromParentViewController()
            } else {
                print("fromVC is nil")
            }
    
            if let to = toVC {
                self.addChildViewController(to)
                to.view.frame = CGRectMake(0, 0, containerView.frame.width, containerView.frame.height)
                self.containerView.insertSubview(to.view, atIndex: 0)
                to.didMoveToParentViewController(self)
            } else {
                print("toVC is nil")
            }
        }
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            // Dispose of any resources that can be recreated.
    
            removeViewController()
        }
    
        func removeViewController() {
            if let leftVC = leftViewController {
                if let _ = leftVC.parentViewController {
                    print("leftVC is using")
                } else {
                    print("set leftVC = nil")
                    leftViewController = nil
                }
            }
    
            if let rightVC = rightViewController {
                if let _ = rightVC.parentViewController {
                    print("rightVC is using")
                } else {
                    print("set rightVC = nil")
                    rightViewController = nil
                }
            }
        }
    
    
        @IBAction func onSegmentValueChanged(sender: UISegmentedControl) {
            UIView.beginAnimations("xxx", context: nil)
            UIView.setAnimationDuration(0.4)
            UIView.setAnimationCurve(.EaseInOut)
    
            switch sender.selectedSegmentIndex {
            case 0:
                UIView.setAnimationTransition(.FlipFromRight, forView: self.containerView, cache: true)
    
                if let leftVC = leftViewController {
                    switchViewController(from: rightViewController, to: leftVC)
                } else {
                    if let sb = storyboard {
                        leftViewController = sb.instantiateViewControllerWithIdentifier("leftViewController") as! LeftViewController
                        switchViewController(from: rightViewController, to: leftViewController)
                    } else {
                        print("storyboard is nil")
                    }
                }
            default:
                UIView.setAnimationTransition(.FlipFromLeft, forView: self.containerView, cache: true)
    
                if let rightVC = rightViewController {
                    switchViewController(from: leftViewController, to: rightVC)
                } else {
                    if let sb = storyboard {
                        rightViewController = sb.instantiateViewControllerWithIdentifier("rightViewController") as! RightViewController
                        switchViewController(from: leftViewController, to: rightViewController)
                    } else {
                        print("storyboard is nil")
                    }
                }
            }
    
            UIView.commitAnimations()
        }
    }
    

    【讨论】:

      【解决方案3】:

      对于想要快速实现相同功能的人

      import UIKit
      
      class HomeController: UIViewController {
      
          var currentViewController:UIViewController?
      
          @IBOutlet weak var homeController: UIView!
      
          override func viewDidLoad() {
              super.viewDidLoad()
      
              let initialController:UIViewController = self.viewControllerForSegmentedIndex(0)
      
              self.addChildViewController(initialController)
      
              initialController.view.frame = self.homeController.bounds
              self.homeController.addSubview(initialController.view)
              self.currentViewController = initialController
      
          }
      
          @IBAction func segmentChanged(sender: UISegmentedControl) {
      
              let viewCOntroller:UIViewController = viewControllerForSegmentedIndex(sender.selectedSegmentIndex)
      
              self.addChildViewController(viewCOntroller)
      
              self.transitionFromViewController(self.currentViewController!, toViewController: viewCOntroller, duration: 0.5, options: UIViewAnimationOptions.TransitionFlipFromBottom, animations: {
                  self.currentViewController?.view.removeFromSuperview()
                  viewCOntroller.view.frame = self.homeController.bounds
                  self.homeController.addSubview(viewCOntroller.view)
      
                  }, completion:{ finished in
      
                      viewCOntroller.didMoveToParentViewController(self)
                      self.currentViewController?.removeFromParentViewController()
                      self.currentViewController = viewCOntroller
      
              })
      
          }
          func viewControllerForSegmentedIndex(index:Int) -> UIViewController {
              var viewController:UIViewController?
              switch index {
              case 0:
                  viewController = self.storyboard?.instantiateViewControllerWithIdentifier("StoryboardIdForFirstController")
                  break
              case 1:
                  viewController = self.storyboard?.instantiateViewControllerWithIdentifier("StoryboardIdForSecondController")
                  break
              case 2:
                  viewController = self.storyboard?.instantiateViewControllerWithIdentifier("StoryboardIdForThirdController")
                  break
              default:
                  break
              }
              return viewController!
          }
      }
      

      故事板视图

      【讨论】:

        【解决方案4】:

        这是 Matthias Bauch 的解决方案,但还是想在 Swift 中分享它! 编辑: 添加指向 Swift 2.0 现成演示应用程序的链接。 https://github.com/ahmed-abdurrahman/taby-segmented-control

        var currentViewController: UIViewController?
        @IBOutlet weak var contentView: UIView!
        @IBOutlet weak var segmentedControl: UISegmentedControl!
        
        @IBAction func switchHappeningTabs(sender: UISegmentedControl) {
            if let vc = viewControllerForSelectedSegmentIndex(sender.selectedSegmentIndex) {
                self.addChildViewController(vc)
                self.transitionFromViewController(self.currentViewController!, toViewController: vc, duration: 0.5, options: UIViewAnimationOptions.TransitionFlipFromRight, animations: {
                    self.currentViewController!.view.removeFromSuperview()
                    vc.view.frame = self.contentView.bounds
                    self.contentView.addSubview(vc.view)
                    }, completion: { finished in
                        vc.didMoveToParentViewController(self)
                        self.currentViewController!.removeFromParentViewController()
                        self.currentViewController = vc
                    }
                )        
            }
        }
        
        override func viewDidLoad() {
            super.viewDidLoad()
        
            if let vc = self.viewControllerForSelectedSegmentIndex(self.segmentedControl.selectedSegmentIndex) {
                self.addChildViewController(vc)
                self.contentView.addSubview(vc.view)
                self.currentViewController = vc
            }
        }
        
        func viewControllerForSelectedSegmentIndex(index: Int) -> UIViewController? {
            var vc: UIViewController?
            switch index {
            case 0:
                    vc = self.storyboard?.instantiateViewControllerWithIdentifier("FooViewController") as? UIViewController
            case 1:
                    vc = self.storyboard?.instantiateViewControllerWithIdentifier("BarViewController") as? UIViewController
            default:
                return nil
            }
        
            return vc
        }
        

        【讨论】:

        • 非常感谢!这让我很开心:)
        • 当然,这是我的荣幸 :)
        【解决方案5】:

        此代码非常适合您的目的,我将它用于我的一个新应用程序。
        它使用新的 UIViewController 包含 API,允许在您自己的 UIViewController 中使用 UIViewController,而无需手动转发 viewDidAppear: 等内容的麻烦

        - (void)viewDidLoad {
            [super viewDidLoad];
            // add viewController so you can switch them later. 
            UIViewController *vc = [self viewControllerForSegmentIndex:self.typeSegmentedControl.selectedSegmentIndex];
            [self addChildViewController:vc];
            vc.view.frame = self.contentView.bounds;
            [self.contentView addSubview:vc.view];
            self.currentViewController = vc;
        }
        - (IBAction)segmentChanged:(UISegmentedControl *)sender {
            UIViewController *vc = [self viewControllerForSegmentIndex:sender.selectedSegmentIndex];
            [self addChildViewController:vc];
            [self transitionFromViewController:self.currentViewController toViewController:vc duration:0.5 options:UIViewAnimationOptionTransitionFlipFromBottom animations:^{
                [self.currentViewController.view removeFromSuperview];
                vc.view.frame = self.contentView.bounds;
                [self.contentView addSubview:vc.view];
            } completion:^(BOOL finished) {
                [vc didMoveToParentViewController:self];
                [self.currentViewController removeFromParentViewController];
                self.currentViewController = vc;
            }];
            self.navigationItem.title = vc.title;
        }
        
        - (UIViewController *)viewControllerForSegmentIndex:(NSInteger)index {
            UIViewController *vc;
            switch (index) {
                case 0:
                    vc = [self.storyboard instantiateViewControllerWithIdentifier:@"FooViewController"];
                    break;
                case 1:
                    vc = [self.storyboard instantiateViewControllerWithIdentifier:@"BarViewController"];
                    break;
            }
            return vc;
        }
        

        我从 Ray Wenderlich 的书 iOS5 by tutorial 的第 22 章中得到了这些东西。 不幸的是,我没有指向教程的公共链接。但是有一个 WWDC 2011 视频,标题为“实现 UIViewController Containment”

        编辑

        self.typeSegmentedControl 是您的UISegmentedControl 的出口

        self.contentView 是您的容器视图的出口

        self.currentViewController 只是我们用来存储我们当前使用的UIViewController 的一个属性

        【讨论】:

        • 我没有使用情节提要完成它,但是当我将您的代码与 nib 文件一起使用时,它可以工作......所以谢谢你得到我的投票;)
        • 这个摇滚男人。 2 个月后我才发现 [self storyboard]。谢谢!!
        • 这似乎是一个愚蠢的问题,但是当从头开始时,我会遇到诸如在“ViewController *”类型的对象上找不到此属性“typeSegmentedControl”之类的问题,我可能正在做一些愚蠢的事情我
        • 你必须为typeSegmentedControl添加@property (UISegmentedControl)
        • 我将vc.view.frame = self.contentView.bounds;移到了动画块之外,以避免在过渡期间子视图超出 contentView 的边界,否则会导致闪烁。
        【解决方案6】:

        您可以将初始视图控制器嵌入到导航控制器中。通过选择情节提要中的视图控制器,然后选择编辑器->嵌入->导航控制器来做到这一点。

        在您的 indexDidChangeForSegmentedControl: 方法中,您只需将相应的视图控制器推送到导航堆栈:

        - (IBAction)indexDidChangeForSegmentedControl:(UISegmentedControl*)segmentedControl
        {
            [self.navigationController pushViewController:[self.viewControllers objectAtIndex:[segmentedControl.selectedIndex]] animated:YES];
        
        }
        

        但是当您使用情节提要时,您的方法根本没有多大意义。 我不知道您是否可以使用 segue 将单个分段控制按钮连接到视图控制器。试试看吧。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-08-22
          • 2015-09-23
          • 2011-07-13
          • 2012-05-15
          相关资源
          最近更新 更多