Как поместить элемент UIPageControl поверх скользящих страниц в UIPageViewController?
Относительно этого учебника от AppCoda о том, как реализовать приложение с UIPageViewController, я бы хотел использовать элемент управления настраиваемой страницы поверх страниц, а не дно.
Когда я просто помещаю элемент управления страницей поверх отдельных представлений, которые будут отображаться, логический результат состоит в том, что элементы управления прокручиваются с просмотром страницы вдали от экрана.
Как можно поместить элемент управления поверх представлений, чтобы представления страниц были в полноэкранном режиме (например, с изображением), чтобы пользователь мог видеть представления под фиксированным элементом управления?
Я прикрепил пример скриншота - кредиты AppCoda и путь:
![enter image description here]()
Ответы
Ответ 1
После дальнейшего изучения и поиска я нашел решение, также в stackoverflow.
Ключ - это следующее сообщение для отправки пользовательскому элементу UIPageControl
:
[self.view bringSubviewToFront:self.pageControl];
Учебник AppCoda является основой для этого решения:
Добавьте элемент 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
У меня не было комментариев, чтобы прокомментировать ответ, который возник из-за этого, но мне это очень нравится. Я улучшил код и преобразовал его в быстрый для ниже подкласса 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()
}
}
Очистите, и он работает хорошо. Не нужно ничего поддерживать, просто сделайте свой контроллер просмотра страницы экземпляром этого класса в раскадровке или сделайте свой собственный класс контроллера класса просмотра наследуемым от этого класса.
Ответ 3
sn3ek Ваш ответ дал мне большую часть пути. Я не установил текущую страницу, используя методы viewControllerCreation
.
Я сделал мой ViewController also
делегатом UIPageViewController
. Затем я устанавливаю PageControl
CurrentPage
в этом методе. Использование 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>
Ответ 4
Такой же эффект может быть достигнут просто путем подкласса 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 и т.д.
Ответ 5
Вам нужно реализовать пользовательский UIPageControl
и добавить его в представление. Как отмечали другие, нужно называть view.bringSubviewToFront(pageControl)
.
У меня есть пример контроллера вида со всем кодом при настройке пользовательского UIPageControl
(в раскадровке) с UIPageViewController
Существует два метода, которые необходимо выполнить, чтобы установить текущий индикатор страницы.
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
}
}
}
Ответ 6
Вот ответ 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)
}
Ответ 7
Здесь ответы 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 - Я не замечаю никаких бесконечных циклов, как упоминалось выше.