我正在努力找出将UISegmentedControl
用于iPhone应用程序的“最佳”方式。我已经在stackoverflow上阅读了一些帖子并看到了一些人的想法,但我无法理清这样做的最佳方法。我所指的帖子是:
Changing Views from UISegmentedControl 和 How do I use a UISegmentedControl to switch views?
似乎选项是:
UIView
,并根据所选片段左/右或上/下制作动画UITabBarController
换出子视图 - 似乎很傻cellForRowAtIndex
中,并根据所选的段选项(不适用于我的应用程序)从不同的数据源或部分填充表格。那么哪种方法最适合子视图/非表方法?哪个最容易实现?你能分享一些示例代码吗?
谢谢!
答案 0 :(得分:19)
我在iPad应用程序中也遇到过这个要求。
我遇到的解决方案是为其创建专门的视图控制器 每种视图样式,用于处理与这些视图相关的业务逻辑 (即与每个段相关),并以编程方式添加/删除它们 子视图到“管理”控制器以响应所选段 指数变化。
要做到这一点,必须创建一个管理的额外UIViewController子类 UISegmentedControl更改,并添加/删除子视图。
下面的代码完成了所有这些,还要注意一些注意事项/附加内容:
接口:
@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 :(得分:11)
我会选择你提到的第二个选项,在IB中创建子视图并将它们交换进主视图。这将是一个很好的机会使用UIViewController
,未经分类:在初始设置中,使用-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];
答案 2 :(得分:3)
这是一个很好的教程,可以进一步解释这个概念:http://redartisan.com/2010/5/26/uisegmented-control-view-switching
和它的github位置:https://github.com/crafterm/SegmentedControlExample.git