Page view Navigation

本文介绍如何使用UIPageViewController实现流畅的页面切换效果,包括初始化设置、动态调整视图内容及利用Storyboard进行页面控制器管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Managing the Page Navigation

  •   currentPage  property
  •   numberOfPages  property
  •   hidesForSinglePage  property
  • 示范A= = == == = =
  •  用UIPageViewController来实现,通过改变其所包含的viewcontroller,快速实现翻页效果,代码量最小,基本方法就是:
  • pageViewController viewControllerAfterViewController

    pageViewController viewControllerBeforeViewController

  •     // make a page view controller
        UIPageViewController* pvc = [[UIPageViewController alloc] 
                                     initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl
                                     navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal 
                                     options:nil];
        
        // give it an initial page
        Pep* page = [[Pep alloc] initWithPepBoy:[self.pep objectAtIndex:0] nib: nil bundle: nil];
        //nib is nil as by default, it will go to load the nib with same name...
        
        [pvc setViewControllers:[NSArray arrayWithObject:page]
                           direction:UIPageViewControllerNavigationDirectionForward
                            animated:NO completion:NULL];


  • 从自动nib关联,动态调整view的内容。
  • - (void)viewDidLoad

    {

        [super viewDidLoad];

        self.name.text = self.boy;

        self.pic.image = [UIImage imageNamed

                    [NSString stringWithFormat: @"%@.jpg", [self.boy lowercaseString]]];

    }

    ==向前翻动和向后翻页
    -(UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController 
    {
        NSString* boy = [(Pep*)viewController boy];
        NSUInteger ix = [self.pep indexOfObject:boy];
        //反向 的查找... ...
        ix++;
        if (ix >= [self.pep count])
            return nil;
        return [[Pep alloc] initWithPepBoy:[self.pep objectAtIndex:ix] nib: nil bundle: nil];
        //返回新对象
    }
    //viewControllerBeforeViewController
    -(UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController {
        NSString* boy = [(Pep*)viewController boy];
        NSUInteger ix = [self.pep indexOfObject:boy];//先获得内容
        if (ix == 0)
            return nil;
        return [[Pep alloc] initWithPepBoy:[self.pep objectAtIndex:--ix] nib: nil bundle: nil];//后创建对象view controller
    }
    

    示范B= = == == = =

    用xcode 4.3 for iOS 5.0的默认template产生的翻页程序,由于采用了storyboard,似乎复杂了些!这个template的特别之处是没有机会让用户选择 是否要使用storeboard,


    @property (strong, nonatomic) UIPageViewController *pageViewController;

        self.pageViewController = [[[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil] autorelease];
        self.pageViewController.delegate = self;
    
        flyDataViewController *startingViewController = [self.modelController viewControllerAtIndex:0 storyboard:self.storyboard];
        NSArray *viewControllers = [NSArray arrayWithObject:startingViewController];
        //set the viewcontroller as container...
        [self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:NULL];
    

    基本来说,结构一样,先初始化自己,(这段代码是没有ARC启用的)然后初始化default viewcontroller,然后pageviewcontroller setViewcontrollers。这里的一个特别的地方是

    从storyboard获得sub viewcontroller。

    @interface flyModelController : NSObject <UIPageViewControllerDataSource>
    
    - (flyDataViewController *)viewControllerAtIndex:(NSUInteger)index storyboard:(UIStoryboard *)storyboard
    //一般而言一个app一个storayboard,如此更具备通用性
    - (NSUInteger)indexOfViewController:(flyDataViewController *)viewController;
    //逆向计算viewController的index,用于定位下一个/上一个。。。 是两个辅助函数
    
    @end
    在这个模板中,把

    <UIPageViewControllerDelegate>和datasource协议分开在两个class中实现,上一个简洁的就直接在 appdelegate中全部搞定了

    @interface AppDelegate : UIResponder <UIApplicationDelegate, UIPageViewControllerDataSource>
    

    真正的datasource就是如下(和之前一样没什么。。。):

    #pragma mark - Page View Controller Data Source
    
    - (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
    {
        NSUInteger index = [self indexOfViewController:(flyDataViewController *)viewController];//method 1
        if ((index == 0) || (index == NSNotFound)) {
            return nil;
        }
        
        index--;
        return [self viewControllerAtIndex:index storyboard:viewController.storyboard];//method 2
    }
    
    - (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
    {
        NSUInteger index = [self indexOfViewController:(flyDataViewController *)viewController];
        if (index == NSNotFound) {
            return nil;
        }
        
        index++;
        if (index == [self.pageData count]) {
            return nil;
        }
        return [self viewControllerAtIndex:index storyboard:viewController.storyboard];
    }
    
    = = = =》storyboard中通过vc identifier来获取vc instance
      // Create a new view controller and pass suitable data.
        flyDataViewController *dataViewController = [storyboard instantiateViewControllerWithIdentifier:@"flyDataViewController"];
        dataViewController.dataObject = [self.pageData objectAtIndex:index];


    看到上面细致的效果,amzaing,其实仔细一看,这个template产生的文件虽然很多,倒是很符合Mvc的。Modelcontroller提供数据,算data model,所有数据访问操作来自它,它adopt pageview的

    datasource protocol。dataviewcontroller实现了view,以及如何把数据展现到view outlet了,算view;rootviewcontroller实现了

    @interface flyRootViewController : UIViewController <UIPageViewControllerDelegate>,自然就是真正的controller。

    那appdelegate只是作为一个entrance,custom 代码一点也没有,直接导向第一个rootviewcontroller,从之前的storyboard截图来看,两个viewcontroller之间没有segue,是通过代码方式使用的 



    下面看看controller是怎么做到的:

    //only one instance by getter inside class...
    //@synthesize modelController = _modelController;
    - (flyModelController *)modelController
    {
         // Return the model controller object, creating it if necessary.
         // In more complex implementations, the model controller may be passed to the view controller.
        if (!_modelController) {
            _modelController = [[flyModelController alloc] init];
        }
        return _modelController;
    }


    [self.view addSubview:self.pageViewController.view];
    
        // Set the page view controller's bounds using an inset rect so that self's view is visible around the edges of the pages.
        CGRect pageViewRect = self.view.bounds;
        pageViewRect = CGRectInset(pageViewRect, 50.0, 40.0);
        self.pageViewController.view.frame = pageViewRect;
    
        [self.pageViewController didMoveToParentViewController:self];
        //Called after the view controller is added or removed from a container view controller.
    
        // Add the page view controller's gesture recognizers to the book view controller's view so that the gestures are started more easily.
        self.view.gestureRecognizers = self.pageViewController.gestureRecognizers;

    这个代码还有些意思的,通过subview利用了原windowview的边框,通过didmovetoparentviewcontroller可以实现与presented viewcontroller交互,通过gesture的转移,方便了翻页

    因为我们留了边界,这么做可以帮助翻页手势识别从边上开始。

    delegate的方法基本是 optional的,实现了一个,就是在landscape时候,书本是双页显示内容的,那么要计算view的位置:

    - (UIPageViewControllerSpineLocation)pageViewController:(UIPageViewController *)pageViewController spineLocationForInterfaceOrientation:(UIInterfaceOrientation)orientation
    {
        if (UIInterfaceOrientationIsPortrait(orientation)) {
            // In portrait orientation: Set the spine position to "min" and the page view controller's view controllers array to contain just one view controller. Setting the spine position to 'UIPageViewControllerSpineLocationMid' in landscape orientation sets the doubleSided property to YES, so set it to NO here.
            UIViewController *currentViewController = [self.pageViewController.viewControllers objectAtIndex:0];
            NSArray *viewControllers = [NSArray arrayWithObject:currentViewController];
            [self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:NULL];
            
            self.pageViewController.doubleSided = NO;
            return UIPageViewControllerSpineLocationMin;
        }
    
        // In landscape orientation: Set set the spine location to "mid" and the page view controller's view controllers array to contain two view controllers. If the current page is even, set it to contain the current and next view controllers; if it is odd, set the array to contain the previous and current view controllers.
        flyDataViewController *currentViewController = [self.pageViewController.viewControllers objectAtIndex:0];
        NSArray *viewControllers = nil;
    
        NSUInteger indexOfCurrentViewController = [self.modelController indexOfViewController:currentViewController];
        if (indexOfCurrentViewController == 0 || indexOfCurrentViewController % 2 == 0) {
            UIViewController *nextViewController = [self.modelController pageViewController:self.pageViewController viewControllerAfterViewController:currentViewController];
            viewControllers = [NSArray arrayWithObjects:currentViewController, nextViewController, nil];
        } else {
            UIViewController *previousViewController = [self.modelController pageViewController:self.pageViewController viewControllerBeforeViewController:currentViewController];
            viewControllers = [NSArray arrayWithObjects:previousViewController, currentViewController, nil];
        }
        [self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:NULL];
    
    
        return UIPageViewControllerSpineLocationMid;
    }








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值