2014-01-10 5 views
56

Относительно этого tutorial by AppCoda about how to implement a app with UIPageViewController Я бы хотел использовать элемент управления пользовательской страницы поверх страниц, а не снизу.Как поместить элемент UIPageControl поверх скользящих страниц в UIPageViewController?

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

Как можно поместить элемент управления поверх представлений, чтобы изображения страниц были полными (например, с изображением), чтобы пользователь мог видеть представления под фиксированным элементом управления?

Я прикрепил пример скриншот - кредиты AppCoda and Path:

enter image description here

ответ

49

После дальнейшего исследования и поиска I found a solution, а также на StackOverflow.

Ключ следующее сообщение для отправки пользовательского UIPageControl элемента:

[self.view bringSubviewToFront:self.pageControl]; 

The AppCoda tutorial is the foundation for this solution:

Добавить UIPageControl элемент на вершине RootViewController - контроллер вида со стрелкой.

Создать связанный IBOutlet элемент в ViewController.m.

В методе viewDidLoad вы должны добавить следующий код в качестве последнего метода, который вы вызываете после добавления всех подзонов.

[self.view bringSubviewToFront:self.pageControl]; 

Чтобы назначить текущую страницу на основе pageIndex текущего контента зрения можно добавить следующее к UIPageViewControllerDataSource методов:

- (UIPageViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController 
{ 
    // ... 
    index--; 
    [self.pageControl setCurrentPage:index]; 

    return [self viewControllerAtIndex:index]; 
} 

- (UIPageViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController 
{ 
    // ... 
    index++; 
    [self.pageControl setCurrentPage:index]; 

    // ... 
    return [self viewControllerAtIndex:index]; 
} 
+2

странно для меня, установив страницу страницы контроля, прежде чем увеличивать/уменьшать индекс. Контроллером viewController, который я получал от этого метода, был контроллер ** нового вида, а не тот, который был до перехода **. – Gokul

+0

Это совсем не странно; это ожидается. Эти методы вызывают в контроллере * current * view, чтобы определить, что будет дальше. –

+0

@ sn3ek Как создать связанный элемент IBOutlet. – VJVJ

27

sn3ek Ваш ответ заставил меня большую часть пути. Однако я не установил текущую страницу, используя методы viewControllerCreation.

Я сделал свой ViewController also делегатом от UIPageViewController. Затем я установил PageControlCurrentPage в этом методе. Использование pageIndex поддерживается в качестве ссылки ContentViewController в оригинальной статье.

- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed 
{ 
    APPChildViewController *currentViewController = pageViewController.viewControllers[0]; 
    [self.pageControl setCurrentPage:currentViewController.pageIndex]; 
} 

не забудьте добавить это viewDidLoad

self.pageViewController.delegate = self; 

Чтобы следить за комментариями PROPELLERHEAD в интерфейс для ViewController будет иметь вид

@interface ViewController : UIViewController <UIPageViewControllerDataSource, UIPageViewControllerDelegate> 
+2

Просто, чтобы быть ясным. Делегатом UIPageViewController является UIPageViewControllerDelegate, поэтому интерфейс вашего ViewController будет выглядеть примерно так: '' '@interface ViewController: UIViewController ' '' – PropellerHead

+1

Это правильно. – Coderdad

2

Тот же эффект может быть достигается просто путем подклассификации UIPageViewController и переопределения viewDidLayoutSubviews следующим образом:

-(void)viewDidLayoutSubviews { 
    UIView* v = self.view; 
    NSArray* subviews = v.subviews; 
    if([subviews count] == 2) { 
     UIScrollView* sv = nil; 
     UIPageControl* pc = nil; 
     for(UIView* t in subviews) { 
      if([t isKindOfClass:[UIScrollView class]]) { 
       sv = (UIScrollView*)t; 
      } else if([t isKindOfClass:[UIPageControl class]]) { 
       pc = (UIPageControl*)t; 
      } 
     } 
     if(sv != nil && pc != nil) { 
      // expand scroll view to fit entire view 
      sv.frame = v.bounds; 
      // put page control in front 
      [v bringSubviewToFront:pc]; 
     } 
    } 
    [super viewDidLayoutSubviews]; 
} 

Тогда нет необходимости поддерживать отдельный UIPageControl и т. Д.

+2

Мне действительно понравился этот ответ. Он работал хорошо. Пока я не включил iPhone 4S под управлением iOS 7.1. В этот момент все прошло бесконечно. Не знаю почему, но будьте осторожны. –

48

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

class UIPageViewControllerWithOverlayIndicator: UIPageViewController { 
    override func viewDidLayoutSubviews() { 
     for subView in self.view.subviews as! [UIView] { 
      if subView is UIScrollView { 
       subView.frame = self.view.bounds 
      } else if subView is UIPageControl { 
       self.view.bringSubviewToFront(subView) 
      } 
     } 
     super.viewDidLayoutSubviews() 
    } 
} 

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

+0

Когда я помещаю этот цикл в ViewDidLoad, я могу найти scrollView, но не представление UIPageControl. я что-то упускаю ? – Hakim

+0

@ Хаким, возможно, у контроллера отсутствует тип UIPageViewController? Трудно сказать без примера точной ситуации. –

+1

Я собираюсь добавить это в закладки только для того, насколько это универсально и полезно. Thankx так много !! –

0

Вот ответ Swifty 2, основанный на ответе @ zerotool выше. Просто подкласс UIPageViewController, а затем добавьте это переопределение, чтобы найти scrollview и изменить его размер. Затем захватите элемент управления страницей и переместите его в начало всего остального. Вам также необходимо установить цвет фона для элементов управления страницы. Эти две последние строки могут попасть в ваш делегат приложения.

override func viewDidLayoutSubviews() { 

    super.viewDidLayoutSubviews() 

    var sv:UIScrollView? 
    var pc:UIPageControl? 

    for v in self.view.subviews{ 

     if v.isKindOfClass(UIScrollView) { 

      sv = v as? UIScrollView 

     }else if v.isKindOfClass(UIPageControl) { 

      pc = v as? UIPageControl 
     } 
    } 

    if let newSv = sv { 

     newSv.frame = self.view.bounds 
    } 

    if let newPc = pc { 

     self.view.bringSubviewToFront(newPc) 
    } 
} 

let pageControlAppearance = UIPageControl.appearance() 
pageControlAppearance.backgroundColor = UIColor.clearColor() 

btw - Я не замечаю никаких бесконечных циклов, как упоминалось выше.

1

Вы должны ввести обычай UIPageControl и добавить его в представление. Как отмечали другие, необходимо называть view.bringSubviewToFront(pageControl).

У меня есть example контроллера вида со всем кодом по настройке пользовательских UIPageControl (в раскадровке) с UIPageViewController

Есть 2 способа, которые нужно реализовать, чтобы установить текущий индикатор страницы.

func pageViewController(pageViewController: UIPageViewController, willTransitionToViewControllers pendingViewControllers: [UIViewController]) { 
    pendingIndex = pages.indexOf(pendingViewControllers.first!) 
} 

func pageViewController(pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) { 
    if completed { 
     currentIndex = pendingIndex 
     if let index = currentIndex { 
      pageControl.currentPage = index 
     } 
    } 
} 
1

Вот RxSwift/RxCocoa ответ я соединял после просмотра других ответов.

let pages = Variable<[UIViewController]>([]) 
let currentPageIndex = Variable<Int>(0) 
let pendingPageIndex = Variable<(Int, Bool)>(0, false) 

let db = DisposeBag() 

override func viewDidLoad() { 
    super.viewDidLoad() 
    pendingPageIndex 
     .asDriver() 
     .filter { $0.1 } 
     .map { $0.0 } 
     .drive(currentPageIndex) 
     .addDisposableTo(db) 

    currentPageIndex.asDriver() 
     .drive(pageControl.rx.currentPage) 
     .addDisposableTo(db) 
} 

func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) { 
    if let index = pages.value.index(of: pendingViewControllers.first!) { 
     pendingPageIndex.value = (index, false) 
    } 
} 

func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) { 
    pendingPageIndex.value = (pendingPageIndex.value.0, completed) 
} 
Смежные вопросы