Iphone 从UIPageViewController中删除视图控制器

Iphone 从UIPageViewController中删除视图控制器,iphone,objective-c,ios,cocoa-touch,Iphone,Objective C,Ios,Cocoa Touch,奇怪的是,没有直接的方法可以做到这一点。考虑下面的场景: 您有一个具有1个页面的页面视图控制器 添加另一页(共2页)并滚动至该页 我想要的是,当用户滚动回第一页时,第二页现在被删除并取消分配,用户不能再刷回该页 在转换完成后,我尝试将视图控制器作为子视图控制器删除,但它仍然允许我滚动回空页面(它不会“调整”页面视图的大小) 我想做的是可能的吗?我只是自己在学习,所以请恕我直言,但据我所知,您需要更改pageviewcontroller的数据源,而不是删除viewcontroller。pagevi

奇怪的是,没有直接的方法可以做到这一点。考虑下面的场景:

  • 您有一个具有1个页面的页面视图控制器
  • 添加另一页(共2页)并滚动至该页
  • 我想要的是,当用户滚动回第一页时,第二页现在被删除并取消分配,用户不能再刷回该页
  • 在转换完成后,我尝试将视图控制器作为子视图控制器删除,但它仍然允许我滚动回空页面(它不会“调整”页面视图的大小)


    我想做的是可能的吗?

    我只是自己在学习,所以请恕我直言,但据我所知,您需要更改pageviewcontroller的数据源,而不是删除viewcontroller。pageviewcontroller中显示的页面数由其数据源决定,而不是由ViewController决定。

    maq是正确的。如果使用滚动转换,从UIPageViewController中删除子视图控制器不会阻止用户导航到已删除的“页面”时返回屏幕。如果您感兴趣,下面是我如何从UIPageViewController中删除子视图控制器的

    // deleteVC is a child view controller of the UIPageViewController
    [deleteVC willMoveToParentViewController:nil];
    [deleteVC.view removeFromSuperview];
    [deleteVC removeFromParentViewController]; 
    
    var isScrolling = false
    
    func viewDidLoad() {
    ...
    
      for v in view.subviews{
        if v.isKindOfClass(UIScrollView) {
          (v as! UIScrollView).delegate = self
        }
      }
    }
    
    func scrollViewWillBeginDragging(scrollView: UIScrollView){
        isScrolling = true
    }
    
    func scrollViewDidEndDecelerating(scrollView: UIScrollView){
        isScrolling = false
    }
    
    func jumpToVC{
        if isScrolling {  //you should not jump out when scrolling
            return
        }
        setViewControllers([vc], direction:direction, animated:true, completion:{[unowned self] (succ) -> Void in
            if succ {
                dispatch_async(dispatch_get_main_queue(), { () -> Void in
                    self.setViewControllers([vc], direction:direction, animated:false, completion:nil)
                })
            }
        })
    }
    
    视图控制器deleteVC已从UIPageViewController的ChildViewController属性中删除,但如果用户导航到它,它仍会显示在屏幕上

    在比我聪明的人找到一个优雅的解决方案之前,这里有一个解决办法(这是一个黑客——所以你必须问问自己是否真的需要从UIPageViewController中删除页面)

    这些说明假定一次只显示一页

    用户点击表示要删除页面的按钮后,使用SetViewController:direction:animated:completion:方法导航到下一页或上一页。当然,然后需要从数据模型中删除页面的内容

    接下来(这里是黑客),创建和配置一个全新的UIPageViewController,并将其加载到前台(即在另一个UIPageViewController前面)。确保新的UIPageViewController开始显示与先前显示完全相同的页面。新的UIPageViewController将从数据源获取新的视图控制器

    最后,卸载并销毁位于后台的UIPageViewController


    不管怎样,maq问了一个非常好的问题。不幸的是,我没有足够的声望来投票支持这个问题。啊,敢于梦想。。。总有一天我会得到15点声誉积分

    事实上,我想我解决了这个问题。这就是我的应用程序中发生的情况:

  • 通过将UIPageViewController子类实例从模型中删除并将UIPageViewController的ViewController属性设置为不同的ViewController,已将其从UIPageViewController中删除。这就足够做这项工作了。无需在该控制器上执行任何控制器包含代码
  • ViewController不见了,但我仍然可以通过向右滑动滚动到它
  • 我的问题是这个。我正在向UIPageViewController显示的ViewController添加自定义手势识别器。此识别器在同样拥有UIPageViewController的控制器上作为强属性保留
  • 修复:在解除对ViewController的访问之前,我确保正确清理了它使用的所有内存(dealloc),并移除了手势识别器
  • 您的里程数可能会有所不同,但我认为此解决方案没有错,当某些东西不起作用时,我首先怀疑我的代码:)

  • 我将把这个答案放在这里只是为了我自己将来的参考,如果它对任何人都有帮助的话——我最后做的是:

  • 删除该页并前进到下一页
  • setViewControllers
    的完成块中,我使用修改后的数据创建/初始化了一个新的UIPageViewController(项目已删除),并在不设置动画的情况下推送它,因此屏幕上没有任何变化(我的UIPageViewController包含在UINavigationController中)
  • 按下新的UIPageViewController后,获取UINavigationController的
    ViewController
    数组的副本,移除倒数第二个视图控制器(即旧的UIPageViewController)
  • 没有第4步-完成
    虽然这里的答案都是信息性的,但这里给出了另一种处理问题的方法:

    当我第一次搜索这个问题的答案时,我搜索时的措辞让我在这个问题上陷入了困境,而不是我刚刚链接到的那个问题,所以我觉得有义务发布一个链接到另一个问题的答案,现在我已经找到了它,并且进行了一点详细阐述

    matt很好地描述了这个问题:

    这实际上是UIPageViewController中的一个错误。它仅在滚动样式(UIPageViewControllerTransitionStyleScroll)和 调用SetViewController后:方向:动画:完成:使用 动画:是的。因此,有两种解决办法:

    不要使用UIPageViewControllerTransitionStyleScroll

    或者,如果调用SetViewController:direction:animated:completion:,则使用 只有动画:没有

    要清楚地看到错误,请调用 SetViewController:方向:动画:完成:然后,在 界面(作为用户),向左(向后)导航到上一页 手动。您将导航回错误的页面:而不是前面的页面 一页都没有,但你在 调用了setViewControllers:方向:已设置动画:完成:

    出现此错误的原因似乎是,在使用滚动时 样式,UIPageViewController执行某种内部缓存。因此 在调用SetViewController:direction:animated:completion:, 它无法清除其内部缓存。它认为它知道 上一页是。因此,当用户向左导航到
    - (void) setViewControllers:(NSArray*)viewControllers direction:(UIPageViewControllerNavigationDirection)direction animated:(BOOL)animated completion:(void (^)(BOOL))completion {
    
        if (!animated) {
            [super setViewControllers:viewControllers direction:direction animated:NO completion:completion];
            return;
        }
    
        [super setViewControllers:viewControllers direction:direction animated:YES completion:^(BOOL finished){
    
            if (finished) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    [super setViewControllers:viewControllers direction:direction animated:NO completion:completion];
                });
            } else {
                if (completion != NULL) {
                    completion(finished);
                }
            }
        }];
    }
    
    UIViewController *jumpToAnotherViewController = [self viewControllerAtIndex:dyingPageIndex-1];
    [self setViewControllers:@[jumpToAnotherViewController] direction:UIPageViewControllerNavigationDirectionReverse animated:NO completion:nil];
    
    jumpToAnotherViewController = [self viewControllerAtIndex:dyingPageIndex-1];
    [self setViewControllers:@[jumpToAnotherViewController] direction:UIPageViewControllerNavigationDirectionReverse animated:YES completion:nil];
    
    jumpToAnotherViewController = [self viewControllerAtIndex:dyingPageIndex;
    [self setViewControllers:@[jumpToAnotherViewController] direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:nil];
    
    - (void)deleteAViewController:(id)sender {
        YourUIViewController *dyingGroup = (YourUIViewController *)sender;
        NSUInteger dyingPageIndex = dyingGroup.pageIndex;
        // Check to see if we are in the last page as it's a special case.
        BOOL isTheLastPage = (dyingPageIndex >= YourTotalNumberOfPagesFromModel.count);
        // Make a temporary jump back - make sure to use animated:NO to have it jump instantly
        UIViewController *jumpToAnotherViewController = [self viewControllerAtIndex:dyingPageIndex-1];
        [self setViewControllers:@[jumpToAnotherViewController] direction:UIPageViewControllerNavigationDirectionReverse animated:NO completion:nil];
        // Now delete the selected group from the model, setting the target
        [YourModel deletePage:dyingPageIndex];
        if (isTheLastPage) {
            // Now jump to the definitive controller. In this case, it's the same one, we're just reloading it to refresh the data source.
            // This time we're using animated:YES
            jumpToAnotherViewController = [self viewControllerAtIndex:dyingPageIndex-1];
            [self setViewControllers:@[jumpToAnotherViewController] direction:UIPageViewControllerNavigationDirectionReverse animated:YES completion:nil];
        } else {
            // Now jump to the definitive controller. This reloads the data source. This time we're using animated:YES
            jumpToAnotherViewController = [self viewControllerAtIndex:dyingPageIndex];
            [self setViewControllers:@[jumpToAnotherViewController] direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:nil];
        }
    }
    
    var isScrolling = false
    
    func viewDidLoad() {
    ...
    
      for v in view.subviews{
        if v.isKindOfClass(UIScrollView) {
          (v as! UIScrollView).delegate = self
        }
      }
    }
    
    func scrollViewWillBeginDragging(scrollView: UIScrollView){
        isScrolling = true
    }
    
    func scrollViewDidEndDecelerating(scrollView: UIScrollView){
        isScrolling = false
    }
    
    func jumpToVC{
        if isScrolling {  //you should not jump out when scrolling
            return
        }
        setViewControllers([vc], direction:direction, animated:true, completion:{[unowned self] (succ) -> Void in
            if succ {
                dispatch_async(dispatch_get_main_queue(), { () -> Void in
                    self.setViewControllers([vc], direction:direction, animated:false, completion:nil)
                })
            }
        })
    }
    
    - (void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray *)pendingViewControllers {
        self.pageViewControllerTransitionInProgress = YES;
    }
    
    - (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed {
            self.pageViewControllerTransitionInProgress = NO;
    }
    
    - (void)setCurrentPage:(NSString *)newCurrentPageId animated:(BOOL)animated {
    
        if (self.pageViewControllerTransitionInProgress) {
            return;
        }
    
        [self.pageContentViewController setViewControllers:@[pageDetails] direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:^(BOOL finished) {
        }
    
    }
    
    NSMutableArray *mArray = [[NSMutableArray alloc] initWithArray:self.userArray];
    [mArray removeObject:userToBlock];
    self.userArray = mArray;
    
    UIViewController *startingViewController = [self viewControllerAtIndex:atIndex-1];
    NSArray *viewControllers = @[startingViewController];
    [self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionReverse animated:NO completion:nil];
    
    fileprivate var isAnimated:Bool = false
    
    override func setViewControllers(_ viewControllers: [UIViewController]?, direction: UIPageViewControllerNavigationDirection, animated: Bool, completion: ((Bool) -> Void)? = nil) {
    
            if self.isAnimated {
                delay(0.5, closure: { 
                    self.setViewControllers(viewControllers, direction: direction, animated: animated, completion: completion)
                })
            }else {
                    super.setViewControllers(viewControllers, direction: direction, animated: animated, completion: completion)
            }
    
        }
    
    
    extension SliderViewController:UIPageViewControllerDelegate {
    
        func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) {
            self.isAnimated = true
        }
    
        func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
            self.isAnimated = finished
        }
    }
    
    func delay(_ delay:Double, closure:@escaping ()->()) {
        DispatchQueue.main.asyncAfter(
            deadline: DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC), execute: closure)
    }