我建立一个位置的应用程序,显示用户身边的一些地方。
我有一个NearbyPlacesViewController
与有两个按钮“列表”和“地图”段控制
如果“列表”用户按 - 我告诉他,他周围的地方列表中的表视图
如果用户按“图” - 视图翻转周围,我展示给用户在其上的地方作为引脚一个MapView。
在“清单”我也用一个UISearchBar和UISearchDisplayController搜索的tableView
在“地图”我也有MapView类之外的其他子视图
目前,我把所有的意见( UITableView, MKMapView, UISearchBar
更多...)
和委托方法( UITableViewDelegate, UITableViewDataSource, MKMapViewDelegate, UISearchDisplayDelegate
,以及更多......)
在NearbyPlacesViewController
。
当“地图”按钮,我隐藏所有的意见,相关的“列表”视图(的tableView,搜索栏...),我取消隐藏所有的意见,相关的“地图”查看用户按(MapView类,其他一些子视图...),然后我用UIView transitionWithView
做他们之间翻转动画。
一切正常,但似乎有点乱,结果是一个大NearbyPlacesViewController了大量的代码和委托方法。
它是更好地与独立viewControllers办呢?
如果是这样,我怎么办呢? 我创建ListViewController和MapViewController中,并把它们放在一个NearbyViewController?
如何在它们之间共享的模式?
只要你得到一个什么样的视图控制器遏制可能看起来像(iOS 5中)从某种意义上说,这是做这件事。 它由四个类的,容器视图控制器(其视图将具有用于两个子视图控制器之间进行切换的分段控制),两个随机子视图控制器和一个模型类,我们会在存储(其可以由被访问的数据两个子视图控制器)。
首先创建一个容器视图控制器与分段控制(我还加一个UIView基本上定义了子视图控制器的意见将被放置在框架,只是为了更容易地找出哪里把这一观点):
// ContainerViewController.h
#import <UIKit/UIKit.h>
@interface ContainerViewController : UIViewController
@property (weak, nonatomic) IBOutlet UISegmentedControl *segmentedControl;
@property (weak, nonatomic) IBOutlet UIView *childView;
- (IBAction)changeChild:(id)sender;
@end
然后你实现它:
// ContainerViewController.m
#import "ContainerViewController.h"
#import "FirstContainedViewController.h"
#import "SecondContainedViewController.h"
#import "MyModel.h"
@interface ContainerViewController ()
{
FirstContainedViewController *_controller0;
SecondContainedViewController *_controller1;
MyModel *_model;
UIViewController __weak *_currentChildController; // let's keep track of the current
}
@end
@implementation ContainerViewController
@synthesize segmentedControl = _segmentedControl;
@synthesize childView = _childView;
- (void)dealloc
{
// let's release our child controllers
_controller0 = nil;
_controller1 = nil;
// and release the model, too
_model = nil;
}
// this is my own method to
// 1. add the child view controller to the view controller hierarchy;
// 2. do the appropriate notification (even though I don't use it, Apple says you should do this, so I will); and
// 3. set the frame size to the appropriate size
- (void)addChildToThisContainerViewController:(UIViewController *)childController
{
[self addChildViewController:childController];
[childController didMoveToParentViewController:self];
childController.view.frame = CGRectMake(0.0,
0.0,
self.childView.frame.size.width,
self.childView.frame.size.height);
}
- (void)viewDidLoad
{
[super viewDidLoad];
// let's create our model, our data
_model = [[MyModel alloc] init];
// set the segmented index to point to the first one
[self.segmentedControl setSelectedSegmentIndex:0];
// let's create our two controllers and provide each a pointer to our model
_controller0 = [[FirstContainedViewController alloc] initWithNibName:@"FirstContainedView" bundle:nil];
_controller0.model = _model;
_controller1 = [[SecondContainedViewController alloc] initWithNibName:@"SecondContainedView" bundle:nil];
_controller1.model = _model;
// let's add them to the view controller hierarchy
[self addChildToThisContainerViewController:_controller0];
[self addChildToThisContainerViewController:_controller1];
// let's add the currently selected controller as the "current child controller" and add it to our current view
_currentChildController = [self.childViewControllers objectAtIndex:self.segmentedControl.selectedSegmentIndex];
[self.childView addSubview:_currentChildController.view];
}
- (void)viewDidUnload
{
[self setChildView:nil];
[self setSegmentedControl:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (IBAction)segmentedControlValueChanged:(UISegmentedControl *)sender
{
UIViewController *oldChildController = _currentChildController;
UIViewController *newChildController = [self.childViewControllers objectAtIndex:sender.selectedSegmentIndex];
UIViewAnimationOptions options;
// let's change the animation based upon which segmented control you select ... you may change this as fits your desired UI
if (sender.selectedSegmentIndex == 0)
options = UIViewAnimationOptionTransitionFlipFromLeft;
else
options = UIViewAnimationOptionTransitionFlipFromRight;
[self transitionFromViewController:oldChildController
toViewController:newChildController
duration:0.5
options:options
animations:nil
completion:nil];
_currentChildController = newChildController;
}
@end
我的模型只是有两个数据元素,对象数组和字符串,但很明显,你可以做任何你想要的。 我将只显示标题(如实施细节是微乎其微的,无趣的):
// MyModel.h
#import <Foundation/Foundation.h>
@interface MyModel : NSObject
@property (nonatomic, strong) NSMutableArray *listOfItems;
@property (nonatomic, strong) NSString *displayText;
- (MyModel *)init;
@end
和子视图控制器也同样简单:
// FirstContainedViewController.h
#import <UIKit/UIKit.h>
@class MyModel;
@interface FirstContainedViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
@property (nonatomic, weak) MyModel *model;
@end
和实现可能看起来像(这是一个简单的例子,但说明如何检索来自共享模型的信息):
// FirstContainedViewController.m
#import "FirstContainedViewController.h"
#import "MyModel.h"
@implementation FirstContainedViewController
@synthesize model = _model;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark - tableview data source delegate methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.model.listOfItems count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = @"fcvc";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell)
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
cell.textLabel.text = [self.model.listOfItems objectAtIndex:indexPath.row];
return cell;
}
@end
但愿这给你的,你怎么可能使用不同的视图控制器为你的两个观点从某种意义上说,如何在它们之间切换,让你的模型都可以访问。 这是一个相当简单的例子,但它的功能。 有一些优化,我可能会建议,但希望这是足以让你在正确的方向前进。
当与segmentedControl处理这是我如何在过去做到了。 您可能能够创建一个单独的控制器类来处理一切的基础模型,并清理出一些代码,但是这其实只是取决于你想多远,走了。
想想ModelViewController。 如果他们是真正只有您之间切换视图,使用一个UIViewController中是合适的,这就是我通常做分段控制,因为它通常归结为各地电流控制器的视图切换。 控制器一定要处理IBAction为对分段的控制。
代表和数据源的意思是提取到一个单独的类时,它是有道理的,对你来说它。 我会考虑你正在使用的各种代表不同的类别,这将显著清理,同时也坚持贴近设计原则苹果打算。 你可以在自己的班级保持的UITableView委托和数据源一起,但除此之外,创建针对每个不同的委托一个独立的类会显著清理。
独立的视图控制器可能是要走一个更合适的方法。 我喜欢他们。 也意味着你可以做出初步视图控制器的父母给了别人,并奠定了你有各种意见和subvuews父的意见添加您的孩子视图控制器为,当他们的需要。 也可以更容易地添加一些自定义动画或在稍后的日期继电器输出。
在我看来,最好的办法是有三个视图控制器和它们之间创建模态塞格斯。 (我假设你使用故事板)。你必须有两个孩子(名单及地图)父视图控制器。
(1)在你的故事板(即具有ParentViewController,ListViewController&MapViewController中)从每个键子的VC创建模式Segue公司。 给他们标识符(showList&showMap将工作做好),并选择转型:水平翻转。
建立协议和代表:(我会告诉你如何做一个,然后就重复了)
(2a)中在ListViewController.h添加上述@interface:
@class ListViewController;
@protocol ListViewControllerDelegate
- (void)listViewControllerDidFinish:(ListViewController *)controller;
@end
(2b)的添加委托作为一个属性:
@property (weak, nonatomic) id <ListViewControllerDelegate> delegate;
(3A)在ListViewController.m合成:
@synthesize delegate;
(3b)和在IBAction为按钮的方法来翻转回代表:
- (IBAction)flipBack:(id)sender
{
[self.delegate ListViewControllerDidFinish:self];
}
(4)在添加ParentViewController.h在最高层#import "ListViewController.h"
和@interface的端<ListViewControllerDelegate>
(5A)在ParentViewController.m添加方法,以符合协议:
- (void)listViewControllerFinish:(ListViewController *)controller
{
[self dismissModalViewControllerAnimated:YES];
}
(5b)中然后将其设置为在prepareForSegue委托:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:@"showList"]) {
[[segue destinationViewController] setDelegate:self];
}
}