Подтвердить что ты не робот

UIPageViewController предотвращает прокрутку моего представления таблицы вверх, когда вы нажимаете строку состояния

Я искал, прежде чем публиковать этот вопрос, но ничего не нашел.

У меня огромная проблема. У меня есть прокручиваемый тип UIPageViewController в качестве основы для моего приложения с тремя контроллерами представлений.

Один из контроллеров представления (listTableView) имеет представление таблицы и контроллер отображения поиска.

Проблема заключается в том, что я не могу прокручивать верхнюю часть представления таблицы при нажатии на строку состояния, как обычное табличное представление. Я считаю, что UIPageViewController вмешивается в это, но я понятия не имею, как это исправить, но я знаю, что мне нужно, чтобы приложение не было сломано.

Я ценю любую помощь, предлагаемую.

Я знаю, что кто-то попросит код, хотя в этом случае он иррелевант, но здесь он предназначен для создания UIPageViewController:

#import "MainViewController.h"

@interface MainViewController ()

@property (nonatomic, strong) UIPageViewController *pageViewController;
@property (nonatomic, strong) NSArray *contentViewControllers;

@end

@implementation MainViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.pageViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"PageView"];
    self.pageViewController.dataSource = self;

    UIViewController *settings = [self.storyboard instantiateViewControllerWithIdentifier:@"Settings"];

    UIViewController *listTableView = [self.storyboard instantiateViewControllerWithIdentifier:@"List"];

    UIViewController *first = [self.storyboard instantiateViewControllerWithIdentifier:@"First"];

    self.contentViewControllers = [NSArray arrayWithObjects:settings,listTableView,first,nil];

    [self.pageViewController setViewControllers:@[first] direction:UIPageViewControllerNavigationDirectionReverse animated:NO completion:nil];

    [self addChildViewController:self.pageViewController];
    [self.view addSubview:self.pageViewController.view];
    [self.pageViewController didMoveToParentViewController:self];

    self.view.backgroundColor = [UIColor colorWithRed:(248.0/255.0) green:(248.0/255.0) blue:(248.0/255.0) alpha:1.0];
}

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
  viewControllerBeforeViewController:(UIViewController *)viewController {

    NSUInteger index = [self.contentViewControllers indexOfObject:viewController];

    if (index == 0) {
        return nil;
    }

    return self.contentViewControllers[index - 1];
}

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
   viewControllerAfterViewController:(UIViewController *)viewController {

    NSUInteger index = [self.contentViewControllers indexOfObject:viewController];

    if (index >= self.contentViewControllers.count - 1) {
        return nil;
    }

    return self.contentViewControllers[index + 1];
}
4b9b3361

Ответ 1

Решение

После чата мы обнаружили что-то интересное. Контроллер просмотра страниц поддерживает другие представления контроллеров представлений внутри иерархии представлений, поэтому они также захватывают поведение scrollsToTop и вмешиваются. Это означает, что вам нужно отключить scrollsToTop для каждого прокручиваемого представления внутри viewWillDisappear: исчезающих контроллеров представления (и снова включить его на viewWillAppear:).


Оригинальное расследование

Быстрый и простой способ: просмотр прокрутки является единственным подзором представления UIPageViewController:

self.pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];

Проверка в отладчике:

(lldb) po [self.pageViewController.view recursiveDescription]
<_UIPageViewControllerContentView: 0x8d7c390; frame = (0 0; 320 480); clipsToBounds = YES; opaque = NO; autoresize = W+H; layer = <CALayer: 0x8d7c4a0>>
   | <_UIQueuingScrollView: 0xa912800; frame = (0 0; 320 480); clipsToBounds = YES; gestureRecognizers = <NSArray: 0x8d7cc90>; layer = <CALayer: 0x8d7c7e0>; contentOffset: {320, 0}>
   |    | <UIView: 0x8d7da00; frame = (0 0; 320 480); layer = <CALayer: 0x8d7da60>>
   |    | <UIView: 0x8d7dab0; frame = (320 0; 320 480); layer = <CALayer: 0x8d7db10>>
   |    | <UIView: 0x8d7db40; frame = (640 0; 320 480); layer = <CALayer: 0x8d7dba0>>

Для достижения этого прокрутки можно использовать несколько методов. Самое простое - перебрать self.pageViewController.view.subviews и найти тот, который является подклассом UIScrollView. Поскольку это единственное подчинение, ваш цикл завершится после одной итерации.

Является ли это решение оптимальным? Нет. Это ошибка? Теоретически, конечно. Возможно, это изменится? Скорее всего, поскольку иерархия представлений довольно логична. Это, по крайней мере, дает вам быстрое решение, вместо того, чтобы иметь дело с изменением всей структуры приложения из-за небольшого надзора со стороны Apple (предоставление пользователю доступа к просмотру прокрутки).

Вы должны открыть запрос функции с Apple над https://bugreport.apple.com.

Ответ 2

Документы iOS 7 на -scrollToTop говорят

На iPhone жест жестов в прокрутке не влияет, если есть больше чем один экран прокрутки на экране с параметрами свитковToTop на YES.

Я использую UIPageViewController так же, как и вы; одним из моих контролеров страниц является UITableViewController. Таким образом, я получаю окраску с помощью политики two-scrollviews-onscreen-no-scrolltotop.

Идея Kyle для реализации собственного поведения scrollToTop с помощью невидимой кнопки, вероятно, является вашей самой надежной ставкой в ​​этой ситуации.

Ответ 3

В моем случае у меня был UITableView в контроллерах представлений дочерних элементов UIPageViewController. Вытягивая предложения Льва Натана, добавив это в мой контроллер просмотра для детей, он выполнил задание:

- (void)viewWillAppear:(BOOL)animated 
{
    [super viewWillAppear:animated];
    self.tableView.scrollsToTop = YES; 
}

- (void)viewWillDisappear:(BOOL)animated 
{
    [super viewWillDisappear:animated];
    self.tableView.scrollsToTop = NO; 
}

Как уже упоминалось, конкурирующий UIScrollView в контроллерах дочерних представлений будет мешать друг другу методу делегата scrollsToTop. Этот код гарантирует, что только один из них имеет свитокToTop включен за один раз.

Ответ 4

Я использовал это:

for v in view.subviews {
    if v.isKindOfClass(UIScrollView) {
        (v as! UIScrollView).scrollsToTop = false
    }
}

Но если есть еще другие scrollviews, которые можно прокручивать вверх, ваш не будет работать. Используйте этот script, чтобы узнать ваши другие просмотры прокрутки: fooobar.com/questions/250108/..., затем отключите их прокрутку вверх.

Затем в диспетчере представлений, где вы хотите выполнить прокрутку вверх, чтобы работать, добавьте следующее:

override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)
    tableView.scrollsToTop = true
}

override func viewWillDisappear(animated: Bool) {
    super.viewWillDisappear(animated)
    tableView.scrollsToTop = false
}

Ответ 5

Я думаю, что лучшим решением будет использование следующих двух методов протокола UIPageViewControllerDelegate (быстрая и грязная версия, учитывая, что на экране есть только один контроллер вида):

- (void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray *)pendingViewControllers
{
    ((UITableViewController *)pendingViewControllers[0].tableView).scrollsToTop = YES;
}

- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed
{
    ((UITableViewController *)previousViewControllers[0].tableView).scrollsToTop = NO;
}

Изменить: лучше использовать подход указанный в последнем абзаце принятого ответа