【问题标题】:Add border for dots in UIPageControl在 UIPageControl 中为点添加边框
【发布时间】:2016-03-07 11:02:23
【问题描述】:

我想为 UIPageControl 中的点添加边框颜色。这是它的小图:

我可以通过从 XCode 配置第二个点来放置第二个点,但我不能让第一个和第三个圆圈内部为空。有没有简单的方法来实现?

谢谢:)

【问题讨论】:

    标签: ios uipagecontrol


    【解决方案1】:

    已编辑- Swift 3 & 4 扩展 以实现相同的结果-

    extension UIPageControl {
    
        func customPageControl(dotFillColor:UIColor, dotBorderColor:UIColor, dotBorderWidth:CGFloat) {
            for (pageIndex, dotView) in self.subviews.enumerated() {
                if self.currentPage == pageIndex {
                    dotView.backgroundColor = dotFillColor
                    dotView.layer.cornerRadius = dotView.frame.size.height / 2
                }else{
                    dotView.backgroundColor = .clear
                    dotView.layer.cornerRadius = dotView.frame.size.height / 2
                    dotView.layer.borderColor = dotBorderColor.cgColor
                    dotView.layer.borderWidth = dotBorderWidth
                }
            }
        }
    
    }
    

    要使用它,请在 viewDidLoad() 或 viewDidAppear() 中编写以下代码

    pageControl.customPageControl(dotFillColor: .orange, dotBorderColor: .green, dotBorderWidth: 2)
    

    Objective-C中使用下面的代码-

    - (void) customPageControlWithFillColor:(UIColor*)dotFillColor borderColor:(UIColor*)dotBorderColor borderWidth:(CGFloat)dotBorderWidth {
        for (int pageIndex = 0; pageIndex < _pageControl.numberOfPages; pageIndex++) {
            UIView* dotView = [_pageControl.subviews objectAtIndex:pageIndex];
            if (_pageControl.currentPage == pageIndex) {
                dotView.backgroundColor = dotFillColor;
                dotView.layer.cornerRadius = dotView.frame.size.height / 2;
            } else {
                dotView.backgroundColor = [UIColor clearColor];
                dotView.layer.cornerRadius = dotView.frame.size.height / 2;
                dotView.layer.borderColor = dotBorderColor.CGColor;
                dotView.layer.borderWidth = dotBorderWidth;
            }
        }
    }
    

    输出-

    【讨论】:

    • 还有其他方法可以实现吗?
    • @EmrahAkgül 如果您在情节提要中设置页面控件,请尝试在viewDidAppear 之后调用for 循环。它对我有用。当我在viewDidLoad 中调用循环时它不起作用。谢谢@RiosK
    • borderColorborderWidth 设置就足够了。其余的都不需要。可以使用pageIndicatorTintColorcurrentPageIndicatorTintColor 设置状态的backgroundColor。赞成这个,因为它有帮助。确保在视图出现后调用,就像上面提到的@TheRohanSanap。
    • @iPeter 它在我的案例中显示。参考附件。
    • 如果视图层次结构因操作系统更新而改变,迭代子视图可能随时中断。
    【解决方案2】:

    另一种方法是使用正确尺寸的图案图像(目前直径为 7 个点)。结果如下所示:

    这是如何完成的:

    let image = UIImage.outlinedEllipse(size: CGSize(width: 7.0, height: 7.0), color: .darkGray)
    self.pageControl.pageIndicatorTintColor = UIColor.init(patternImage: image!)
    self.pageControl.currentPageIndicatorTintColor = .darkGray
    

    它使用UIImage这个简单的小扩展:

    /// An extension to `UIImage` for creating images with shapes.
    extension UIImage {
    
        /// Creates a circular outline image.
        class func outlinedEllipse(size: CGSize, color: UIColor, lineWidth: CGFloat = 1.0) -> UIImage? {
    
            UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
            guard let context = UIGraphicsGetCurrentContext() else {
                    return nil
            }
    
            context.setStrokeColor(color.cgColor)
            context.setLineWidth(lineWidth)
            // Inset the rect to account for the fact that strokes are
            // centred on the bounds of the shape.
            let rect = CGRect(origin: .zero, size: size).insetBy(dx: lineWidth * 0.5, dy: lineWidth * 0.5)
            context.addEllipse(in: rect)
            context.strokePath()
    
            let image = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            return image
        }
    }
    

    这样做的缺点是,如果在操作系统更新中点大小发生变化,图像会看起来很奇怪,因为它会被平铺或剪裁。

    【讨论】:

    • 这在 iOS 14.7.1 版本上无法正常工作
    【解决方案3】:

    SWIFT 3 版本来自@RiosK

    func updatePageControl() {
        for (index, dot) in pageControl.subviews.enumerated() {
            if index == pageControl.currentPage {
                dot.backgroundColor = dotColor
                dot.layer.cornerRadius = dot.frame.size.height / 2;
            } else {
                dot.backgroundColor = UIColor.clear
                dot.layer.cornerRadius = dot.frame.size.height / 2
                dot.layer.borderColor = dotColor.cgColor
                dot.layer.borderWidth = dotBorderWidth
            }
        }
    }
    

    【讨论】:

    • 我必须在 viewDidAppear 和 didFinishAnimating 中加入 call nice 函数才能让它工作。
    【解决方案4】:

    斯威夫特 4。您可以分配borderColor,然后观察currentPage 属性来改变点的边框:

    class CustomPageControl: UIPageControl {
    
        var borderColor: UIColor = .clear
    
        override var currentPage: Int {
            didSet {
                updateBorderColor()
            }
        }
    
        func updateBorderColor() {
            subviews.enumerated().forEach { index, subview in
                if index != currentPage {
                    subview.layer.borderColor = borderColor.cgColor
                    subview.layer.borderWidth = 1
                } else {
                    subview.layer.borderWidth = 0
                }
            }
        }
    
    }
    

    【讨论】:

      【解决方案5】:

      对于UIPageControl 可用的当前属性,这是不可能的。但是您可以通过集成任何模仿 iOS UIPageControl 功能的 third party 页面控件来实现。

      其他答案已应用补丁。我非常不同意这个解决方案。

      【讨论】:

      • “其他答案已应用补丁。”还有什么解决办法
      【解决方案6】:

      我正在使用SMPageControl。这是一个用 Objective-C 编写的非常棒的框架,因此它支持 Swift 2 和 Swift 3。

      用法完全简单:

      pod 'SMPageControl'
      

      然后在你的PageViewController:

      import SMPageControl
      
      class MyController: UIPageViewController {
      
           var pageControl = SMPageControl()
      
           override func viewDidLoad() {
              super.viewDidLoad()
      
              stylePageControl()
          }
      
      private func stylePageControl() {
      
          pageControl = SMPageControl(frame: CGRect(x: 0, y: self.view.frame.size.height - 50, width: self.view.frame.size.width, height: 50))
          pageControl.numberOfPages = yourPageControllerArray.count
      
      //  the first (first) picture is the item in the bar, that is unused
      //  the second (currentFirst) is an item that we use, when this is the current active page
      //  in this example, we don't have dots, but we use "pictues" as dots
      
          let first = UIImage(named: "pageHome")?.imageWithColor(UIColor.grayColor())
          let currentFirst = first?.imageWithColor(UIColor.whiteColor())
      
          pageControl.setImage(first, forPage: 0)
          pageControl.setCurrentImage(currentFirst, forPage: 0)
      
          let second = UIImage(named: "pageMusic")?.imageWithColor(UIColor.grayColor())
          let currentSecond = second?.imageWithColor(UIColor.whiteColor())
      
          pageControl.setImage(second, forPage: 1)
          pageControl.setCurrentImage(currentSecond, forPage: 1)
      
          pageControl.indicatorMargin = 30.0 // this is the space between the dots
      
          self.view.addSubview(pageControl)
      }
      

      我使用过的 UIImage 扩展:

      extension UIImage {
      
          func imageWithColor(color1: UIColor) -> UIImage {
              UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale)
              color1.setFill()
      
              let context = UIGraphicsGetCurrentContext()! as CGContextRef
              CGContextTranslateCTM(context, 0, self.size.height)
              CGContextScaleCTM(context, 1.0, -1.0);
              CGContextSetBlendMode(context, CGBlendMode.Normal)
      
              let rect = CGRectMake(0, 0, self.size.width, self.size.height) as CGRect
              CGContextClipToMask(context, rect, self.CGImage!)
              CGContextFillRect(context, rect)
      
              let newImage = UIGraphicsGetImageFromCurrentImageContext()! as UIImage
              UIGraphicsEndImageContext()
      
              return newImage
          }
      
      }
      

      结果如下:

      现在我们当然可以使用彩色点作为图像,(空白为未使用,彩色填充为已使用)然后我们将得到要求的结果。

      【讨论】:

        【解决方案7】:

        只需添加这两行并添加所需的图像!

        pageControl.currentPageIndicatorTintColor  = UIColor.init(patternImage: UIImage(named: "slider_selected")!)
        
        pageControl.pageIndicatorTintColor =  UIColor.init(patternImage: UIImage(named: "slider")!)
        

        【讨论】:

          【解决方案8】:

          请试试这个 UIPageControl 的自定义子类。 iOS 14 允许使用 SFSymbol 设置指示器图像。

          class BorderedPageControl: UIPageControl {
          
              var selectionColor: UIColor = .black
              
              override var currentPage: Int {
                  didSet {
                      updateBorderColor()
                  }
              }
              
              override init(frame: CGRect) {
                  super.init(frame: frame)
                  currentPageIndicatorTintColor = selectionColor
              }
              
              required init?(coder: NSCoder) {
                  super.init(coder: coder)
              }
              
              func updateBorderColor() {
                  if #available(iOS 14.0, *) {
                      let smallConfiguration = UIImage.SymbolConfiguration(pointSize: 8.0, weight: .bold)
                      let circleFill = UIImage(systemName: "circle.fill", withConfiguration: smallConfiguration)
                      let circle = UIImage(systemName: "circle", withConfiguration: smallConfiguration)
                      for index in 0..<numberOfPages {
                          if index == currentPage {
                              setIndicatorImage(circleFill, forPage: index)
                          } else {
                              setIndicatorImage(circle, forPage: index)
                          }
                      }
                      pageIndicatorTintColor = selectionColor
                  } else {
                      subviews.enumerated().forEach { index, subview in
                          if index != currentPage {
                              subview.layer.borderColor = selectionColor.cgColor
                              subview.layer.borderWidth = 1
                          } else {
                              subview.layer.borderWidth = 0
                          }
                      }
                  }
              }
          }
          

          【讨论】:

          • 最后,这适用于我的 3 台设备:iOS 14.7.1、12.4.1 和 12.3.1
          【解决方案9】:

          Swift 5 版本

          func customPageControl(dotFillColor: UIColor, dotBorderColor: UIColor, dotBorderWidth: CGFloat) {
              for (pageIndex, dotView) in self.subviews.enumerated() {
                  dotView.backgroundColor = currentPage == pageIndex ? dotFillColor : .clear
                  dotView.layer.cornerRadius = dotView.frame.size.height / 2
                  dotView.layer.borderColor = dotBorderColor.cgColor
                  dotView.layer.borderWidth = dotBorderWidth
              }
          }
          

          【讨论】:

            【解决方案10】:

            需要在viewDidAppear中添加这个

             for (int i = 0; i < _pageControl.numberOfPages; i++) {
                    UIView* dot = [_pageControl.subviews objectAtIndex:i];
                    if (i == _pageControl.currentPage) {
                        dot.backgroundColor = [UIColor whiteColor];
                        dot.layer.cornerRadius = dot.frame.size.height / 2;
                    } else {
                        dot.backgroundColor = [UIColor clearColor];
                        dot.layer.cornerRadius = dot.frame.size.height / 2;
                        dot.layer.borderColor = [UIColor whiteColor].CGColor;
                        dot.layer.borderWidth = 1;
                    }
                }
            

            【讨论】:

              【解决方案11】:

              Luke Rogers的解决方案,用objective-c编写:

              -(UIImage *) outlinedEllipse:(CGSize)size color: (UIColor*) lineColor width:(CGFloat) lineWidth {
                      UIGraphicsBeginImageContextWithOptions(size, false, 0.0);
              
                      CGContextRef context = UIGraphicsGetCurrentContext();
                      if (context == NULL) {
                          return NULL;
                      }
              
                      CGContextSetStrokeColorWithColor(context, lineColor.CGColor);
                      CGContextSetLineWidth(context, lineWidth);
                      // Inset the rect to account for the fact that strokes are
                      // centred on the bounds of the shape.
              
                      CGRect rect = CGRectInset(CGRectMake(0, 0, 7.0f, 7.0f), lineWidth * 0.5, lineWidth * 0.5);
                      CGContextAddEllipseInRect(context, rect);
                      CGContextStrokePath(context);
              
                      UIImage* image = UIGraphicsGetImageFromCurrentImageContext();
                      UIGraphicsEndImageContext();
                      return image;
              }
              

              【讨论】:

                【解决方案12】:

                现代 Luke Rogers(elk_cloner 说它对于 ios14 来说不够现代)

                extension UIImage
                {
                // https://stackoverflow.com/questions/35842040/add-border-for-dots-in-uipagecontrol
                    // modernized Luke Rogers
                    class func outlinedEllipse(size: CGSize, color: UIColor, lineWidth: CGFloat = 1.0) -> UIImage? {
                
                        let renderer = UIGraphicsImageRenderer(size: size)
                        let image = renderer.image { context in
                
                            color.setFill()
                            
                            context.cgContext.setLineWidth(lineWidth)
                            // Inset the rect to account for the fact that strokes are
                            // centred on the bounds of the shape.
                            let rect = CGRect(origin: .zero, size: size).insetBy(dx: lineWidth * 0.5, dy: lineWidth * 0.5)
                            context.cgContext.strokeEllipse(in: rect)
                        }
                        return image
                    }
                    
                }
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2020-07-18
                  • 2021-06-17
                  • 2016-12-02
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多