2010-01-22 24 views
23

我试图找出“最佳”的方式来使用UISegmentedControl的iPhone应用程序。我已经在这里计算器看了几个帖子,看到几个人的想法,但我确实不能理清做到这一点的最好办法。我所指的职位是:UISegmentedControl最佳实践

Changing Views from UISegmentedControlHow do I use a UISegmentedControl to switch views?

这似乎是选项是:

  • 每个视图中添加IB和布置它们之上然后互相显示/隐藏它们
  • 在IB中分别创建每个子视图,然后在主视图中创建一个容器以填充所需的子视图
  • 建立一个真正高大或真宽UIView和动画它左/右或上/下视所选段
  • 上使用UITabBarController换出子视图 - 看来愚蠢
  • 对于表,重新加载表和cellForRowAtIndex和填充选择基于段选择不同的数据源或部分表(不适用于我的应用程序的情况下)

那么哪种方法是最好的子视图/非表格方式?哪个最容易实现?你可以分享一些示例代码的方法?

谢谢!

回答

11

我会跟你提到的第二个选项去,在IB创建子视图和进出主视图的交换他们。这将是一个很好的机会,使用UIViewController,unsubclassed:在你的初始设置,创建使用-initWithNibName:bundle:控制器(其中第一个参数是NIB的含个体子视图名称,第二个参数是nil),并添加其view为必要时您的主视图的子视图。这将有助于保持你的内存占用低:UIViewController的默认行为接收内存警告是释放其看来,如果没有上海华时。只要您从视图层次结构中删除隐藏的视图,就可以将控制器保留在内存中,而不必担心释放任何东西。

(响应编辑评论:)

你并不需要继承UIViewController,但你需要为每个视图单独XIBs。您也不需要向IB中的包含视图添加任何内容。

实例变量,在任何类处理这一切的接口:

UIViewController *controllerOne; 
UIViewController *controllerTwo; 

UIViewController *currentController; 

IBOutlet UIView *theContainerView; 

在你的设置(-applicationDidFinishLaunching:或其他)

controllerOne = [[UIViewController alloc] initWithNibName:@"MyFirstView" bundle:nil]; 
controllerTwo = [[UIViewController alloc] initWithNibName:@"MySecondView" bundle:nil]; 

要切换到控制器:

- (void)switchToController:(UIViewController *)newCtl 
{ 
     if(newCtl == currentController) 
      return; 
     if([currentController isViewLoaded]) 
      [currentController.view removeFromSuperview]; 

     if(newCtl != nil) 
      [theContainerView addSubview:newCtl.view]; 

     currentController = newCtl; 
} 

然后,只需调用带,如,

[self switchToController:controllerOne]; 
+0

只是为了澄清......你是说创建一个单独的UIViewController的.h,.M,和.xib文件在每个子视图中,在“包含”视图的viewDidLoad中实例化它们中的每一个,在IB中添加一个UIView到包含视图,然后做什么? – 2010-01-22 21:58:47

19

我在iPad应用程序中遇到过这个需求。

我来的解决方案是为 建立专门的视图控制器的视图中的每个风格来处理业务逻辑与这些观点 (即与各段),和编程添加/删除他们作为 子视图到'管理'控制器响应所选段 索引更改。

要做到这一点,必须创建一个额外的UIViewController子类,该子类管理 UISegmentedControl更改,并添加/删除子视图。

下面的代码做这一切,也采取了一些注意事项/额外的护理:

  • viewWillAppear中/ viewWillDisappear /等,都没有叫上自动子视图 ,并且需要通过告知“管理”控制器
  • viewWillAppear中/ viewWillDisappear /等,都没有叫上“管理” 控制器时,它是一个导航控制器内,因此 导航控制器委托
  • 如果你想推到导航堆栈从01以内段的子视图,因为子视图已创建在 导航层次结构之外,因此您需要回拨到'管理'视图 ,并且不会引用导航 控制器。
  • 如果在导航控制器场景中使用,后退按钮是 自动设置为段的名称。

接口:

@interface SegmentManagingViewController : UIViewController <UINavigationControllerDelegate> { 
    UISegmentedControl * segmentedControl; 
    UIViewController  * activeViewController; 
    NSArray    * segmentedViewControllers; 
} 

@property (nonatomic, retain) IBOutlet UISegmentedControl * segmentedControl; 
@property (nonatomic, retain) UIViewController   * activeViewController; 
@property (nonatomic, retain) NSArray      * segmentedViewControllers; 

@end 

实现:

@interface SegmentManagingViewController() 
- (void)didChangeSegmentControl:(UISegmentedControl *)control; 
@end 

@implementation SegmentManagingViewController 

@synthesize segmentedControl, activeViewController, segmentedViewControllers; 

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    UIViewController * controller1 = [[MyViewController1 alloc] initWithParentViewController:self]; 
    UIViewController * controller2 = [[MyViewController2 alloc] initWithParentViewController:self]; 
    UIViewController * controller3 = [[MyViewController3 alloc] initWithParentViewController:self]; 

    self.segmentedViewControllers = [NSArray arrayWithObjects:controller1, controller2, controller3, nil]; 
    [controller1 release]; 
    [controller2 release]; 
    [controller3 release]; 

    self.navigationItem.titleView = self.segmentedControl = 
    [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:@"Seg 1", @"Seg 2", @"Seg 3", nil]]; 
    self.segmentedControl.selectedSegmentIndex = 0; 
    self.segmentedControl.segmentedControlStyle = UISegmentedControlStyleBar; 

    [self.segmentedControl addTarget:self action:@selector(didChangeSegmentControl:) forControlEvents:UIControlEventValueChanged]; 

    [self didChangeSegmentControl:self.segmentedControl]; // kick everything off 
} 

- (void)viewWillAppear:(BOOL)animated { 
    [super viewWillAppear:animated]; 
    [self.activeViewController viewWillAppear:animated]; 
} 

- (void)viewDidAppear:(BOOL)animated { 
    [super viewDidAppear:animated]; 
    [self.activeViewController viewDidAppear:animated]; 
} 

- (void)viewWillDisappear:(BOOL)animated { 
    [super viewWillDisappear:animated]; 
    [self.activeViewController viewWillDisappear:animated]; 
} 

- (void)viewDidDisappear:(BOOL)animated { 
    [super viewDidDisappear:animated]; 
    [self.activeViewController viewDidDisappear:animated]; 
} 

#pragma mark - 
#pragma mark UINavigationControllerDelegate control 

// Required to ensure we call viewDidAppear/viewWillAppear on ourselves (and the active view controller) 
// inside of a navigation stack, since viewDidAppear/willAppear insn't invoked automatically. Without this 
// selected table views don't know when to de-highlight the selected row. 

- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated { 
    [viewController viewDidAppear:animated]; 
} 

- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated { 
    [viewController viewWillAppear:animated]; 
} 

#pragma mark - 
#pragma mark Segment control 

- (void)didChangeSegmentControl:(UISegmentedControl *)control { 
    if (self.activeViewController) { 
     [self.activeViewController viewWillDisappear:NO]; 
     [self.activeViewController.view removeFromSuperview]; 
     [self.activeViewController viewDidDisappear:NO]; 
    } 

    self.activeViewController = [self.segmentedViewControllers objectAtIndex:control.selectedSegmentIndex]; 

    [self.activeViewController viewWillAppear:NO]; 
    [self.view addSubview:self.activeViewController.view]; 
    [self.activeViewController viewDidAppear:NO]; 

    NSString * segmentTitle = [control titleForSegmentAtIndex:control.selectedSegmentIndex]; 
    self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:segmentTitle style:UIBarButtonItemStylePlain target:nil action:nil]; 
} 

#pragma mark - 
#pragma mark Memory management 

- (void)dealloc { 
    self.segmentedControl = nil; 
    self.segmentedViewControllers = nil; 
    self.activeViewController = nil; 
    [super dealloc]; 
} 

@end 

希望这有助于。

+1

注册成功!在-didChangeSegmentedControl:方法中有一个小的内存泄漏。最后一条语句应该是:self.navigationItem.backBarButtonItem = [[[UIBarButtonItem alloc] initWithTitle:segmentTitle style:UIBarButtonItemStylePlain target:nil action:nil] autorelease];类似的内存泄漏在viewDidLoad中:self.navigationItem.titleView = self.segmentedControl = [[[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:@“Seg 1”,@“Seg 2”,@“Seg 3”,nil ]] autorelease]; – Mustafa 2010-09-01 04:49:19

+0

添加一个链接到我发布的关于这个模式的进一步更新 - 使用UINavigationController而不是'容器'视图控制器。 HTTP:// redartisan。2010/6/27/uisegmented-control-view-switching-revisited – crafterm 2011-03-07 07:00:39

+0

由于某些原因,当我在iPad上使用此功能时,细节部分无法正确调整大小,就好像视图正在以完整的iPad纵向绘制。 – Convolution 2011-07-28 13:18:28