带有点图像的自定义 UIPageControl

Posted

技术标签:

【中文标题】带有点图像的自定义 UIPageControl【英文标题】:Custom UIPageControl with dot images 【发布时间】:2016-08-10 09:20:07 【问题描述】:

当我需要自定义 UIPageControl 时,我使用了 this 和 this 解决方案。

为我们拥有的新版本的 swift 稍微修改一下:

class myPageControl: UIPageControl 
    var activeImage: UIImage!
    var inactiveImage: UIImage!

    required init?(coder aDecoder: NSCoder) 
        super.init(coder: aDecoder)
        activeImage = UIImage(named: "active.png")!
        inactiveImage = UIImage(named: "inactive.png")!
    

    func updateDots()
    
        for i in 0 ..< self.subviews.count
        
            let dot : UIImageView = imageViewForSubview(self.subviews[i])
            if (i == self.currentPage) 
                dot.image = activeImage
            
            else 
                dot.image = inactiveImage
            
        
    

    func imageViewForSubview(view: UIView) -> UIImageView 
        var dot: UIImageView? = nil
        if (view.isKindOfClass(UIView)) 
            for subview: UIView in view.subviews 
                if (subview is UIImageView) 
                    dot = (subview as! UIImageView)
                
            
            if dot == nil 
                dot = UIImageView(frame: CGRectMake(0.0, 0.0, view.frame.size.width, view.frame.size.height))
                view.addSubview(dot!)
            
        
        else 
            dot = (view as! UIImageView)
        
        return dot!
    

    func setPage(page: Int) 
        super.currentPage = page
        self.updateDots()
    

我的问题是当你第一次启动应用程序时我无法更改图片。 只有当页面改变时才会改变。

viewDidLoad()中,我添加了setPage(0)updateDots(),但是没有结果。我可能做错了什么?

【问题讨论】:

【参考方案1】:

Swift 3.0 ...您知道您是否可以接受声明的风险:“修改现有控件的子视图很脆弱”。

您必须在 viewDidAppear() 和页面控件的 valueChanged 处理程序中调用“updateDots()”。

 import UIKit

 class CustomImagePageControl: UIPageControl 

   let activeImage:UIImage = UIImage(named: "SelectedPage")!
   let inactiveImage:UIImage = UIImage(named: "UnselectedPage")!

   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 
             if let imageView = self.imageForSubview(view) 
                 if i == self.currentPage 
                     imageView.image = self.activeImage
                  else 
                     imageView.image = self.inactiveImage
                 
                 i = i + 1
              else 
                 var dotImage = self.inactiveImage
                 if i == self.currentPage 
                     dotImage = self.activeImage
                 
                 view.clipsToBounds = false
                 view.addSubview(UIImageView(image:dotImage))
                 i = i + 1
             
         
     

     fileprivate func imageForSubview(_ 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
     
 

【讨论】:

这是调用“updateDots()”的更好主意。还没有尝试过,但 Dmitry 建议覆盖 numberOfPages 和 currentPage 变量 --> ***.com/questions/12190147/… 刚刚签入 ios 14,self.subviews 只获得一个子视图。有什么想法吗? iOS 14 有 prefferedIndicatorImage,使用它并设置 tintColor 此方案适用于活动图像和非活动图像不同的情况。否则,您可以使用“prefferedIndicatorImage”和色调颜色。 @Laurynas Letkauskas【参考方案2】:

我稍微改进了@CodenameDuchess 的回答。您还可以自定义 xibs/storyboards 上的图像。

class CustomPageControl: UIPageControl 

@IBInspectable var currentPageImage: UIImage?

@IBInspectable var otherPagesImage: UIImage?

override var numberOfPages: Int 
    didSet 
        updateDots()
    


override var currentPage: Int 
    didSet 
        updateDots()
    


override func awakeFromNib() 
    super.awakeFromNib()
    pageIndicatorTintColor = .clear
    currentPageIndicatorTintColor = .clear
    clipsToBounds = false


private func updateDots() 

    for (index, subview) in subviews.enumerated() 
        let imageView: UIImageView
        if let existingImageview = getImageView(forSubview: subview) 
            imageView = existingImageview
         else 
            imageView = UIImageView(image: otherPagesImage)

            imageView.center = subview.center
            subview.addSubview(imageView)
            subview.clipsToBounds = false
        
        imageView.image = currentPage == index ? currentPageImage : otherPagesImage
    


private func getImageView(forSubview view: UIView) -> UIImageView? 
    if let imageView = view as? UIImageView 
        return imageView
     else 
        let view = view.subviews.first  (view) -> Bool in
            return view is UIImageView
         as? UIImageView

        return view
    


【讨论】:

【参考方案3】:

你可以使用UIStackView来达到你想要的效果。

将您的activeImageView 和其他inactiveImageViews 放入aStackView。不仅仅是在scrollViewDidScroll(_:) 中更改activeImageView 的索引。

func scrollViewDidScroll(_ scrollView: UIScrollView) 
  let index = Int(scrollView.contentOffset.x / scrollView.frame.width)
  aStackView.insertArrangedSubview(activeImageView, at: index)
  

ps。 UIStackView 的insertArrangedSubview(_:at:) 只是更新已排列子视图的堆栈索引,如果它已经在排列子视图列表中。

【讨论】:

【参考方案4】:

Apple 为 UIPageControll 引入了一些新的 API。从 iOS 14 开始,可以选择提供自定义图像。

这是支持 iOS 14 的更新代码

class CustomPageControl: UIPageControl 

@IBInspectable var currentPageImage: UIImage?

@IBInspectable var otherPagesImage: UIImage?

override var numberOfPages: Int 
    didSet 
        updateDots()
    


override var currentPage: Int 
    didSet 
        updateDots()
    


override func awakeFromNib() 
    super.awakeFromNib()
    if #available(iOS 14.0, *) 
        defaultConfigurationForiOS14AndAbove()
     else 
        pageIndicatorTintColor = .clear
        currentPageIndicatorTintColor = .clear
        clipsToBounds = false
    


private func defaultConfigurationForiOS14AndAbove() 
    if #available(iOS 14.0, *) 
        for index in 0..<numberOfPages 
            let image = index == currentPage ? currentPageImage : otherPagesImage
            setIndicatorImage(image, forPage: index)
        

        // give the same color as "otherPagesImage" color.
        pageIndicatorTintColor = .gray
        
        // give the same color as "currentPageImage" color.
        currentPageIndicatorTintColor = .red 
        /*
         Note: If Tint color set to default, Indicator image is not showing. So, give the same tint color based on your Custome Image.
        */
    


private func updateDots() 
    if #available(iOS 14.0, *) 
        defaultConfigurationForiOS14AndAbove()
     else 
        for (index, subview) in subviews.enumerated() 
            let imageView: UIImageView
            if let existingImageview = getImageView(forSubview: subview) 
                imageView = existingImageview
             else 
                imageView = UIImageView(image: otherPagesImage)
                
                imageView.center = subview.center
                subview.addSubview(imageView)
                subview.clipsToBounds = false
            
            imageView.image = currentPage == index ? currentPageImage : otherPagesImage
        
    


private func getImageView(forSubview view: UIView) -> UIImageView? 
    if let imageView = view as? UIImageView 
        return imageView
     else 
        let view = view.subviews.first  (view) -> Bool in
            return view is UIImageView
         as? UIImageView

        return view
    


【讨论】:

在 iOS 14 中你应该使用 prefferedIndicatorImage 代替 @Laurynas Letkauskas 当活动图像和非活动图像不同时,此解决方案将适用。否则,您可以使用“prefferedIndicatorImage”和 tint color。

以上是关于带有点图像的自定义 UIPageControl的主要内容,如果未能解决你的问题,请参考以下文章

带有图像的自定义 UIButton

带有用于突出显示的图像的自定义 UITableViewCell

带有在代码中绘制的自定义图像的 UITableViewCell

带有图像的自定义 UIPickerView 皮肤

带有圆形图像视图的自定义圆形 UIButton

带有背景图像的自定义JTextArea