Using @Luke Rogers answer. I came up with solution for latest iOS versions.
-> Extend UIImage and add these functions:
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
}
class func ellipse(size: CGSize, color: UIColor, lineWidth: CGFloat = 1.0) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
guard let context = UIGraphicsGetCurrentContext() else {
return nil
}
context.setFillColor(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.fillPath()
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}}
Then Extend UIPageControl and add these functions:
extension UIPageControl {
@available(iOS 16.0, *)
func outlinedPageIndicaor(color: UIColor, outlinedColor: UIColor? = nil, count: Int) {
self.pageIndicatorTintColor =
outlinedColor != nil ? outlinedColor : color
self.currentPageIndicatorTintColor = color
let image = UIImage.outlinedEllipse(size: CGSize(width: 8.0, height: 8.0), color: .red)
let ellipse = UIImage.ellipse(size: CGSize(width: 9.0, height: 9.0), color: .red)
self.preferredIndicatorImage = image
for i in 0..<count {
self.setCurrentPageIndicatorImage(ellipse, forPage: i)
}
}
func outlinedPageIndicaor(color: UIColor, outlinedColor: UIColor? = nil, count: Int, index: Int) {
self.pageIndicatorTintColor =
outlinedColor != nil ? outlinedColor : color
self.currentPageIndicatorTintColor = color
let image = UIImage.outlinedEllipse(size: CGSize(width: 8.0, height: 8.0), color: .red)
let ellipse = UIImage.ellipse(size: CGSize(width: 9.0, height: 9.0), color: .red)
self.preferredIndicatorImage = image
for i in 0..<count {
if i != index {
self.setIndicatorImage(image, forPage: i)
} else {
self.setIndicatorImage(ellipse, forPage: index)
}
}
}}
You can use this if you are using iOS 16 or above in viewDidLoad
pageControl.outlinedPageIndicaor(color: .systemMint, count: count)
// pass same count as number of pages of pageControl
if iOS version is below 16, then use second method:
in viewDidLoad:
pageControl.outlinedPageIndicaor(color: .systemMint, count: count, index: 0)
//initial index is passed as 0 for first page
and when current page changes:
pageControl.outlinedPageIndicaor(color: .systemMint, count: count, index: index)
//pass current page in index