У меня есть простой UIPageViewController, который отображает UIPageControl по умолчанию в нижней части страниц. Интересно, возможно ли изменить положение UIPageControl, например, чтобы быть сверху экрана, а не снизу. Я искал вокруг и только нашел старые дискуссии, которые говорят, что мне нужно создать свой собственный UIPageControl. Является ли это проще с iOS8 и 9? Благодарю.
Как изменить положение UIPageControl в iOS> = 8.0?
Ответ 1
Да, для этого вы можете добавить настраиваемый контроллер страниц.
self.pageControl = [[UIPageControl alloc] initWithFrame:CGRectMake(0, self.view.frame.size.height - 50, self.view.frame.size.width, 50)]; // your position
[self.view addSubview: self.pageControl];
затем удалите
- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController
а также
- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController
Затем добавьте еще один метод делегата:
- (void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray<UIViewController *> *)pendingViewControllers
{
PageContentViewController *pageContentView = (PageContentViewController*) pendingViewControllers[0];
self.pageControl.currentPage = pageContentView.pageIndex;
}
Ответ 2
Ответ Shameerjan очень хорош, но для его работы требуется еще одна вещь, и это реализация другого метода делегата:
func pageViewController(pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
// If user bailed our early from the gesture,
// we have to revert page control to previous position
if !completed {
let pageContentView = previousViewControllers[0] as! PageContentViewController;
self.pageControl.currentPage = pageContentView.pageIndex;
}
}
Это связано с тем, что, если вы этого не сделаете, если вы слегка перемещаете элемент управления страницей, он вернется к предыдущей позиции, но элемент управления страницы отобразит другую страницу.
Надеюсь, поможет!
Ответ 3
Переопределите viewDidLayoutSubviews() на странице viewcontroller и используйте это
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// get pageControl and scroll view from view subviews
let pageControl = view.subviews.filter{ $0 is UIPageControl }.first! as! UIPageControl
let scrollView = view.subviews.filter{ $0 is UIScrollView }.first! as! UIScrollView
// remove all constraint from view that are tied to pagecontrol
let const = view.constraints.filter { $0.firstItem as? NSObject == pageControl || $0.secondItem as? NSObject == pageControl }
view.removeConstraints(const)
// customize pagecontroll
pageControl.translatesAutoresizingMaskIntoConstraints = false
pageControl.addConstraint(pageControl.heightAnchor.constraintEqualToConstant(35))
pageControl.backgroundColor = view.backgroundColor
// create constraints for pagecontrol
let leading = pageControl.leadingAnchor.constraintEqualToAnchor(view.leadingAnchor)
let trailing = pageControl.trailingAnchor.constraintEqualToAnchor(view.trailingAnchor)
let bottom = pageControl.bottomAnchor.constraintEqualToAnchor(scrollView.topAnchor, constant:8) // add to scrollview not view
// pagecontrol constraint to view
view.addConstraints([leading, trailing, bottom])
view.bounds.origin.y -= pageControl.bounds.maxY
}
Ответ 4
Просто найдите "PageControl" в подклассе PageViewController и установите фрейм, местоположение или что угодно
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
for subView in view.subviews {
if subView is UIPageControl {
subView.frame.origin.y = self.view.frame.size.height - 164
}
}
}
Ответ 5
Да, ответ Shameerjan очень хорош, но вместо добавления другого элемента управления страницей можно использовать индикатор страницы по умолчанию:
- (UIPageControl*)pageControl {
for (UIView* view in self.view.subviews) {
if ([view isKindOfClass:[UIPageControl class]]) {
//set new pageControl position
view.frame = CGRectMake( 100, 200, width, height);
return (id)view;
}
}
return nil;
}
а затем увеличьте размер UIPageViewController, чтобы скрыть нижний зазор:
//somewhere in your code
self.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height+40);
Ответ 6
Для быстрого:
self.pageController = UIPageControl(
frame: CGRect(
x: 0,
y: self.view.frame.size.height - 50,
width: self.view.frame.size.width,
height: 50
)
)
self.view.addSubview(pageController)
Помните, что используйте pageController.numberOfPages и делегируйте страницуView
затем удалите
func presentationCountForPageViewController(
pageViewController: UIPageViewController
) -> Int
а также
func presentationIndexForPageViewController(
pageViewController: UIPageViewController
) -> Int
Затем добавьте еще один метод делегата:
func pageViewController(
pageViewController: UIPageViewController,
willTransitionToViewControllers pendingViewControllers:[UIViewController]){
if let itemController = pendingViewControllers[0] as? PageContentViewController {
self.pageController.currentPage = itemController.pageIndex
}
}
}
Ответ 7
здесь очень эффективный способ изменить положение стандартного PageControl для PageViewController, не имея необходимости создавать новый...
extension UIPageViewController {
override open func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
for subV in self.view.subviews {
if type(of: subV).description() == "UIPageControl" {
let pos = CGPoint(x: subV.frame.origin.x, y: subV.frame.origin.y - 75 * 2)
subV.frame = CGRect(origin: pos, size: subV.frame.size)
}
}
}
}
Ответ 8
Swift 4 версии @Jan ответ с исправленной ошибкой, когда пользователь отменяет переход:
Во-первых, вы создаете собственный pageControl:
let pageControl = UIPageControl()
Вы добавляете его в представление и позиционируете его так, как хотите:
self.view.addSubview(self.pageControl)
self.pageControl.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
self.pageControl.leftAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leftAnchor, constant: 43),
self.pageControl.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor, constant: -33)
])
Затем вам нужно инициализировать pageControl
:
self.pageControl.numberOfPages = self.dataSource.controllers.count
Наконец, вам нужно реализовать UIPageViewControllerDelegate
и его метод pageViewController(_:didFinishAnimating:previousViewControllers:transitionCompleted:)
:
func pageViewController(_ pageViewController: UIPageViewController,
didFinishAnimating finished: Bool,
previousViewControllers: [UIViewController],
transitionCompleted completed: Bool) {
// this will get you currently presented view controller
guard let selectedVC = pageViewController.viewControllers?.first else { return }
// and its index in the dataSource controllers (I'm using force unwrap, since in my case pageViewController contains only view controllers from my dataSource)
let selectedIndex = self.dataSource.controllers.index(of: selectedVC)!
// and we update the current page in pageControl
self.pageControl.currentPage = selectedIndex
}
Теперь, по сравнению с ответом @Jan, мы обновляем self.pageControl.currentPage
используя pageViewController(_:didFinishAnimating:previousViewControllers:transitionCompleted:)
(показано выше), вместо pageViewController(_:willTransitionTo:)
. Это преодолевает проблему отмененного перехода - pageViewController(_:didFinishAnimating:previousViewControllers:transitionCompleted:)
вызывается всегда, когда переход завершен (он также лучше имитирует поведение стандартного управления страницей).
Наконец, чтобы удалить стандартный элемент управления страницами, обязательно удалите реализацию методов presentationCount(for:)
и presentationIndex(for:)
UIPageViewControllerDataSource
- если методы будут реализованы, будет представлен стандартный элемент управления страницей.
Итак, вы НЕ хотите иметь это в своем коде:
func presentationCount(for pageViewController: UIPageViewController) -> Int {
return self.dataSource.controllers.count
}
func presentationIndex(for pageViewController: UIPageViewController) -> Int {
return 0
}
Ответ 9
Вот мой прием. Эта версия только изменяет индикатор, когда анимация завершена, т.е. когда вы добираетесь до целевой страницы.
/** Each page you add to the UIPageViewController holds its index */
class Page: UIViewController {
var pageIndex = 0
}
class MyPageController : UIPageViewController {
private let pc = UIPageControl()
private var pendingPageIndex = 0
// ... add pc to your view, and add Pages ...
/** Will transition, so keep the page where it goes */
func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController])
{
let controller = pendingViewControllers[0] as! Page
pendingPageIndex = controller.pageIndex
}
/** Did finish the transition, so set the page where was going */
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool)
{
if (completed) {
pc.currentPage = pendingPageIndex
}
}
}
Ответ 10
Это хорошо, и с большим изменением
var pendingIndex = 0;
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
if completed {
pageControl.currentPage = pendingIndex
}
}
func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) {
let itemController = pendingViewControllers.first as! IntroPageItemViewController
pendingIndex = itemController.itemIndex
}
Ответ 11
Убедитесь, что параметр pageControl добавлен как subview. Затем в
-(void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
CGRect frame = self.pageControl.frame;
frame.origin.x = self.view.frame.size.width/2 -
frame.size.width/2;
frame.origin.y = self.view.frame.size.height - 100 ;
self.pageControl.numberOfPages = self.count;
self.pageControl.currentPage = self.currentIndex;
self.pageControl.frame = frame;
}
Ответ 12
Просто получите первый контроллер представления и узнайте индекс в файле didFinishAnimating:
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
pageControl.currentPage = onboardingViewControllers.index(of: pageViewController.viewControllers!.first!)!
}