从控制器内的页面更改PageViewController中的页面?

时间:2015-08-04 17:24:37

标签: ios objective-c xcode uipageviewcontroller

我有UIPageViewController,有3页。如何在按钮点击时切换到UIPageViewController内的页面? (每个页面都是我在故事板中创建的单独UIViewController。)

我尝试了很多代码,但是我在故事板中创建了UIPageViewController时出现了错误,我将其设置为:

PageViewController.m

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.dataSource = self;
    self.navigationController.navigationBarHidden = NO;

    [self setViewControllers:@[[self.storyboard instantiateViewControllerWithIdentifier:@"Main"]] 
                   direction:UIPageViewControllerNavigationDirectionForward 
                    animated:YES
                  completion:nil];
}

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
    if ([viewController isKindOfClass:[NavView2ViewController class]])
       return nil;

    return [self.storyboard instantiateViewControllerWithIdentifier:@"two"];
}

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
    if ([viewController isKindOfClass:[NavViewController class]])
        return nil;

    return [self.storyboard instantiateViewControllerWithIdentifier:@"one"];
}

3 个答案:

答案 0 :(得分:3)

您可以通过几种不同的方式执行此操作,具体取决于您希望如何构建应用程序的其余部分。

NSNotificationCenter

使用通知将允许您将子视图控制器与父页面视图控制器分离。它将足够灵活,允许整个应用程序中的其他代码控制哪个页面可见。然而,一个缺点是存在一定程度的间接性,并且不会立即显示触发页面更改的内容。

PageViewController上设置观察者,例如:

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.dataSource = self;
    self.navigationController.navigationBarHidden = NO;

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(handleButtonTap:)
                                                 name:MyPageViewControllerButtonNotification
                                               object:nil];

    [self setViewControllers:@[[self.storyboard instantiateViewControllerWithIdentifier:@"Main"]]
                   direction:UIPageViewControllerNavigationDirectionForward
                    animated:YES
                  completion:nil];
}

- (void)handleButtonTap:(NSNotification *)notification
{
    // Determine which page to move to based
    // on the notification object or userInfo
}

并发布任何子视图控制器的通知:

- (void)buttonTapped:(id)sender
{
    // Customise the sender or userInfo in order to
    // pass further information with the notification.
    [[NSNotificationCenter defaultCenter] postNotificationName:MyPageViewControllerButtonNotification
                                                        object:sender
                                                      userInfo:nil];
}

您需要在MyPageViewControllerButtonNotification和您希望发布此通知的所有视图控制器共有的文件中创建字符串PageViewController

Delegates

使用委托模式将在视图控制器和页面视图控制器之间提供比通知更紧密的耦合,这可能使以后扩展更加困难。这样做的好处是可以轻松跟踪页面更改的来源。

在页面视图控制器和子视图控制器共有的文件中定义协议:

@protocol PageControlDelegate <NSObject>

- (void)moveToPage:(NSUInteger)pageNumber;

@end

确保您的页面视图控制器符合该协议:

@interface PageViewController : UIPageViewController <PageControlDelegate>

(并在PageViewController.m

中实施该方法
- (void)moveToPage:(NSUInteger)pageNumber
{
    // switch to the appropriate page
}

当您为需要按钮交互的网页创建视图控制器时,您需要提供对PageViewController引用:

@interface SomeChildViewController : UIViewController

@property (nonatomic, weak) id<PageControlDelegate> pageControlDelegate;

@end

设置下一页时的示例分配:

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
    if ([viewController isKindOfClass:[NavViewController class]])
        return nil;

    SomeChildViewController *childController = [self.storyboard instantiateViewControllerWithIdentifier:@"one"];

    childController.pageControlDelegate = self;

    return childController;
}

然后,您可以从具有pageControlDelegate

的任何子视图控制器直接调用此方法
- (void)buttonTapped:(id)sender
{
    NSUInteger pageNumber = // Decide which page to move to
    [self.pageControlDelegate moveToPage:pageNumber];
}

答案 1 :(得分:0)

您可以根据需要随时拨打setViewController。使用您想要的ViewController再次调用它。您还可以通过访问ViewController属性来尝试找到viewControllers。但我认为,此属性只会显示正在显示的当前ViewController

答案 2 :(得分:0)

这就是我想出来的,它不需要黑魔法和代表。假设您拥有名为PageViewController的自定义MyPageViewController类,并在viewControllerList中实例化并保留子视图控制器:

Swift 4

class MyPageViewController: UIPageViewController, UIPageViewControllerDataSource {

  lazy var viewControllersList: [UIViewController] = {
    let storyBoard = UIStoryboard(name: "Main", bundle: nil)
    let first = storyBoard.instantiateViewController(withIdentifier: "FirstViewController")
    let second = storyBoard.instantiateViewController(withIdentifier: "SecondViewController")

    return [first,
            second]
  }()
}

现在在子视图控制器中,您可以通过以下方式切换到下一个视图控制器。在此示例中,我在选择表格行时执行切换:

Swift 4

  override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    if let pageViewController = self.parent as? MyPageViewController {
      if let currentIndex = pageViewController.viewControllersList.index(of: self) {
        guard (pageViewController.viewControllersList.count - currentIndex) > 1 else {
          fatalError("Can't navigate to the next view controller!")
        }
        let nextViewController = pageViewController.viewControllersList[currentIndex + 1]
        pageViewController.setViewControllers([nextViewController], direction: .forward, animated: true, completion: nil)
      }
    }
  }