如何在点击UIButton后在UIPageViewController中添加新的视图控制器?

时间:2012-11-04 20:42:08

标签: ios model uibutton uipageviewcontroller

我想知道如何实现会影响UIPageViewController模型的按钮。例如,我希望我的UIPageViewController模型数组加载其中的单个对象,当点击一个按钮时,将添加一个新的视图控制器,并自动翻页或类似的东西(如在Notes应用程序中)。删除用户正在查看的当前对象也是如此。

到目前为止,我尝试通过向我的根视图控制器实现一些IBActions但到目前为止没有运气。

以下是我实现ViewController类的方法:

@implementation ViewController

@synthesize modelArray = _modelArray;
@synthesize pageVC = _pageVC;

#pragma mark - UIPageViewControllerDataSource Methods

// Returns the view controller before the given view controller. (required)
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
      viewControllerBeforeViewController:(UIViewController *)viewController
{
    NSUInteger currentIndex = [self.modelArray indexOfObject:[(ContentVC *)viewController     labelContents]];
    if(currentIndex==0)
        return nil;

    ContentVC *cVC = [[ContentVC alloc] init];
    cVC.labelContents = [self.modelArray objectAtIndex:currentIndex-1];
    return cVC;
}

// Returns the view controller after the given view controller. (required)
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
   viewControllerAfterViewController:(UIViewController *)viewController
{
    NSUInteger currentIndex = [self.modelArray indexOfObject:[(ContentVC *)viewController labelContents]];
    if(currentIndex==self.modelArray.count-1)
        return nil;

    ContentVC *cVC = [[ContentVC alloc] init];
    cVC.labelContents = [self.modelArray objectAtIndex:currentIndex+1];
    return cVC;
}

#pragma mark - UIPageViewControllerDelegate Methods
// Returns the spine location for the given orientation.
- (UIPageViewControllerSpineLocation)pageViewController:(UIPageViewController *)pageViewController
               spineLocationForInterfaceOrientation:(UIInterfaceOrientation)orientation
{
    if(UIInterfaceOrientationIsPortrait(orientation)){
        // Set the array with only 1 view controller
        UIViewController *currentVC = [self.pageVC.viewControllers objectAtIndex:0];
        NSArray *viewControllers = [NSArray arrayWithObject:currentVC];
        [self.pageVC setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:nil];

        // Set the doubleSided property to NO
        self.pageVC.doubleSided = NO;
        // Return the spine location
        return UIPageViewControllerSpineLocationMin;
    } else { // if landscape
        NSArray *viewControllers = nil;
        ContentVC *currentVC = [self.pageVC.viewControllers objectAtIndex:0];
        NSUInteger currentIndex = [self.modelArray indexOfObject:[(ContentVC *)viewControllers labelContents]];
        if(currentIndex==0 || currentIndex %2 == 0){
            UIViewController *nextViewController = [self pageViewController:self.pageVC viewControllerAfterViewController:currentVC];
            viewControllers = [NSArray arrayWithObjects:currentVC, nextViewController, nil];
        } else {
            UIViewController *previousVC = [self pageViewController:self.pageVC viewControllerBeforeViewController:currentVC];
            viewControllers = [NSArray arrayWithObjects:previousVC, currentVC, nil];
        }
        // Set the view controllers as property of the UIPageViewController
        [self.pageVC setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:nil];
        return UIPageViewControllerSpineLocationMid;
    }

}

#pragma mark - View lifecycle

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Instantiate the model array
    self.modelArray = [[NSMutableArray alloc] init];
    [self.modelArray addObject:@"Page One"];
    NSLog(@"%@", self.modelArray);

    // Instantiate the UIPageViewController
    self.pageVC = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];

    // Assign the delegate and datasource as self
    self.pageVC.delegate = self;
    self.pageVC.dataSource = self;

    // Set the initial view controllers
    ContentVC *cVC = [[ContentVC alloc] initWithNibName:@"ContentVC" bundle:nil];
    cVC.labelContents = [self.modelArray objectAtIndex:0];
    NSArray *viewControllers = [NSArray arrayWithObject:cVC];
    [self.pageVC setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];

    // Add the pageViewController as the childViewController
    [self addChildViewController:self.pageVC];

    // Add the view of pageViewController  to the currentView
    [self.view addSubview:self.pageVC.view];

    // Call didMoveToParentViewController: of the childViewController, the UIPageViewController instance in our case.
    [self.pageVC didMoveToParentViewController:self];

    // Assign the gestureRecognizers property of the pageViewController to the view's gestureRecognizers property
    self.view.gestureRecognizers = self.pageVC.gestureRecognizers;

}

非常感谢!

1 个答案:

答案 0 :(得分:11)

UIPageViewController使用数据源来获取下一个或上一个视图控制器。因此,解决方案是在触摸按钮后将新视图控制器添加到数据源。

假设您的数据源是作为NSArray实现的(请参阅XCode的基于页面的应用程序模板以获取此示例)您只需将新vc添加到该阵列并通过调用{{1}来设置新的vc }。

由于您未提供有关如何实施层次结构的任何详细信息,因此无法更具体。

修改

现在我有了一些代码,这就是我要做的事情:

首先,我不会在[UIPageViewController setViewControllers:direction:animated:completion:]中保存labelContents,而是保存视图控制器本身。除了其他方面,每次更改页面时,您当前的设计都会创建一个新的modelArray。这是很多不必要的开销。以下是我将如何实现这一点:

(顺便说一下,你应该想到一个比ContentVC更具描述性的名字。现在,如果只有一个标签可能没问题,但是如果你将来添加更多标签怎么办?)

labelContents

评论中的代码:

- (ContentVC *)contentViewControllerWithLabelContents:(NSString *)labelContents
{
    ContentVC *vc = [[ContentVC alloc] initWithNibName:@"ContentVC" bundle:nil];
    vc.labelContents = labelContents;
    return vc;
}

- (void)viewDidLoad
{
    NSMutableArray *vcs = [NSMutableArray array];
    [vcs addObject:[self contentViewControllerWithLabelContents:@"Page One"]];
    [vcs addObject:[self contentViewControllerWithLabelContents:@"Page Two"]];
    //...
    self.modelArray = vcs;
}


#pragma mark - UIPageViewControllerDataSource Methods

// Returns the view controller before the given view controller. (required)
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
      viewControllerBeforeViewController:(UIViewController *)viewController
{
    NSUInteger currentIndex = [self.modelArray indexOfObject:viewController];
    if(currentIndex == 0)
        return nil;

    ContentVC *cVC = [self.modelArray objectAtIndex:currentIndex - 1];
    return cVC;
}

// Returns the view controller after the given view controller. (required)
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
   viewControllerAfterViewController:(UIViewController *)viewController
{
    NSUInteger currentIndex = [self.modelArray indexOfObject:viewController];
    if(currentIndex == self.modelArray.count - 1)
        return nil;

    ContentVC *cVC = [self.modelArray objectAtIndex:currentIndex + 1];
    return cVC;
}

无效,因为您未设置- (IBAction)newButtonTapped:(id)sender { if(sender){ [self.modelArray addObject:@"Page Two"]; ContentVC *newVC = [[ContentVC alloc] initWithNibName:@"ContentVC" bundle:nil]; NSArray *arr = [NSArray arrayWithObject:newVC]; [self.pageVC setViewControllers:arr direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil]; NSLog(@"%@", self.modelArray); } } 的{​​{1}}。因此,您基本上最终会调用labelContentsContentVC,具体取决于您[self.modelObject indexOfObject:nil]的实施情况。由于它们都不在数组中,因此调用返回[self.modelObject indexOfObject:@""],它在64位系统上转换为labelContents,即NSNotFound。稍后,您尝试访问索引为NSIntegerMax的{​​{1}}并提升2147483647

因此,可以通过在modelArray方法中设置NSIntegerMax - 1或者按照我的建议重新设计代码来解决此问题:

NSRangeException