Iphone导航到上一个/下一个viewController [英] Iphone navigate to previous/next viewController

查看:146
本文介绍了Iphone导航到上一个/下一个viewController的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个viewController,它使用tableview显示查询结果。
通过点击一行,我推动了一个childView,并设置了一个包含右侧2个按钮的导航栏(上一个/下一个)。
我的问题是:
当我点击上一个或下一个按钮时,如何切换到上一个或下一个childView?
我希望在视图切换时也有过渡效果?
任何帮助?

I have a viewController that displays the result of a query using a tableview). By taping on a row a I push a the childView and I set a navigationBar that contains 2 buttons on the right (Previous/Next). My question is : How can I switch to the previous or next "childView" when I tap on previous or next button? I would like to have also a transition effect while the view is switching? Any help?

推荐答案

我有一个包含营地列表的视图,触摸一个用户需要用户营地细节。我想允许用户左右滑动以在营地列表中移动,显示每个营地的详细信息。我想要一个显示滑动的视觉动画,并且后退按钮总是指向后移动导航堆栈,即返回列表。

I had a view that contained a list of camps, and touching one takes users to the camp details. I wanted to allow the user to swipe left and right to move through the list of camps displaying the details of each. I wanted a visual animation that showed the swipe, and that the 'Back' button always referred to moving back up the navigation stack, ie, returning to the list.

具有结果表的第一个视图是唯一知道previous和next含义的对象,因此他们将负责实现滑动操作。因为我们将对该视图中的当前显示的行/部分进行更改,而视图不是当前视图,您需要添加vars / properties来跟踪它。

The first view that has the table with results is the only object that knows what "previous" and "next" mean, so they will be responsible for implementing the swipe action. Because we will be making changes to the "currently displayed" row/section in that view, while the view is not the current view, you will need to add vars/properties to track that.

因为导航控制器已经可以为视图更改设置动画,所以我让它完成大部分工作。当移动previous时,我创建一个包含先前条目细节的新视图,将其插入导航堆栈(在LIST视图和当前DETAIL视图之间),并执行popViewControllerAnimated,它提供视觉效果并卸载详细信息视图只是动画了。

Because the navigation controller can already animate view changes, I let it do the majority of work. When moving "previous", I create a new view with the previous entry details, insert it into the navigation stack (between the LIST view and the current DETAIL view), and do a popViewControllerAnimated which provides a visual effect and also unloads the details view just animated off.

要转到下一个训练营细节,我创建一个包含下一个条目细节的新视图,将其添加到导航堆栈的末尾,它会动画显示,然后我通过删除刚刚设置动画的详细信息视图来清理导航堆栈。

To move to the "next" camp details, I create a new view with the next entry details, add it onto the end of the navigation stack, it animates in, then I clean up the navigation stack by removing the details view that just animated off.

因此,简而言之:
详细信息视图将检测滑动手势并通知家长。
父级确定应显示的下一行/上一行。
父级用新的替换当前视图,动画替换左/右以直观地指示效果。父级还会更新导航堆栈,以确保后退按钮始终充当LIST视图的弹出窗口,而不是先前显示的详细视图。

So, in a nutshell: The details view will detect the swipe gestures and inform the parent. The parent determines the next/previous row that should be displayed. The parent replaces the current view with a new one, animating the replacement left/right to visually indicate the effect. The parent also updates the navigation stack to ensure that the "Back" button always acts as a pop to the LIST view, not to a previously shown DETAIL view.

我不能在这里发布我的所有代码,但下面是大多数代码。要注意的一些特定GOTCHAS:

I can't post all my code here, but below is the majority. Some specific GOTCHAS to watch out for:


  1. 如果您尝试删除VC,操作导航堆栈可能会在运行时导致警告错误虽然它是动画。因此,我们等到它被完全替换,然后将其删除,通过注册为导航控制器的委托,并使用didShowViewController方法来检测何时可以安全地进行更改。只有在列表中向前移动时才需要这种复杂功能,因为在后退逻辑中,导航控制器会在popViewController之后自行清理。

  1. Manipulating the navigation stack can cause warning errors at runtime if you try to delete a VC while it is animating out. Therefore we wait until it is completely replaced, then remove it, by registering as the delegate for the navigation controller, and using the "didShowViewController" method to detect when it is safe to make changes. This complication is only needed when moving forward in the list, since in the "back" logic, the navigation controller cleans up itself after the popViewController.

按顺序要使用didShowViewController,您必须设置一个委托。代表不能是可能消失的VC,否则你会崩溃。我只有控制LIST视图将自己设置为委托。

In order to use didShowViewController you must set a delegate. The delegate must not be a VC that may go away, otherwise you will get a crash. I only have the controlling LIST view set itself as a delegate.

当您操纵用户正在查看详细信息的行/部分时,我也移动了在隐藏的LIST视图上突出显示(并滚动表格),这样当它们最终返回它时,会显示最后查看的项目。

As you manipulate which row/section the user is viewing the details of, I also move the highlight (and scroll the table) on the hidden LIST view, so that when they eventually go "BACK" to it, the last viewed item is shown.

创建详细信息视图时,传入父视图,定义方法以让父母知道滑动,并在详细信息视图中注册滑动识别器,在viewDidLoad方法中,

When creating a DETAIL view, pass in the parent, define methods to let the parent know a swipe occurred, and register swipe recognizers on the DETAIL view, in the viewDidLoad method,

LIST视图中的代码(父)

Code in the LIST view (parent)

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

DETAILS视图中的代码(子):

Code in the DETAILS view (child):

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

这篇关于Iphone导航到上一个/下一个viewController的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆