diff --git a/Example/ViewController.swift b/Example/ViewController.swift index 772ff50..c2662da 100644 --- a/Example/ViewController.swift +++ b/Example/ViewController.swift @@ -14,21 +14,37 @@ class ViewController: UIViewController { @IBOutlet weak var collectionView: UICollectionView! @IBOutlet weak var pageControl: ISPageControl! var pageControl1: ISPageControl! + var pageControl2: ISPageControl! let images: [UIImage] = [#imageLiteral(resourceName: "bg1"), #imageLiteral(resourceName: "bg2"), #imageLiteral(resourceName: "bg3"), #imageLiteral(resourceName: "bg4"), #imageLiteral(resourceName: "bg5"), #imageLiteral(resourceName: "bg6"), #imageLiteral(resourceName: "bg7"), #imageLiteral(resourceName: "bg8")] override func viewDidLoad() { super.viewDidLoad() pageControl.numberOfPages = images.count - let frame = CGRect(x: 0, y: 500, width: UIScreen.main.bounds.width, height: 100) - pageControl1 = ISPageControl(frame: frame, numberOfPages: images.count) - pageControl1.radius = 8 + let frame1 = CGRect(x: 0, y: 450, width: UIScreen.main.bounds.width, height: 100) + pageControl1 = ISPageControl(frame: frame1, numberOfPages: images.count) + pageControl1.dotRadius = 8 pageControl1.padding = 10 pageControl1.inactiveTintColor = UIColor.white.withAlphaComponent(0.4) pageControl1.currentPageTintColor = UIColor.black pageControl1.borderWidth = 1 pageControl1.borderColor = UIColor.black.withAlphaComponent(0.4) view.addSubview(pageControl1) + + let frame2 = CGRect(x: 0, y: 550, width: UIScreen.main.bounds.width, height: 100) + pageControl2 = ISPageControl(frame: frame2, numberOfPages: images.count) + pageControl2.dotRadius = 3 + pageControl2.dotHeight = 6 + pageControl2.dotWidth = 30 + pageControl2.minOpacityValue = 0.2 + pageControl2.middleOpacityValue = 0.6 + pageControl2.fadeOpacity = true + pageControl2.fadeScale = false + pageControl2.inactiveTintColor = UIColor.white.withAlphaComponent(0.4) + pageControl2.currentPageTintColor = UIColor.black + pageControl2.borderWidth = 1 + pageControl2.borderColor = UIColor.black.withAlphaComponent(0.4) + view.addSubview(pageControl2) } } @@ -58,6 +74,7 @@ extension ViewController: UIScrollViewDelegate { let pageNumber = round(scrollView.contentOffset.x / scrollView.frame.size.width) pageControl.currentPage = Int(pageNumber) pageControl1.currentPage = Int(pageNumber) + pageControl2.currentPage = Int(pageNumber) } } diff --git a/Sources/ISPageControl.swift b/Sources/ISPageControl.swift index 04a8dc2..4439eb5 100644 --- a/Sources/ISPageControl.swift +++ b/Sources/ISPageControl.swift @@ -9,10 +9,22 @@ import UIKit open class ISPageControl: UIControl { + + open var fadeScale: Bool = true { + didSet { + setNeedsLayout() + } + } + + open var fadeOpacity: Bool = false { + didSet { + setNeedsLayout() + } + } + fileprivate let limit = 5 fileprivate var fullScaleIndex = [0, 1, 2] fileprivate var dotLayers: [CALayer] = [] - fileprivate var diameter: CGFloat { return radius * 2 } fileprivate var centerIndex: Int { return fullScaleIndex[1] } open var currentPage = 0 { @@ -36,8 +48,32 @@ open class ISPageControl: UIControl { } } - @IBInspectable open var radius: CGFloat = 5 { + @IBInspectable open var dotRadius: CGFloat = 5 { + didSet { + if dotHeight < 2 * dotRadius { + dotHeight = 2 * dotRadius + } + if dotWidth < 2 * dotRadius { + dotWidth = 2 * dotRadius + } + updateDotLayersLayout() + } + } + + @IBInspectable open var dotWidth: CGFloat = 10 { + didSet { + if dotRadius > dotWidth / 2 { + dotRadius = dotWidth / 2 + } + updateDotLayersLayout() + } + } + + @IBInspectable open var dotHeight: CGFloat = 10 { didSet { + if dotRadius > dotHeight / 2 { + dotRadius = dotHeight / 2 + } updateDotLayersLayout() } } @@ -60,6 +96,18 @@ open class ISPageControl: UIControl { } } + @IBInspectable open var minOpacityValue: CGFloat = 0.4 { + didSet { + setNeedsLayout() + } + } + + @IBInspectable open var middleOpacityValue: CGFloat = 0.7 { + didSet { + setNeedsLayout() + } + } + @IBInspectable open var numberOfPages: Int = 0 { didSet { setupDotLayers() @@ -107,7 +155,7 @@ open class ISPageControl: UIControl { override open func sizeThatFits(_ size: CGSize) -> CGSize { let minValue = min(7, numberOfPages) - return CGSize(width: CGFloat(minValue) * diameter + CGFloat(minValue - 1) * padding, height: diameter) + return CGSize(width: CGFloat(minValue) * dotWidth + CGFloat(minValue - 1) * padding, height: dotHeight) } open override func layoutSubviews() { @@ -143,14 +191,14 @@ private extension ISPageControl { func updateDotLayersLayout() { let floatCount = CGFloat(numberOfPages) - let x = (bounds.size.width - diameter * floatCount - padding * (floatCount - 1)) * 0.5 - let y = (bounds.size.height - diameter) * 0.5 - var frame = CGRect(x: x, y: y, width: diameter, height: diameter) + let x = (bounds.size.width - dotWidth * floatCount - padding * (floatCount - 1)) * 0.5 + let y = (bounds.size.height - dotHeight) * 0.5 + var frame = CGRect(x: x, y: y, width: dotWidth, height: dotHeight) dotLayers.forEach { - $0.cornerRadius = radius + $0.cornerRadius = dotRadius $0.frame = frame - frame.origin.x += diameter + padding + frame.origin.x += dotWidth + padding } } @@ -160,7 +208,7 @@ private extension ISPageControl { dotLayers.enumerated().filter{ $0.offset != centerIndex }.forEach { let index = abs($0.offset - centerIndex) - let interval = $0.offset > centerIndex ? diameter + padding : -(diameter + padding) + let interval = $0.offset > centerIndex ? dotWidth + padding : -(dotWidth + padding) $0.element.position = CGPoint(x: centerLayer.position.x + interval * CGFloat(index), y: $0.element.position.y) } } @@ -171,20 +219,44 @@ private extension ISPageControl { return } - var transform = CGAffineTransform.identity - if !fullScaleIndex.contains($0.offset) { - var scaleValue: CGFloat = 0 - if abs($0.offset - first) == 1 || abs($0.offset - last) == 1 { - scaleValue = min(middleScaleValue, 1) - } else if abs($0.offset - first) == 2 || abs($0.offset - last) == 2 { - scaleValue = min(minScaleValue, 1) - } else { - scaleValue = 0 + if fadeScale { + + var transform = CGAffineTransform.identity + if !fullScaleIndex.contains($0.offset) { + var scaleValue: CGFloat = 0 + if abs($0.offset - first) == 1 || abs($0.offset - last) == 1 { + scaleValue = min(middleScaleValue, 1) + } else if abs($0.offset - first) == 2 || abs($0.offset - last) == 2 { + scaleValue = min(minScaleValue, 1) + } else { + scaleValue = 0 + } + transform = transform.scaledBy(x: scaleValue, y: scaleValue) + } + + $0.element.setAffineTransform(transform) + } + + if fadeOpacity { + + var opacity: CGFloat = 1 + if !fullScaleIndex.contains($0.offset) { + var scaleValue: CGFloat = 0 + if abs($0.offset - first) == 1 || abs($0.offset - last) == 1 { + scaleValue = min(middleOpacityValue, 1) + } else if abs($0.offset - first) == 2 || abs($0.offset - last) == 2 { + scaleValue = min(minOpacityValue, 1) + } else { + scaleValue = 0 + } + opacity = scaleValue } - transform = transform.scaledBy(x: scaleValue, y: scaleValue) + + $0.element.opacity = Float(opacity) + } - $0.element.setAffineTransform(transform) + } }