How to change borders of UIPageControl dots?
Asked Answered
K

4

5

Changing the colours is pretty straightforward, but is it possible to change the border of all unselected dots?

Ex:

dot.layer.borderWidth = 0.5 dot.layer.borderColor = UIColor.blackColor()

Katy answered 26/2, 2016 at 11:47 Comment(3)
I don't think that is possible. But you can easily implement your own page control that can do that.Snowblind
It is possible @dasdom. Check my answer below https://mcmap.net/q/1908996/-how-to-change-borders-of-uipagecontrol-dotsReitareiter
@KunalGupta I would highly suggest to not do this. This can break with every minor OS update.Snowblind
R
7

Yes This can be done.. Actually its pretty simple.

For iOS 14 Apple has introduced a great customization, where you can set custom images and even set background

let pageControl = UIPageControl()
pageControl.numberOfPages = 5

pageControl.backgroundStyle = .prominent

pageControl.preferredIndicatorImage = UIImage(systemName: "bookmark.fill")

pageControl.setIndicatorImage(UIImage(systemName: "heart.fill"), forPage: 0)

For prior to iOS 14:-

The Pagecontrol is composed of many Subviews which you can access. self.pageControl.subviews returns you [UIView] i.e array of UIView's. After you get a single view you can add border to it , change its borderColor, change its border width, transform the dot size like scaling it.. All those properties that a UIView has can be used.

                for index in 0..<array.count{ // your array.count
                
                let viewDot = weakSelf?.pageControl.subviews[index]
                viewDot?.layer.borderWidth = 0.5
                viewDot?.transform = CGAffineTransform(scaleX: 1.2, y: 1.2)
                
                if (index == indexPath.row){ // indexPath is the current indexPath of your selected cell or view in the collectionView i.e which needs to be highlighted
                    viewDot?.backgroundColor = UIColor.black
                    viewDot?.layer.borderColor = UIColor.black.cgColor
                }
                else{
                    viewDot?.backgroundColor = UIColor.white
                    viewDot?.layer.borderColor = UIColor.black.cgColor
                    
                }
            }

and it looks like this

enter image description here

And remember you do not need to set weakSelf?.pageControl.currentPage = indexPath.row.Do let me know in case of any problem.. Hope this solves your problem.

All the best

Reitareiter answered 18/10, 2016 at 6:54 Comment(4)
Hi! I tested your code (but in objective c) and I can't get the border. Can you help me please?Inoperative
Tested in Swift 4. Worked for me less than 2 min. Thanks, buddy, Its party time.Fro
Woohoooo Great to hear that it helped you ;) @FroReitareiter
can i have the code for the same in objective c?Monson
B
3

iOS 14 allows setting indicator image with SFSymbol here's my subclassing of UIPageControl

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
                }
            }
        }
    }
}
Barayon answered 22/9, 2020 at 10:5 Comment(0)
M
2

Extension for set pagecontrol indicator border / Swift 3

  extension UIImage {
    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)
        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
    }
  }

USE:

let image = UIImage.outlinedEllipse(size: CGSize(width: 7.0, height: 7.0), color: .lightGray)
self.pageControl.pageIndicatorTintColor = UIColor.init(patternImage: image!)
self.pageControl.currentPageIndicatorTintColor = .lightGray
Merri answered 7/8, 2017 at 12:55 Comment(0)
C
0

If anybody wants to CustomUIPageControl, then might need this

@IBDesignable
class CustomPageControl: UIView {
    
    var dotsView = [RoundButton]()
    var currentIndex = 0
    
    @IBInspectable var circleColor: UIColor = UIColor.orange {
        didSet {
            updateView()
        }
    }
    @IBInspectable var circleBackgroundColor: UIColor = UIColor.clear {
        didSet {
            updateView()
        }
    }
    @IBInspectable var numberOfDots: Int = 7 {
        didSet {
            updateView()
        }
    }
    @IBInspectable var borderWidthSize: CGFloat = 1 {
        didSet {
            updateView()
        }
    }
   
   override init(frame: CGRect) {
        super.init(frame: frame)
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    func  updateView() -> Void {
        for v in self.subviews{
            v.removeFromSuperview()
        }
        dotsView.removeAll()
        
        let stackView   = UIStackView()
        stackView.axis  = NSLayoutConstraint.Axis.horizontal
        stackView.distribution  = UIStackView.Distribution.fillEqually
        stackView.alignment = UIStackView.Alignment.center
        stackView.spacing   = 10
        stackView.translatesAutoresizingMaskIntoConstraints = false
        self.addSubview(stackView)

        //Constraints
        stackView.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
        stackView.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
        NSLayoutConstraint.activate([
            stackView.heightAnchor.constraint(equalToConstant: 20.0)
        ])
        stackView.removeFullyAllArrangedSubviews()
        for i in 0..<numberOfDots {
            let button:RoundButton = RoundButton(frame: CGRect.zero)
            button.translatesAutoresizingMaskIntoConstraints = false
            NSLayoutConstraint.activate([
                button.heightAnchor.constraint(equalToConstant: 10.0),
                button.widthAnchor.constraint(equalToConstant: 10.0),
            ])
            button.tag = i
            button.layer.borderWidth = 1
//            button.backgroundColor = circleBackgroundColor
//            button.layer.borderWidth = borderWidthSize
//            button.layer.borderColor = circleColor.cgColor
            button.addTarget(self, action:#selector(self.buttonClicked), for: .touchUpInside)
            stackView.addArrangedSubview(button)
            dotsView.append(button)
        }
       
    }
    func updateCurrentDots(borderColor : UIColor, backColor : UIColor, index : Int){
        for button in dotsView{
            if button == dotsView[index]{
                button.backgroundColor = backColor
                button.layer.borderColor = borderColor.cgColor
            }else{
                button.backgroundColor = .clear
                button.layer.borderColor = borderColor.cgColor
            }
        }
    }
    @objc func buttonClicked() {
        print("Button Clicked")
    }




class RoundButton: UIButton {

    override init(frame: CGRect) {
         super.init(frame: frame)
     }

     required init?(coder aDecoder: NSCoder) {
         super.init(coder: aDecoder)
     }

     override func prepareForInterfaceBuilder() {
         super.prepareForInterfaceBuilder()
     }
    override func layoutSubviews() {
        self.layer.cornerRadius = self.frame.size.width / 2
    }
}

extension UIStackView {

    func removeFully(view: UIView) {
        removeArrangedSubview(view)
        view.removeFromSuperview()
    }

    func removeFullyAllArrangedSubviews() {
        arrangedSubviews.forEach { (view) in
            removeFully(view: view)
        }
    }

}

You can use either Programmatically or Stoaryboard

To update the current dots calls this function

self.pageControl.updateCurrentDots(borderColor: .white, backColor: .white, index:1)
Cartload answered 4/1, 2021 at 9:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.