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

查看:28
本文介绍了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.

具有结果表的第一个视图是唯一知道上一个"和下一个"含义的对象,因此它们将负责实现滑动操作.因为我们将更改该视图中当前显示的"行/部分,而该视图不是当前视图,所以您需要添加变量/属性来跟踪它.

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.

因为导航控制器已经可以为视图更改设置动画,所以我让它完成了大部分工作.当移动上一个"时,我创建了一个包含前一个条目详细信息的新视图,将其插入到导航堆栈中(在 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 视图的弹出窗口,而不是之前显示的 DETAIL 视图.

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.

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

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.

在创建DETAIL视图时,传入父视图,定义方法让父视图知道发生了滑动,并在DETAIL视图上注册滑动识别器,在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天全站免登陆