我们可以在 UIPageViewController 中自定义页面指示器吗?

Posted

技术标签:

【中文标题】我们可以在 UIPageViewController 中自定义页面指示器吗?【英文标题】:Can we customize the page indicator in UIPageViewController? 【发布时间】:2013-07-04 09:29:14 【问题描述】:

现在是黑色背景的白点。如果我希望它是白色背景的黑点呢?

- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController NS_AVAILABLE_ios(6_0)

    return _imageArrays.count;
// The number of items reflected in the page indicator.
- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController NS_AVAILABLE_IOS(6_0)

    return self.intCurrentIndex;
// The selected item reflected in the page indicator.

【问题讨论】:

UIPageViewController 的 UIPageControl 缺少自定义钩子是一个真正的问题。显然,您不能重新定位它或更改颜色。如果只有一页,您也不能告诉它隐藏。事实上,UIPageViewController 是一个非常糟糕的类——不能很好地使用自动布局,创建各种神奇的子视图等。不幸的是,使用 UIScrollView 进行分页也是有问题的,因为它为你打开内存管理问题的大门。有很多页面。 raywenderlich.com/21703/user-interface-customization-in-ios-6 我在 Swift 4 中有一个解决方案。请在下面查看我的答案。 【参考方案1】:

你可以使用UIAppearance来改变UIPageControl的颜色。在 AppDelegate 的 didFinishLaunchingWithOptions 函数中试试这个。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

    UIPageControl *pageControl = [UIPageControl appearance];
    pageControl.pageIndicatorTintColor = [UIColor lightGrayColor];
    pageControl.currentPageIndicatorTintColor = [UIColor blackColor];
    pageControl.backgroundColor = [UIColor blueColor];

    return YES;

编辑:

要将样式仅应用于特定的视图控制器,请改用appearanceWhenContainedIn,如下所示:

UIPageControl *pageControl = [UIPageControl appearanceWhenContainedIn:[MyViewController class], nil];

现在,只有 MyViewController 中包含的 UIPageControl 对象会适应这种风格。

感谢 Mike 和 Shinoo!

编辑: 如果您在屏幕底部看到UIPageControl 周围的黑色背景,这是由于您的UIPageViewController 的背景颜色而不是UIPageControl。您可以按如下方式更改此颜色:

- (void)viewDidLoad 
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor blueColor]; //Set it to whatever you like

【讨论】:

如果想避免全局更改页面控件,您可以进一步使用[UIPageControl appearenceInContainer:[MyViewController class], nil] [UIPageControl appearanceWhenContainedIn:[MyViewController class], nil] 应该是正确的 我喜欢这个答案。更简洁。 您可以将其添加到您的 PageViewControllers 超级控制器中,而不是 App 委托。但是为此 +1,比我发现的其他解决方案要好得多。 @Yas 我认为 PageControl 的背景颜色是由于视图控制器的 backGroundColor 导致我在 pageviewController 中有 imageViews 并且 PageControl 存在于这些图像上方并且设置 backGroundColor 属性不会更改 PageControl 颜色。 【参考方案2】:

我不相信你可以操纵 UIPageViewController 的页面控件。我的解决方案:

我有一个“根”UIViewController,即 UIPageViewControllerDelegate 和 UIPageViewControllerDataSource。

在这个根视图控制器上,我有@property (strong, nonatomic) IBOutlet UIPageControl *pageControl。在相应的故事板笔尖中,我添加了一个 UIPageControl,定位它,然后选中“隐藏单页”。如果我愿意,我也可以更改颜色。

然后,我在根视图控制器的 viewDidLoad 中添加以下内容:self.pageControl.numberOfPages = [self.features count]

我的根视图控制器也有@property (strong, nonatomic) UIPageViewController *pageViewController。在实施中:

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


self.pageViewController.delegate = self;
DataViewController *startingViewController = [self viewControllerAtIndex:0 storyboard:self.storyboard];
NSArray *viewControllers = @[startingViewController];
[self.pageViewController setViewControllers:viewControllers
                                  direction:UIPageViewControllerNavigationDirectionForward
                                   animated:NO
                                 completion:NULL];
self.pageViewController.dataSource = self;      
[self addChildViewController:self.pageViewController];
[self.view addSubview:self.pageViewController.view];
self.pageViewController.view.frame = CGRectMake(0.0, 0.0, [[UIScreen mainScreen] bounds].size.width, [[UIScreen mainScreen] bounds].size.height + 10.0);
[self.pageViewController didMoveToParentViewController:self];
self.view.gestureRecognizers = self.pageViewController.gestureRecognizers;

(旁注:设置框架的那条线使 UIPageViewController 的视图的高度超过屏幕尺寸,因此本机页面控件不再可见。我的应用程序仅是纵向的,仅适用于 iPhone,所以我稍微下车了在这里很容易。如果您需要处理旋转,则必须找到一种方法使本机页面控件保持在屏幕外。我尝试使用自动布局,但 UIPageViewController 创建了一组具有一堆自动布局掩码约束的魔术视图,我找不到覆盖的方法。)

无论如何...然后我添加一个额外的 UIPageViewController 委托方法来将我的新的非本机 UIPageControl 更改为当前选择的页面:

- (void)pageViewController:(UIPageViewController *)viewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed

  if (!completed)return;

  // Find index of current page
  DataViewController *currentViewController = (DataViewController *)[self.pageViewController.viewControllers lastObject];
  NSUInteger indexOfCurrentPage = [self indexOfViewController:currentViewController];
  self.pageControl.currentPage = indexOfCurrentPage;

没有我想的那么漂亮,但是 Apple 的这个类的 API 并不完全适合优雅。

【讨论】:

无需调整视图框架的大小。如果您不实现数据源页面指示器方法,则不会出现本机页面控件并且不会添加视图底部的额外边距。 非常感谢。这个页面视图控制器解决了我的问题。就我而言,我不需要 self.view.gestureRecognizers = self.pageViewController.gestureRecognizers;而且,我设置了 pageControl.userInteractionEnabled = NO;因此,当我们在 pageControl 中滑动时,它不会更新 currentPage 属性,但 pageViewController 不会更改视图控制器。【参考方案3】:

您实际上可以在其中一个委托调用中获取它并将其本地存储在您自己的属性中。

将此代码放入您的委托中以访问 UIPageViewController 中的 UIPageControl:

- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController

    [self setupPageControlAppearance];
    return kPageCount;


- (void)setupPageControlAppearance

    UIPageControl * pageControl = [[self.view.subviews filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"(class = %@)", [UIPageControl class]]] lastObject];
    pageControl.pageIndicatorTintColor = [UIColor grayColor];
    pageControl.currentPageIndicatorTintColor = [UIColor blackColor];

【讨论】:

【参考方案4】:

您可以在子视图中递归搜索它

- (void)findAndConfigurePageControlInView:(UIView *)view

    for (UIView *subview in view.subviews) 
        if ([subview isKindOfClass:[UIPageControl class]]) 
            UIPageControl * pageControl = (UIPageControl *)subview;
            //customize here
            pageControl.hidesForSinglePage = YES;
            break;
         else 
            [self findAndConfigurePageControlInView:subview];
        
    


- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController

    [self findAndConfigurePageControlInView:self.view];
    return self.promotionsVCs.count;

对我有用

【讨论】:

我尝试了类似的方法,但我从来没有找到作为 UIPageControl 的子视图。请在下面查看我的回答,了解我的所作所为。【参考方案5】:
UIPageControl *pageControl = [UIPageControl appearanceWhenContainedIn:[MyViewController class], nil];
pageControl.pageIndicatorTintColor = [UIColor whiteColor];
pageControl.currentPageIndicatorTintColor = [UIColor redColor];
pageControl.backgroundColor = [UIColor blackColor];

这将改变“MyViewController”的外观。如果您想在同一视图的不同页面指示器中使用不同的颜色,则必须创建不同的子视图并单独自定义它们。

【讨论】:

【参考方案6】:

这是我在 Swift 4 中所做的。我首先在 viewDidLoad 中尝试了类似的答案,但这最终奏效了。同样的 sn-p 用于回答类似的 SO 问题。

    override func viewDidLayoutSubviews() 
    super.viewDidLayoutSubviews()
    for view in self.view.subviews
        if view is UIPageControl
            (view as! UIPageControl).currentPageIndicatorTintColor = .yellow
            
        
    

在此块中拥有 UIPageControl 后,您应该能够自定义其指示器颜色

【讨论】:

【参考方案7】:

如果你使用 UIPageViewController 创建的“自动生成”页面指示器,我认为你不能自定义它。您可以这样做的唯一方法是添加一个额外的 PageControl,可以是 Apple 提供的,也可以是 @Maschel 建议的自定义。

【讨论】:

【参考方案8】:

可以通过外观自定义。您可以像这样在 AppDelegate 中执行此操作。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

   UIPageControl *pageControl = [UIPageControl appearance];
   pageControl.pageIndicatorTintColor = [UIColor whiteColor];
   pageControl.currentPageIndicatorTintColor = [UIColor blackColor];
   pageControl.backgroundColor = [UIColor lightGrayColor];

   return YES;

如果您只想为某个视图控制器执行此操作,请将 pageControl 替换为此。

UIPageControl *pageControl = [UIPageControl appearanceWhenContainedIn:[MyViewController class], nil];

【讨论】:

【参考方案9】:

这个非常适合自定义图像

self.pageControl.pageIndicatorTintColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"page_indicater"]];

self.pageControl.currentPageIndicatorTintColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"page_indicater_selection"]];

【讨论】:

【参考方案10】:

您可以使用 SMPageControl:Github。它的工作方式与 UIPageControl 类似,但具有更多自定义可能性。

【讨论】:

请注意,这类似于 UIPageControl,而不是 UIPageController。我已经编辑了答案来解决这个问题,但我的编辑被拒绝了。不知道为什么。 因为问题是在寻找可以使用UIPageViewController提供的数据源的答案【参考方案11】:

您可以通过定义这样的计算属性轻松访问UIPageViewControllerpageControl

var pageControl: UIPageControl? 
    for subview in view.subviews 
        if let pageControl = subview as? UIPageControl 
            return pageControl
        
    
    return nil

然后像这样自定义它以满足您的需求:

override func viewDidLoad() 
    super.viewDidLoad()
    pageControl?.backgroundColor = .white
    pageControl?.pageIndicatorTintColor = .red
    pageControl?.currentPageIndicatorTintColor = .blue

明显的警告:如果 Apple 决定更改 UIPageViewController 视图层次结构,这将停止工作。

【讨论】:

以上是关于我们可以在 UIPageViewController 中自定义页面指示器吗?的主要内容,如果未能解决你的问题,请参考以下文章

我们可以在我们自己的数据库中存储美国客户的 ACH 详细信息吗?

Forge Viewer - 我们可以在加载的模型上进行选择/突出显示并保存在数据库中,以便我们可以在下次用户加载时显示该选择吗?

如果我们不提供广告,我们可以使用 IDFA

我们可以使用 Visual Studio 在 VSTS 中检查点吗?

我们可以在 C++ 中有一个静态类吗?

我们可以选择在 sklearn 中使用啥决策树算法吗?