2011-06-05 24 views
1

我有一個viewController顯示使用tableview查詢的結果)。 通過在一行上粘貼我推一個childView,我設置了一個導航條,其中包含右側的兩個按鈕(上一個/下一個)。 我的問題是: 當我點擊上一個或下一個按鈕時,如何切換到上一個或下一個「childView」? 我想在視圖切換時也有一個過渡效果? 有什麼幫助嗎?Iphone導航到上一個/下一個viewController

回答

3

我有一個觀點,包含一個陣營的列表,並觸摸一個用戶到陣營的細節。我想允許用戶左右滑動以瀏覽顯示每個細節的營地列表。我想要一個顯示滑動的可視化動畫,並且「返回」按鈕始終指向移回導航堆棧,即返回列表。

具有結果表的第一個視圖是唯一知道「上一個」和「下一個」是什麼意思的對象,因此他們將負責實施滑動操作。由於我們將對該視圖中的「當前顯示的」行/部分進行更改,而該視圖不是當前視圖,因此您需要添加變量/屬性來跟蹤該視圖。

因爲導航控制器已經可以對視圖更改進行動畫處理,所以我讓它執行大部分工作。當移動「前一個」時,我創建一個新視圖,其中包含以前的條目詳細信息,將其插入導航堆棧(在LIST視圖和當前DETAIL視圖之間),並執行popViewControllerAnimated,它提供視覺效果並卸載細節視圖只是動畫了。

要移動到「下一個」陣營詳細信息,我創建一個新的視圖,其中包含下一個條目詳細信息,將其添加到導航堆棧的末尾,然後通過刪除細節來清理導航堆棧視圖,只是動畫關閉。

所以,簡而言之: 細節視圖將檢測輕掃手勢並通知父母。 父級確定應顯示的下一個/上一個行。 父代用當前視圖替換當前視圖,左右替換動畫以可視化指示效果。父母也會更新導航堆棧,以確保「返回」按鈕始終充當LIST視圖的彈出窗口,而不是以前顯示的DETAIL視圖。

我不能在這裏發佈我所有的代碼,但下面是大多數。一些具體的陷阱需要提防:

  1. 操縱導航堆棧可以在運行時產生錯誤,警告如果試圖刪除VC是動畫的同時。因此,我們等到它完全被替換,然後刪除它,通過註冊爲導航控制器的委託,並使用「didShowViewController」方法來檢測何時可以安全地進行更改。只有在列表中向前移動時才需要此複雜功能,因爲在「後退」邏輯中,導航控制器在popViewController之後自行清理。

  2. 爲了使用didShowViewController,您必須設置一個委託。代表不得是可能消失的風險投資,否則你將會崩潰。我只有控制LIST視圖將自己設置爲委託。當你操縱哪個行/部分的用戶正在查看細節時,我還會在隱藏的LIST視圖上移動高亮(並滾動表格),以便當它們最終「返回」到它時,顯示上次查看的項目。

當創建一個詳細視圖,通過在親本中,定義的方法來讓母體知道發生了滑動,並在細節視圖寄存器輕掃識別器,在viewDidLoad方法,

代碼在列表視圖(父)

-(NSString *) nameOfPreviousCampAndUpdateCurrents; 
    { 
     // pseudo code 
     // targetsection = srcSection 
     // targetrow = srcRow-1. 
     // if targetrow < 0 
     // targetsection = srcSection - 1 
     // targetrow = last row of targetsection 
     // if targetSection < 0 
     // return nil; 
     // 
     // return name at targetsection, targetrow 

     NSInteger targetSection; 
     NSInteger targetRow; 
     NSString *results = nil; 

     targetSection = self.currentDetailViewSection; 
     targetRow = self.currentDetailViewRow-1; 

     if (targetRow < 0) 
     { 
      targetSection--; 
      if (targetSection <0) 
      { 
       return nil; 
      }// end if 

      NSInteger numberOfRowsInSection = [self tableView:self.myTable numberOfRowsInSection:targetSection];   
      targetRow = numberOfRowsInSection-1;   
     }// end if 

     results = [self getCampNameInSection:targetSection atOffset:targetRow]; 
     self.currentDetailViewSection = targetSection; 
     self.currentDetailViewRow = targetRow; 

     return results; 

    } 

    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
    { 
     // Navigation logic may go here. Create and push another view controller. 

     CampDetails *detailViewController = [[[CampDetails alloc] initWithNibName:nil bundle:nil] autorelease]; 
     detailViewController.campName = [self getCampNameInSection:indexPath.section atOffset:indexPath.row]; 
     detailViewController.campID = [self getCampIDForSection:indexPath.section atOffset:indexPath.row]; 
     detailViewController.parent = self; 

     self.currentDetailViewSection = indexPath.section; 
     self.currentDetailViewRow = indexPath.row; 

     // ... 
     // Pass the selected object to the new view controller. 
     [[self navigationController] pushViewController:detailViewController animated:YES]; 
     //[detailViewController release]; 

    } 

    -(void) viewDidLoad; 
    { 
     // The ROOT view controller should do this. 
     if ([[self.navigationController viewControllers] count] == 1) 
     { 
      self.navigationController.delegate = self;   
     }// end if 
    } 

    -(void) moveToNextCamp; 
    { 
     NSString *nextCamp = [self nameOfNextCampAndUpdateCurrents]; 

     if (nextCamp == nil) 
     { 
      UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"Warning" 
                  message:@"You are already at the last item in the list of camps." 
                  delegate:self 
                cancelButtonTitle:@"OK" 
                otherButtonTitles:nil]; 
      [alert show]; 
      [alert release]; 

      return; 
     }// end if 

     CampDetails *detailViewController = [[[CampDetails alloc] initWithNibName:nil bundle:nil]autorelease]; 
     detailViewController.campName = nextCamp; 
     detailViewController.campID = [self getCampIDForSection:self.currentDetailViewSection atOffset:self.currentDetailViewRow]; 
     detailViewController.parent = self; 

     // do the animation to the right 
     [self.navigationController pushViewController:detailViewController animated:YES]; 


    // remove the previous controller so that popping the current one takes us "up" 
    // WHILE THE FOLLOWING CODE DOES WORK, it also results in a runtime warning. 
    // so instead, we tinker with the controller stack only when it's safe (see below) 
    // NSMutableArray *viewControllers = [NSMutableArray arrayWithArray:self.navigationController.viewControllers]; 
    // [viewControllers removeObjectAtIndex:1]; 
    // [self.navigationController setViewControllers:viewControllers animated:NO]; 
    //  

     // clean up the stack AFTER the child is shown. 
     self.userJustSwiped = YES; 

     [self updateTableHighlightAndScrollPosition]; 


    } 
    -(void) moveToPreviousCamp; 
    { 
     NSString *previousCamp = [self nameOfPreviousCampAndUpdateCurrents]; 

     if (previousCamp == nil) 
     { 
      UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"Warning" 
                  message:@"You are already at the first item in the list of camps." 
                  delegate:self 
                cancelButtonTitle:@"OK" 
                otherButtonTitles:nil]; 
      [alert show]; 
      [alert release]; 

      return; 
     }// end if 

     CampDetails *detailViewController = [[[CampDetails alloc] initWithNibName:nil bundle:nil]autorelease]; 
     detailViewController.campName = previousCamp; 
     detailViewController.campID = [self getCampIDForSection:self.currentDetailViewSection atOffset:self.currentDetailViewRow]; 
     detailViewController.parent = self; 

     // add the controller so that popping the current one takes us there  
     NSMutableArray *viewControllers = [NSMutableArray arrayWithArray:self.navigationController.viewControllers];  
     NSInteger lastNavStackEntryIndex = [viewControllers count]-1;  
     [viewControllers insertObject:detailViewController atIndex:lastNavStackEntryIndex]; 
     [self.navigationController setViewControllers:viewControllers animated:NO]; 

     // do the animation (which also releases the previously current vc) 
     [self.navigationController popViewControllerAnimated:YES]; 

     [self updateTableHighlightAndScrollPosition]; 

    } 

    - (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated 
    { 
     // IF we just swiped to a details view, do some clean up 
     if (self.userJustSwiped) 
     { 
      self.userJustSwiped = NO; 
      // clean up the stack AFTER the child is shown. remove the previous controller so that popping the current one takes us "up" 
      NSMutableArray *viewControllersArray = [NSMutableArray arrayWithArray:navigationController.viewControllers]; 

      NSInteger lastNavStackEntryIndex = [viewControllersArray count] - 1; 

      [viewControllersArray removeObjectAtIndex:lastNavStackEntryIndex-1]; 
      [navigationController setViewControllers:viewControllersArray animated:NO];   

     }// end if 



    } 

    -(void) userSwipedLeftOnChild; 
    { 
     [self moveToNextCamp]; 
    } 

    -(void) userSwipedRightOnChild; 
    { 
     [self moveToPreviousCamp]; 
    } 

代碼在詳細視圖(子):

-(void) leftSwipe:(UIGestureRecognizer*)recognizer; 
{ 
    [self.parent userSwipedLeftOnChild]; 
} 
-(void) rightSwipe:(UIGestureRecognizer*)recognizer; 
{ 
    [self.parent userSwipedRightOnChild]; 
} 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    // add swipe recognizers 
    UISwipeGestureRecognizer *leftSwipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(leftSwipe:)]; 
    [leftSwipe setDirection:UISwipeGestureRecognizerDirectionLeft]; 
    [self.view addGestureRecognizer:leftSwipe]; 
    [leftSwipe release]; 


    UISwipeGestureRecognizer *rightSwipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(rightSwipe:) ]; 
    [rightSwipe setDirection:UISwipeGestureRecognizerDirectionRight]; 
    [self.view addGestureRecognizer:rightSwipe]; 
    [rightSwipe release]; 
} 
1

當輕按這些按鈕時,您可以輕鬆地使用動畫推送和彈出視圖控制器。

如果您需要幫助,請告訴我。

1

使用一個UINavigationController,它自動有一個後退按鈕,然後在右側添加下一個按鈕。

或者只是隱藏導航控制器的欄,並添加自己的兩個按鈕(我認爲你目前的做法)。

要推/彈出視圖 - 控制一個導航控制器上:

推進到下一個VC:

[myNavController pushViewController:vc animated:YES]; 

彈出回最後一個VC:

myNavController popViewControllerAnimated:YES]; 

彈出回第三VC對堆棧:

[myNavController popToViewController:[myNavController.viewControllers objectAtIndex:2] animated:YES]; 

請注意,如果您想最大限度地減少內存使用量,請使用您自己的導航欄和您自己的按鈕,並確保您只有兩個視圖控制器可以使用您自己編碼的索引/數目來確定您在虛擬堆棧中的位置。

相關問題