在 UIPageControl 中为点添加边框
Posted
技术标签:
【中文标题】在 UIPageControl 中为点添加边框【英文标题】:Add border for dots in UIPageControl 【发布时间】:2016-03-07 11:02:23 【问题描述】:我想为 UIPageControl 中的点添加边框颜色。这是它的小图:
我可以通过从 XCode 配置第二个点来放置第二个点,但我不能让第一个和第三个圆圈内部为空。有没有简单的方法来实现?
谢谢:)
【问题讨论】:
【参考方案1】:已编辑- Swift 3 & 4 扩展 以实现相同的结果-
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
要使用它,请在 viewDidLoad() 或 viewDidAppear() 中编写以下代码
pageControl.customPageControl(dotFillColor: .orange, dotBorderColor: .green, dotBorderWidth: 2)
在Objective-C中使用下面的代码-
- (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;
输出-
【讨论】:
还有其他方法可以实现吗? @EmrahAkgül 如果您在情节提要中设置页面控件,请尝试在viewDidAppear
之后调用for
循环。它对我有用。当我在viewDidLoad
中调用循环时它不起作用。谢谢@RiosK
borderColor
和 borderWidth
设置就足够了。其余的都不需要。可以使用pageIndicatorTintColor
和currentPageIndicatorTintColor
设置状态的backgroundColor
。赞成这个,因为它有帮助。确保在视图出现后调用,就像上面提到的@TheRohanSanap。
@iPeter 它在我的案例中显示。参考附件。
如果视图层次结构因操作系统更新而改变,迭代子视图可能随时中断。【参考方案2】:
另一种方法是使用正确尺寸的图案图像(目前直径为 7 个点)。结果如下所示:
这是如何完成的:
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
它使用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
这样做的缺点是,如果在操作系统更新中点大小发生变化,图像会看起来很奇怪,因为它会被平铺或剪裁。
【讨论】:
这在 iOS 14.7.1 版本上无法正常工作【参考方案3】:SWIFT 3 版本来自@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
【讨论】:
我必须在 viewDidAppear 和 didFinishAnimating 中加入 call nice 函数才能让它工作。【参考方案4】:斯威夫特 4。您可以分配borderColor,然后观察currentPage 属性来改变点的边框:
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
【讨论】:
【参考方案5】:对于UIPageControl
可用的当前属性,这是不可能的。但是您可以通过集成任何模仿 iOS UIPageControl
功能的 third party 页面控件来实现。
其他答案已应用补丁。我非常不同意这个解决方案。
【讨论】:
“其他答案已应用补丁。”还有什么解决办法【参考方案6】:我正在使用SMPageControl。这是一个用 Objective-C 编写的非常棒的框架,因此它支持 Swift 2 和 Swift 3。
用法完全简单:
pod 'SMPageControl'
然后在你的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 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
结果如下:
现在我们当然可以使用彩色点作为图像,(空白为未使用,彩色填充为已使用)然后我们将得到要求的结果。
【讨论】:
【参考方案7】:只需添加这两行并添加所需的图像!
pageControl.currentPageIndicatorTintColor = UIColor.init(patternImage: UIImage(named: "slider_selected")!)
pageControl.pageIndicatorTintColor = UIColor.init(patternImage: UIImage(named: "slider")!)
【讨论】:
【参考方案8】:请试试这个 UIPageControl 的自定义子类。 iOS 14 允许使用 SFSymbol 设置指示器图像。
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
【讨论】:
最后,这适用于我的 3 台设备:iOS 14.7.1、12.4.1 和 12.3.1【参考方案9】:Swift 5 版本
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】:需要在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;
【讨论】:
【参考方案11】:Luke Rogers的解决方案,用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;
【讨论】:
【参考方案12】:现代 Luke Rogers(elk_cloner 说它对于 ios14 来说不够现代)
extension UIImage
// https://***.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
【讨论】:
以上是关于在 UIPageControl 中为点添加边框的主要内容,如果未能解决你的问题,请参考以下文章
如何在全屏 ChildViewController 上显示 UIPageControl?