2012-06-23 99 views
1

我正在構建一個位置應用程序,向用戶顯示他周圍的一些地方。
我對此有兩個按鈕「列表」和「地圖」目標c - 使用一個ViewController或更多ViewController翻轉視圖?

段控制NearbyPlacesViewController如果「列表」用戶按 - 我告訴他的地方名單表視圖圍繞在他
如果用戶按下「地圖」 - 視圖翻轉,我向用戶顯示一個mapView,其上的位置作爲引腳。

在「清單」我也用一個UISearchBar和UISearchDisplayController搜索的tableView
在「地圖」我也有MapView類之外的其他子視圖

目前,我把所有的意見(UITableView, MKMapView, UISearchBar多...)
和代表方法(UITableViewDelegate, UITableViewDataSource, MKMapViewDelegate, UISearchDisplayDelegate,等等..)
NearbyPlacesViewController

當用戶按下「地圖」按鈕時,我隱藏了與「列表」視圖(tableView,搜索欄...)有關的所有視圖,並且我取消了與「地圖」相關的所有視圖視圖(mapView,一些其他子視圖...),然後我使用UIView transitionWithView在它們之間做翻轉動畫。

一切正常,但似乎有點混亂,結果是一個很大的代碼和委託方法的大NearbyPlacesViewController。

使用單獨的viewControllers做更好嗎?
如果是這樣,我該怎麼做?創建ListViewController和MapViewController並將它們放在NearbyViewController中?
我該如何分享他們之間的模型?

回答

2

在處理分段控件時,這是我過去的做法。你可能能夠創建一個單獨的控制器類來處理所有事情的底層模型,並清除一些代碼,但這實際上取決於你想要實現的目標。

1

Think ModelViewController。如果它們確實只是您要切換的視圖,那麼使用一個UIViewController是適當的,這就是我通常對分段控件所做的事情,因爲它通常涉及切換當前控制器的視圖。控制器應該明確處理分段控制的IBAction。

代表和數據源意味着當它有意義時被提取到一個單獨的類中,並且在您的情況下它是這樣。我會爲您使用的各種代表考慮單獨的課程,這將顯着地清除它,同時也堅持接近Apple所設計的原則。您可以將UITableView委託和數據源保存在自己的類中,但除此之外,爲每個不同的委託創建單獨的類將會清除它們。

+0

我從來沒有使用這種方法的單獨的類爲tableViews委託或數據源,總是父視圖控制器。如果我這樣做,我在哪裏保持我的模型?它會在viewController中持有tableView的實例,還是在datasource委託類中? – Eyal

+0

MVC純粹主義者會告訴你控制器應該管理模型。在實踐中,我可以將對模型的引用傳遞給委託和數據源(所以來自委託self.listModel),而不是通過控制器引用它(如self.owningController.listModel)。從技術上講,你既可以做到這一點,也可以嘗試兩種方式,看看你感覺更好。注意保留週期。 –

1

單獨的視圖控制器可能是一個更好的方式去。我更喜歡他們。也意味着您可以將初始視圖控制器設置爲其他視圖控制器,並展示您獲得的各種視圖,並將子視圖控制器作爲子視圖添加到父視圖的視圖中。此外,還可以更輕鬆地添加一些自定義動畫或在以後重新播出。

3

幾個選項我撲過來:

  1. 如果使用UISegmentedControl,你可以有兩個UIView對象爲你的兩個屏幕(您可以在Interface Builder創建它們或以編程方式構建它們)和那麼你可以隱藏/顯示或當你在它們之間跳轉時跳轉或跳轉。由於所有數據都將由您的單個視圖控制器進行管理,因此這非常簡單。但是,如果這兩個子視圖變得非常複雜,那麼這個視圖控制器可能會變得非常多毛。但應該可以正常工作。如果你想要單獨的視圖控制器,你可能會追求iOS 5的視圖控制器遏制(參見UIViewController參考中的Implementing a Container View Controller,或參見WWDC 2011 session 102),儘管這有點複雜。您可以將數據存儲爲容器視圖控制器的屬性,這些屬性可傳遞給子控制器或由其引用。

  2. 如果你沒有連接到分段控制UI,你可以使用UITabBarController這非常適合這種情況(它實際上是前一個選項的排列,但是容器視圖控制器,標籤欄控制器在這種情況下,已經爲你寫了)。對於每個的兩個視圖中的一個視圖控制器,並存儲該數據要麼在UITabBarController自定義類,一個單,一些持久性存儲器(比如用戶的默認值,核心數據,SQLite的)等

+0

目前我使用選項1,問題是如果我想例如只顯示在其他地方(其他選項卡)的列表視圖,我不能重用相同的viewController。我需要創建一個沒有地圖視圖的新viewController,它共享很多代碼。 – Eyal

+0

@Eyal我不知道我是否理解了這個問題:假設你正在做選項1,爲什麼你需要另一個沒有地圖視圖的視圖控制器?爲什麼不使用相同的視圖控制器,但不讓用戶轉到地圖視圖(例如,禁用分段控件,隱藏地圖等)?或者你想獨立的視圖控制器,只是想知道如何共享數據? – Rob

1

以我看來,你最好的選擇將是有三個視圖控制器,並創建他們之間的模態段。 (我假設你使用的是故事板。)你可以讓你的父視圖控制器有兩個孩子(列表&地圖)。 (1)在你的故事板(包含ParentViewController,ListViewController & MapViewController)中,創建一個從每個按鈕到子VC的模態塞格。給他們標識符(showList & showMap會很好)並選擇Transition:Flip Horizo​​ntal。

建立協議和代表:(我會告訴你如何做一個,然後就重複了)

(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中。米添加方法,以符合協議:

- (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]; 
    } 
} 
3

只要你得到一個什麼樣的視圖控制器遏制可能看起來像感(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 

希望這給你的,你怎麼可能使用不同的看法感兩個視圖的控制器,如何在它們之間切換,使您的模型都可以訪問。這是一個相當簡單的例子,但它是功能性的。我可能會提出一些優化建議,但希望這足以讓您朝着正確的方向前進。

+0

嗨@Rob,我不小心偶然從你的另一個答案中找到了關於「加載視圖實例的segue」的答案。無論如何,我正在尋找處理我的情況的好方法,似乎我需要走這條路(我不太確定)。我正在尋求關於我發佈http:// stackoverflow這個問題的建議。com/questions/14939510/ipad-uisplitview-passing-data-from-masterviewcontroller -a-uiviewcontroller/14940148#14940148 ...如果你有時間。謝謝! – gdubs

相關問題