【问题标题】:Customize dot with image of UIPageControl at index 0 of UIPageControl在 UIPageControl 的索引 0 处使用 UIPageControl 的图像自定义点
【发布时间】:2012-08-30 04:58:02
【问题描述】:

我是 ios 编程的新手。我试图在 stackoverflow 上搜索另​​一个示例和更多问题,但这不是我的目标。我想在 UIPageControl 的索引 0 处设置一个点图像,类似于 iPhone 搜索主屏幕。有什么办法吗?请用一些代码或其他有用的链接解释一下。

提前致谢

【问题讨论】:

  • 这个解决方案肯定更严厉,但SMPageControl 让这样的事情变得非常容易:)
  • 这很好用。只需要记住先设置页数,然后再尝试自定义特定的页面图像。并且,它不会像下面的一些代码示例那样,在屏幕上出现已经出现的UIView 动画。

标签: iphone ios


【解决方案1】:

我创建了一个自定义页面控制器,它应该以几乎相同的方式运行,而无需侵入 UIPageControl 的内部或为一个小部件提供整个库。

只需在情节提要中放置一个空的 UIStackView 并将其自定义类设为下面的此类,然后像普通 UIPageControl 一样使用numberOfPagescurrentPage。在 UIStackView 上设置间距以更改视图之间的间距。

斯威夫特 4.2

/**
 If adding via storyboard, you should not need to set a width and height constraint for this view,
 just set a placeholder for each so autolayout doesnt complain and this view will size itself once its populated with pages at runtime
 */
class PageControl: UIStackView {

    @IBInspectable var currentPageImage: UIImage = UIImage(named: "whiteCircleFilled")!
    @IBInspectable var pageImage: UIImage = UIImage(named: "whiteCircleOutlined")!
    /**
     Sets how many page indicators will show
     */
    var numberOfPages = 3 {
        didSet {
            layoutIndicators()
        }
    }
    /**
     Sets which page indicator will be highlighted with the **currentPageImage**
     */
    var currentPage = 0 {
        didSet {
            setCurrentPageIndicator()
        }
    }

    override func awakeFromNib() {
        super.awakeFromNib()

        axis = .horizontal
        distribution = .equalSpacing
        alignment = .center

        layoutIndicators()
    }

    private func layoutIndicators() {

        for i in 0..<numberOfPages {

            let imageView: UIImageView

            if i < arrangedSubviews.count {
                imageView = arrangedSubviews[i] as! UIImageView // reuse subview if possible
            } else {
                imageView = UIImageView()
                addArrangedSubview(imageView)
            }

            if i == currentPage {
                imageView.image = currentPageImage
            } else {
                imageView.image = pageImage
            }
        }

        // remove excess subviews if any
        let subviewCount = arrangedSubviews.count
        if numberOfPages < subviewCount {
            for _ in numberOfPages..<subviewCount {
                arrangedSubviews.last?.removeFromSuperview()
            }
        }
    }

    private func setCurrentPageIndicator() {

        for i in 0..<arrangedSubviews.count {

            let imageView = arrangedSubviews[i] as! UIImageView

            if i == currentPage {
                imageView.image = currentPageImage
            } else {
                imageView.image = pageImage
            }
        }
    }
}

为我的目的工作,但我不做任何保证

【讨论】:

    【解决方案2】:

    试试这个链接:-

    用 GrayPageControl 回答:- Is there a way to change page indicator dots color

    真的很好,很可靠。我也用过这段代码。

    你可能需要做更多的自定义

    -(void) updateDots
    {
        for (int i = 0; i < [self.subviews count]; i++)
        {
            UIImageView* dot = [self.subviews objectAtIndex:i];
    
            if (i == self.currentPage) {
                if(i==0) {
                    dot.image = [UIImage imageNamed:@"activesearch.png"];
                } else {
                    dot.image = activeImage;
                }        
            } else {
                if(i==0) {
                    dot.image = [UIImage imageNamed:@"inactivesearch.png"];
                } else {
                    dot.image = inactiveImage;
                }
            }
        }
    }
    

    【讨论】:

    • 我们在设置 GrayPageControl 的项目时,使用 UIViewController ?
    • GrayPageControl 是 pagecontrol 的子类。在必须使用页面控件的类中,只需创建 GrayPageControl 的对象而不是 UIPageControl。
    • 您可以查看一些自定义页面控件的示例应用。
    • 在 iOS7 上它崩溃了,因为子视图不再是 UIImageViews 了!!!注意这样的实现!!!
    • 嘿,我已经提出了 iOS 7 崩溃的解决方案。请看一下:)
    【解决方案3】:

    我已经找到了解决这个问题的方法。我知道这不是办法,但它会在 iOS 8 上市之前一直有效。

    崩溃原因:

    在 iOS 7 [self.subViews objectAtIndex: i] 返回 UIView 而不是 UIImageView 并且 setImage 不是 UIView 的属性并且应用程序崩溃。我使用以下代码解决了我的问题。

    检查子视图是 UIView(iOS7) 还是 UIImageView(iOS6 或更早版本)。如果它是 UIView,我将在该视图上添加 UIImageView 作为子视图,瞧它的工作,而不是崩溃..!!

    -(void) updateDots
    {
        for (int i = 0; i < [self.subviews count]; i++)
        {
            UIImageView * dot = [self imageViewForSubview:  [self.subviews objectAtIndex: i]];
            if (i == self.currentPage) dot.image = activeImage;
            else dot.image = inactiveImage;
        }
    }
    - (UIImageView *) imageViewForSubview: (UIView *) view
    {
        UIImageView * dot = nil;
        if ([view isKindOfClass: [UIView class]])
        {
            for (UIView* subview in view.subviews)
            {
                if ([subview isKindOfClass:[UIImageView class]])
                {
                    dot = (UIImageView *)subview;
                    break;
                }
            }
            if (dot == nil)
            {
                dot = [[UIImageView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, view.frame.size.width, view.frame.size.height)];
                [view addSubview:dot];
            }
        }
        else
        {
            dot = (UIImageView *) view;
        }
    
        return dot;
    }
    

    另外,要清除已经存在的图像,请将现有指示器的色调设置为透明:

    - (void)awakeFromNib
    {   
        self.pageIndicatorTintColor = [UIColor clearColor];
        self.currentPageIndicatorTintColor = [UIColor clearColor];
    }
    

    希望这将解决您的 iOS 7 问题。

    愉快的编码

    【讨论】:

    • 这适用于 iOS 9 吗? iOS 8 及更高版本的任何替代方式?
    【解决方案4】:

    Swift 3 代码的最佳编译,用位置标记替换UIPageControl 的第一个图标

    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
        }
    }
    

    附加图片:

    【讨论】:

    • 默认页面控制图标和替换后的图片都可见怎么办?
    • 最后,iOS 14 使用新的 UIPageControl API 让生活变得轻松,根据您的页面设置不同的图像 => pageControl.setIndicatorImage(UIImage(named: "location.png"), forPage: 0)
    【解决方案5】:

    只需将 UIPageControl 页面指示器颜色更改为图案 Image self.pageControl.currentPageIndicatorTintColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"circle"]];

    【讨论】:

      【解决方案6】:

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

       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
           }
       }
      

      【讨论】:

      • numberOfPagescurrentPage 调用updateDots() 会好很多观察者:stackoverflow.com/a/41136917/865475
      • 我喜欢这个主意。我会试一试。谢谢
      • 在什么地方需要调用updateDots?我在viewDidLoad 内调用它,但不起作用。
      • 尝试调用 viewDidAppear() 中的 updateDots() 和页面控件的 valueChanged 处理程序。或者,您也可以按照 Dmitry 的建议尝试从 numberOfPages 和 currentPage 观察者中调用它。
      【解决方案7】:

      你只需要这样做:

      ((UIImageView *)[[yourPageControl subviews] objectAtIndex:0]).image=[UIImage imageNamed:@"search.png"];
      

      【讨论】:

      • 修改现有控件的子视图是脆弱的,应该避免。
      • @DavidRönnqvist,我同意这一点,DDPageControl 也许是更好的方法。
      • 感谢 Jonas,但图片非常小。我们如何使这张图片比以前更大?大小等于 iPhone 的默认点。
      • 在 iOS7 上它崩溃了,因为子视图不再是 UIImageViews 了!!!注意这样的实现!!!
      【解决方案8】:

      我认为为此您需要自定义整个UIPageControl。请在下面的链接中找到更多信息

      1. How can i change the color of pagination dots of UIPageControl?

      2. http://iphoneappcode.blogspot.in/2012/03/custom-uipagecontrol.html

      【讨论】:

        【解决方案9】:

        来自 iProgrammer 的回答
        如果您想隐藏原始点

        - (UIImageView *)imageViewForSubview:(UIView *)view {
            UIImageView * dot = nil;
            [view setBackgroundColor:[UIColor clearColor]]; << add this line
        

        【讨论】:

        • 这在 iOS 7 中无效,因为点视图的内部结构发生了变化。它们不再是 UIImageViews,使用 bg 颜色隐藏不再有任何影响。
        【解决方案10】:

        按照之前的答案,我想出了下面的解决方案。 请记住,我必须在控制器中添加调用 updateDots() 的 valueChanged 侦听器来处理在 UIPageControl 上进行的点击

        import UIKit
        
        class PageControl: UIPageControl {
            private struct Constants {
                static let activeColor: UIColor = .white
                static let inactiveColor: UIColor = .black
                static let locationImage: UIImage = UIImage(named: "Location")!
            }
        
            // Update dots when currentPage changes
            override var currentPage: Int {
                didSet {
                    updateDots()
                }
            }
        
            override func awakeFromNib() {
                super.awakeFromNib()
                self.pageIndicatorTintColor = .clear
                self.currentPageIndicatorTintColor = .clear
            }
        
            func updateDots() {
                for (index, view) in self.subviews.enumerated() {
                    // Layers will be redrawn, remove old.
                    view.layer.sublayers?.removeAll()
                    if index == 0 {
                        drawImage(view: view)
                    } else {
                        drawDot(index: index, view: view)
                    }
                }
            }
        
            private func drawDot(index: Int, view: UIView) {
                let dotLayer = CAShapeLayer()
                dotLayer.path = UIBezierPath(ovalIn: view.bounds).cgPath
                dotLayer.fillColor = getColor(index: index)
        
                view.layer.addSublayer(dotLayer)
            }
        
            private func drawImage(view: UIView) {
                let height = view.bounds.height * 2
                let width = view.bounds.width * 2
                let topMargin: CGFloat = -3.5
        
                let maskLayer = CALayer()
                maskLayer.frame = CGRect(x: 0, y: 0, width: width, height: height)
                maskLayer.contents = Constants.locationImage.cgImage
                maskLayer.contentsGravity = .resizeAspect
        
                let imageLayer = CALayer()
                imageLayer.frame = CGRect(x:0, y: topMargin, width: width, height: height)
                imageLayer.mask = maskLayer
                imageLayer.backgroundColor = getColor()
        
                view.backgroundColor = .clear // Otherwise black background
                view.layer.addSublayer(imageLayer)
            }
        
            private func getColor(index: Int? = 0) -> CGColor {
                return currentPage == index ? Constants.activeColor.cgColor : Constants.inactiveColor.cgColor
            }
        }
        

        【讨论】:

          【解决方案11】:

          从 iOS 14 开始,您可以使用以下方法获取和设置指示器图像:

          @available(iOS 14.0, *)
          open func indicatorImage(forPage page: Int) -> UIImage?
          
          
          @available(iOS 14.0, *)
          open func setIndicatorImage(_ image: UIImage?, forPage page: Int)
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2016-04-21
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-04-09
            相关资源
            最近更新 更多