我正在尝试找出使用UISegmentedControl
iPhone应用程序的"最佳"方式.我已经在stackoverflow上阅读了一些帖子并看到了一些人的想法,但我无法理清这样做的最佳方法.我所指的帖子是:
从UISegmentedControl更改视图 以及 如何使用UISegmentedControl切换视图?
似乎选项是:
在IB中添加每个视图并将它们叠加在一起然后显示/隐藏它们
在IB中单独创建每个子视图,然后在主视图中创建一个容器,以填充所需的子视图
设置一个非常高或非常宽,UIView
并根据所选的段左/右或上/下动画
用a UITabBarController
来换掉子视图 - 看起来很傻
对于表,重新加载表并cellForRowAtIndex
根据所选的段选项从不同的数据源或部分填充表(不是我的应用程序的情况)
那么哪种方法最适合子视图/非表格方法?哪个最容易实现?你能分享一些示例代码吗?
谢谢!
我在iPad应用程序中也遇到过这个要求.
我遇到的解决方案是为每种视图样式创建专用的视图控制器,以处理与这些视图相关的业务逻辑(即与每个段相关),并以编程方式将它们作为子视图添加/删除到"管理"控制器以响应选定的段索引更改.
要做到这一点,必须创建一个额外的UIViewController子类来管理UISegmentedControl更改,并添加/删除子视图.
下面的代码完成了所有这些,还要注意一些注意事项/附加内容:
viewWillAppear/viewWillDisappear/etc,不会自动在子视图上调用,需要通过'manage'控制器告知
viewWillAppear/viewWillDisappear/etc,当它在导航控制器中时,不会在"管理"控制器上调用,因此导航控制器委托
如果您想从段的子视图中推送到导航堆栈,则需要回到"管理"视图来执行此操作,因为子视图已在导航层次结构之外创建,并且不会对导航控制器的引用.
如果在导航控制器方案中使用,则后退按钮将自动设置为段的名称.
接口:
@interface SegmentManagingViewController : UIViewController{ 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
希望这可以帮助.
我会选择你提到的第二个选项,在IB中创建子视图并将它们交换进主视图.这将是一个很好的机会使用UIViewController
,unsubclassed:在初始设置中,创建一个控制器使用-initWithNibName:bundle:
(其中第一个参数是包含单个子视图的NIB的名称,第二个参数是nil
)并将其添加view
为您的子视图必要时的主要观点.这将有助于保持低内存占用率:UIViewController
接收内存警告时的默认行为是在没有超级视图的情况下释放其视图.只要从视图层次结构中删除隐藏视图,就可以将控制器保留在内存中,而不必担心释放任何内容.
(编辑以回应评论:)
您不需要子类UIViewController
,但每个视图都需要单独的XIB.您也不需要在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];