Lama
Lama

Reputation: 255

Changing page control dots with images

I'm trying to change the dots in a page control with some images.

Here is the code I have tried:

import UIKit

class PageViewController: UIPageViewController, UIPageViewControllerDelegate, UIPageViewControllerDataSource {
    // MARK: Data source functions.
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        guard let viewControllerIndex = orderedViewControllers.index(of: viewController) else {
            return nil
        }
        let previousIndex = viewControllerIndex - 1
        guard previousIndex >= 0 else {
            return orderedViewControllers.last
            // Uncommment the line below, remove the line above if you don't want the page control to loop.
            // return nil
        }
        guard orderedViewControllers.count > previousIndex else {
            return nil
        }
        return orderedViewControllers[previousIndex]
    }

    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
        guard let viewControllerIndex = orderedViewControllers.index(of: viewController) else {
            return nil
        }
        let nextIndex = viewControllerIndex + 1
        let orderedViewControllersCount = orderedViewControllers.count
        // the first view controller.
        guard orderedViewControllersCount != nextIndex else {
            return orderedViewControllers.first
            // Uncommment the line below, remove the line above if you don't want the page control to loop.
            // return nil
        }
        guard orderedViewControllersCount > nextIndex else {
            return nil
        }
        return orderedViewControllers[nextIndex]
    }

    lazy var orderedViewControllers: [UIViewController] = {
        return [self.newVc(viewController: "sbYellow"),
                self.newVc(viewController: "sbRed"),
                self.newVc(viewController: "sbBlue")]
    }()

    var pageControl = UIPageControl()

    override func viewDidLoad() {
        super.viewDidLoad()
        self.dataSource = self
        // This sets up the first view that will show up on our page control
        if let firstViewController = orderedViewControllers.first {
            setViewControllers([firstViewController],
                               direction: .forward,
                               animated: true,
                               completion: nil)
        }
        let pageControl = CustomPageControl(frame: CGRect(x: 100, y: 100, width: 104, height: 40))
        pageControl.numberOfPages = 3
        pageControl.currentPage = 0
        self.view.addSubview(pageControl)
        /*self.delegate = self
         configurePageControl()*/
    }

    func configurePageControl() {
        // The total number of pages that are available is based on how many available colors we have.
        pageControl = UIPageControl(frame: CGRect(x: 0,y: UIScreen.main.bounds.maxY - 50,width: UIScreen.main.bounds.width,height: 50))
        self.pageControl.numberOfPages = orderedViewControllers.count
        self.pageControl.currentPage = 0
        self.pageControl.tintColor = UIColor.black
        self.pageControl.pageIndicatorTintColor = UIColor.white
        self.pageControl.currentPageIndicatorTintColor = UIColor.black
        self.view.addSubview(pageControl)
    }

    func newVc(viewController: String) -> UIViewController {
        return UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: viewController)
    }

    func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
        let pageContentViewController = pageViewController.viewControllers![0]
        self.pageControl.currentPage = orderedViewControllers.index(of: pageContentViewController)!
    }
}

class CustomPageControl: UIPageControl {
    var imageToBeReplacedByDot: UIImage {
        return  imageLiteral(resourceName: "av_timer - material") // Image you want to replace with dots
    }
    var circleImage: UIImage {
        return  imageLiteral(resourceName: "cancel - material") //Default Image
    }
    override var numberOfPages: Int {
        didSet {
            updateDots()
        }
    }
    override var currentPage: Int {
        didSet {
            updateDots()
        }
    }

    override func awakeFromNib() {
        super.awakeFromNib()
        self.pageIndicatorTintColor = UIColor.clear
        self.currentPageIndicatorTintColor = UIColor.clear
        self.clipsToBounds = false
    }

    func updateDots() {
        var i = 0
        for view in self.subviews {
            var imageView = self.imageView(forSubview: view)
            if imageView == nil {
                if i == 0 {
                    imageView = UIImageView(image: imageToBeReplacedByDot)
                } else {
                    imageView = UIImageView(image: circleImage)
                }
                imageView!.center = view.center
                view.addSubview(imageView!)
                view.clipsToBounds = false
            }
            if i == self.currentPage {
                imageView!.alpha = 1.0
            } else {
                imageView!.alpha = 0.5
            }
            i += 1
        }
    }

    fileprivate func imageView(forSubview view: UIView) -> UIImageView? {
        var dot: UIImageView?
        if let dotImageView = view as? UIImageView {
            dot = dotImageView
        } else {
            for foundView in view.subviews {
                if let imageView = foundView as? UIImageView {
                    dot = imageView
                    break
                }
            }
        }
        return dot
    }
}

Which is working fine and changing the dots with images. The issue is that the image will not change if i scroll. Also, I want to position the page control on center top of the screen.

How to achieve that?

Screenshot:

enter image description here

Upvotes: 0

Views: 6834

Answers (3)

Ds Pattaiya
Ds Pattaiya

Reputation: 1

enter image description here

import UIKit
    class ViewController: UIViewController {
        
        @IBOutlet weak var pageControl: UIPageControl! // Make IBOutlet of page Control 

        var indexNo = 0 // initialised Starting index number

        var timer = Timer() // here i used timer for change pages

        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            timer = Timer.scheduledTimer(timeInterval: 2, target: self,selector: #selector(setimage), userInfo: nil, repeats: true)
        }
        
        @objc func setimage(){
            pageControl.numberOfPages = 3 // declare number of pages
            pageControl.page = indexNo // assign value for current page
            pageControl.currentPage = indexNo // for current indicator color
            indexNo += 1
            if indexNo == 3 {
                indexNo = 0
                timer.invalidate() // after end of the pages you can modified also
            }
        }
        
    }
    
    //Mark :- make extension of UIPageControl
    
    extension UIPageControl {
        var page: Int {
            get {
                currentPage
            }
            set {
                //currentPage = newValue
                print(newValue)
                setIndicatorImage(UIImage(named: "Rectangle 2"), forPage: newValue)
                for in 0..<numberOfPages where index != newValue {
                    print(index)
                    setIndicatorImage(UIImage(named: "Ellipse 4"), forPage: index)
                }
            }
        }
    }

Upvotes: -1

bola gamal
bola gamal

Reputation: 109

With the help of AI I got that subclass and it works well for me

import UIKit

class CustomPageControl: UIControl {

private var dotImageViews: [UIImageView] = []

private let spacing: CGFloat = 8

var currentPage: Int = 0 {
    didSet {
        updateDots()
    }
}

var numberOfPages: Int = 0 {
    didSet {
        updateDotImageViews()
        updateDots()
    }
}

var dotImage: UIImage? {
    didSet {
        updateDots()
    }
}

var currentDotImage: UIImage? {
    didSet {
        updateDots()
    }
}

private var dotSize: CGSize {
    return dotImage?.size ?? CGSize(width: 10, height: 10)
}

override var intrinsicContentSize: CGSize {
    let width = CGFloat(numberOfPages) * dotSize.width + CGFloat(max(0, numberOfPages - 1)) * spacing
    let height = dotSize.height
    return CGSize(width: width, height: height)
}

override func layoutSubviews() {
    super.layoutSubviews()
    updateDotImageViews()
    updateDots()
    setViewInCenter()
}

private func setViewInCenter() {
    let totalWidth = CGFloat(dotImageViews.count) * dotSize.width + CGFloat(max(0, dotImageViews.count - 1)) * spacing
    let startX = (bounds.width - totalWidth) / 2

    var x = startX
    for dotImageView in dotImageViews {
        dotImageView.frame = CGRect(x: x, y: (bounds.height - dotSize.height) / 2, width: dotSize.width, height: dotSize.height)
        x += dotSize.width + spacing
    }
}

private func updateDotImageViews() {
    // Remove existing dot image views
    dotImageViews.forEach { $0.removeFromSuperview() }
    dotImageViews.removeAll()
    
    // Create and add new dot image views
    for _ in 0..<numberOfPages {
        let dotImageView = UIImageView()
        dotImageView.contentMode = .center
        addSubview(dotImageView)
        dotImageViews.append(dotImageView)
    }
}

private func updateDots() {
    for (index, dotImageView) in dotImageViews.enumerated() {
        dotImageView.image = index == currentPage ? currentDotImage : dotImage
    }
}
}

Create an outlet for the CustomPageControl in your view controller:

@IBOutlet weak var customPageControl: CustomPageControl!

In your view controller's code, set the properties of the customPageControl instance to customize its appearance:

customPageControl.dotImage = UIImage(named: "dot_image")
customPageControl.currentDotImage = UIImage(named: "current_dot_image")
customPageControl.numberOfPages = 5
customPageControl.currentPage = 2

Replace "dot_image" and "current_dot_image" with the actual names of your dot images.

Upvotes: -1

Abhirajsinh Thakore
Abhirajsinh Thakore

Reputation: 1822

You can use this code for Reference:

import UIKit

class LocationPageControl: UIPageControl {

let locationArrow: UIImage = UIImage(named: "locationArrow")!
let pageCircle: UIImage = UIImage(named: "pageCircle")!

override var numberOfPages: Int {
    didSet {
        updateDots()
    }
}

override var currentPage: Int {
    didSet {
        updateDots()
    }
}

override func awakeFromNib() {
    super.awakeFromNib()
    self.pageIndicatorTintColor = UIColor.clear
    self.currentPageIndicatorTintColor = UIColor.clear
    self.clipsToBounds = false
}

func updateDots() {
    var i = 0
    for view in self.subviews {
        var imageView = self.imageView(forSubview: view)
        if imageView == nil {
            if i == 0 {
                imageView = UIImageView(image: locationArrow)
            } else {
                imageView = UIImageView(image: pageCircle)
            }
            imageView!.center = view.center
            view.addSubview(imageView!)
            view.clipsToBounds = false
        }
        if i == self.currentPage {
            imageView!.alpha = 1.0
        } else {
            imageView!.alpha = 0.5
        }
        i += 1
    }
}

fileprivate func imageView(forSubview view: UIView) -> UIImageView? {
    var dot: UIImageView?
    if let dotImageView = view as? UIImageView {
        dot = dotImageView
    } else {
        for foundView in view.subviews {
            if let imageView = foundView as? UIImageView {
                dot = imageView
                break
            }
        }
    }
    return dot
}
}

Note:- Set your image according as per your need

Upvotes: 0

Related Questions