在 UIPageControl 中为点添加边框

Posted

技术标签:

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

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

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

谢谢:)

【问题讨论】:

【参考方案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://***.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
    
    

【讨论】:

以上是关于在 UIPageControl 中为点添加边框的主要内容,如果未能解决你的问题,请参考以下文章

UIPageControl 点边框颜色

如何更改 UIPageControl 点的边框?

修复 UIPageControl(不是滑动)

如何在全屏 ChildViewController 上显示 UIPageControl?

如何在opencv中为图像添加边框,边框颜色必须与图像颜色相同

在文本视图中为边框添加一些填充