问题
I want to add border color for dots in UIPageControl. Here is the small picture of it:
I am able to put second dot by configuring it from XCode but I cannot make the first and third circles' inside empty. Is there a simple way to achieve that?
Thanks :)
回答1:
That is not possible with the current properties available for UIPageControl. But you can do by integrating any third party page control which mimic the functionality of iOS UIPageControl.
Other answer has applied a patch. I highly disagreed with that solution.
回答2:
Edited- Swift 3 & 4 extension to achieve the same result-
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
}
}
}
}
to use it write below code in viewDidLoad() or viewDidAppear()
pageControl.customPageControl(dotFillColor: .orange, dotBorderColor: .green, dotBorderWidth: 2)
In Objective-C use below code-
- (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;
}
}
}
Output-
回答3:
Another approach would be to use a pattern image of the correct size (which currently is 7 points in diameter). Here's what the result looks like:
And here's how it's done:
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
Which uses this simple little extension to 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
}
}
The downside of this is that if the dot size changes in an OS update, the image will look weird as it will be tiled or clipped.
回答4:
SWIFT 3 Version from @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
}
}
}
回答5:
Swift 4. You can assign borderColor and then observe currentPage property to change dots' border:
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
}
}
}
}
回答6:
I am using SMPageControl. It's a really awesome Framework written in Objective-C, so it's capable with Swift 2 and Swift 3.
The usage is completely simple:
pod 'SMPageControl'
Then in your 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 I've used:
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
}
}
The result looks like this:
Now we could of course use colored dots as the images, (blank colored as unused and color-filled as used) then we would have the asked result.
回答7:
Just add this two lines and add the desired image !!
pageControl.currentPageIndicatorTintColor = UIColor.init(patternImage: UIImage(named: "slider_selected")!)
pageControl.pageIndicatorTintColor = UIColor.init(patternImage: UIImage(named: "slider")!)
回答8:
Need to add this in 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;
}
}
回答9:
Swift 5 version
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:
Luke Rogers's solution, written in 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;
}
回答11:
Modern Luke Rogers
extension UIImage
{
// https://stackoverflow.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
}
}
来源:https://stackoverflow.com/questions/35842040/add-border-for-dots-in-uipagecontrol