【问题标题】:Is it possible to customize UITabBarItem Badge?是否可以自定义 UITabBarItem 徽章?
【发布时间】:2013-04-29 08:14:16
【问题描述】:

下面的问题和我的差不多。

How to use a custom UIImage as an UITabBarItem Badge?

是否可以使用背景图像而不是自己绘制? 我认为这很好,因为我的应用程序只会使用 1 位数的 badgeValue。

如果真的不可能,我想知道我们是否可以更改徽章颜色。 以下问题中的答案并没有真正的帮助。

Is it possible to change UITabBarItem badge color

【问题讨论】:

    标签: iphone ios uitabbar uitabbaritem


    【解决方案1】:

    这是您最好的选择。在文件范围内添加此扩展名,您可以根据需要自定义徽章。只需在您的任何根视图控制器中调用self.tabBarController!.setBadges([1,0,2])

    需要明确的是,标签栏包含三个项目,徽章值从左到右。

    如果您想添加图片,只需更改 addBadge 方法

    extension UITabBarController {
        
        func setBadges(badgeValues: [Int]) {
    
            var labelExistsForIndex = [Bool]()
    
            for _ in badgeValues {
                labelExistsForIndex.append(false)
            }
    
            for view in self.tabBar.subviews where view is PGTabBadge {
                let badgeView = view as! PGTabBadge
                let index = badgeView.tag
                
                if badgeValues[index] == 0 {
                    badgeView.removeFromSuperview()
                }
                
                labelExistsForIndex[index] = true
                badgeView.text = String(badgeValues[index])
            }
    
            for i in 0...(labelExistsForIndex.count - 1) where !labelExistsForIndex[i] && (badgeValues[i] > 0) {
                addBadge(index: i, value: badgeValues[i], color: .red, font: UIFont(name: "Helvetica-Light", size: 11)!)
            }
    
        }
    
        func addBadge(index: Int, value: Int, color: UIColor, font: UIFont) {
    
            let itemPosition = CGFloat(index + 1)
            let itemWidth: CGFloat = tabBar.frame.width / CGFloat(tabBar.items!.count)
    
            let bgColor = color
    
            let xOffset: CGFloat = 5
            let yOffset: CGFloat = -12
    
            let badgeView = PGTabBadge()
            badgeView.frame.size =  CGSize(width: 12, height: 12)
            badgeView.center = CGPoint(x: (itemWidth * itemPosition) - (itemWidth / 2) + xOffset, y: 20 + yOffset)
            badgeView.layer.cornerRadius = badgeView.bounds.width/2
            badgeView.clipsToBounds = true
            badgeView.textColor = UIColor.white
            badgeView.textAlignment = .center
            badgeView.font = font
            badgeView.text = String(value)
            badgeView.backgroundColor = bgColor
            badgeView.tag = index
            tabBar.addSubview(badgeView)
    
        }
    }
        
    class PGTabBadge: UILabel { }
    

    【讨论】:

    • 这个 App Store 安全吗?
    • 当然,标签栏只是一个视图,所以添加子视图是完全合法的。
    • 你是个传奇。
    【解决方案2】:

    这是基于TimWhiting's answer的另一种解决方案:

    extension UITabBar {
            func setBadge(value: String?, at index: Int, withConfiguration configuration: TabBarBadgeConfiguration = TabBarBadgeConfiguration()) {
                let existingBadge = subviews.first { ($0 as? TabBarBadge)?.hasIdentifier(for: index) == true }
                existingBadge?.removeFromSuperview()
    
                guard let tabBarItems = items,
                    let value = value else { return }
    
                let itemPosition = CGFloat(index + 1)
                let itemWidth = frame.width / CGFloat(tabBarItems.count)
                let itemHeight = frame.height
    
                let badge = TabBarBadge(for: index)
                badge.frame.size = configuration.size
                badge.center = CGPoint(x: (itemWidth * itemPosition) - (0.5 * itemWidth) + configuration.centerOffset.x,
                                       y: (0.5 * itemHeight) + configuration.centerOffset.y)
                badge.layer.cornerRadius = 0.5 * configuration.size.height
                badge.clipsToBounds = true
                badge.textAlignment = .center
                badge.backgroundColor = configuration.backgroundColor
                badge.font = configuration.font
                badge.textColor = configuration.textColor
                badge.text = value
    
                addSubview(badge)
            }
        }
    
        class TabBarBadge: UILabel {
            var identifier: String = String(describing: TabBarBadge.self)
    
            private func identifier(for index: Int) -> String {
                return "\(String(describing: TabBarBadge.self))-\(index)"
            }
    
            convenience init(for index: Int) {
                self.init()
                identifier = identifier(for: index)
            }
    
            func hasIdentifier(for index: Int) -> Bool {
                let has = identifier == identifier(for: index)
                return has
            }
        }
    
        class TabBarBadgeConfiguration {
            var backgroundColor: UIColor = .red
            var centerOffset: CGPoint = .init(x: 12, y: -9)
            var size: CGSize = .init(width: 17, height: 17)
            var textColor: UIColor = .white
            var font: UIFont! = .systemFont(ofSize: 11) {
                didSet { font = font ?? .systemFont(ofSize: 11) }
            }
    
            static func construct(_ block: (TabBarBadgeConfiguration) -> Void) -> TabBarBadgeConfiguration {
                let new = TabBarBadgeConfiguration()
                block(new)
                return new
            }
        }
    

    【讨论】:

    • 谢谢!一旦点击带有徽章的标签栏项目,这并不会删除徽章。任何帮助,将不胜感激。 :)
    • @JesseS。您可以通过将徽章的值设置为 nil 在点击时手动删除它。
    【解决方案3】:

    您可以使用更强大的解决方案@UITabbarItem-CustomBadge

    演示

    简单的两行代码就能帮你搞定

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
      //supplying the animation parameter
      [UITabBarItem setDefaultAnimationProvider:[[DefaultTabbarBadgeAnimation alloc] init]];
      [UITabBarItem setDefaultConfigurationProvider:[[DefaultSystemLikeBadgeConfiguration alloc] init]];
    
      //rest of your code goes following...
    
      return YES;
    }
    

    【讨论】:

    • 如果有人要留下-1,请在评论中留下理由
    • 顺便说一句,它是我自己的 github 存储库,我应该添加完整的 6 个代码文件吗?你同意吗? @Zoleas
    【解决方案4】:

    嗯...更改内置徽章的背景对我来说似乎是不可能的。但可能的情况如下:

    子类化 TabBarController,构建一个布局在 NIB 中的自定义视图,将其添加到选项卡栏中您想要的位置的视图层次结构中。

    在自定义视图中,您可以将图像设置为背景,并在该背景之上设置一个标签,这将显示您可以通过代码更改的数值。

    然后,您需要确定自定义视图的水平和垂直位置,您希望将视图放置在标签栏内。

    希望这会有所帮助。 塞巴斯蒂安

    【讨论】:

    • 感谢您的这个想法。我会试试这个。不过,我有一个后续问题。如果这个应用要提交到 AppStore,这个徽章定制可以吗?
    • 不客气……如果您满意,请接受您的回答。好吧....这没问题,因为如果您不喜欢它,则无需使用Apple提供的徽章。如果您尝试修改苹果提供的私有课程,您只会遇到麻烦。
    【解决方案5】:

    TimWhiting's answer 更新到 Swift 4,移除了一些强制展开。

    extension UITabBarController {
      func setBadges(badgeValues: [Int]) {
        var labelExistsForIndex = [Bool]()
    
        for _ in badgeValues {
          labelExistsForIndex.append(false)
        }
    
        for view in tabBar.subviews {
          if let badgeView = view as? PGTabBadge {
            let index = badgeView.tag
    
            if badgeValues[index] == 0 {
              badgeView.removeFromSuperview()
            }
    
            labelExistsForIndex[index] = true
            badgeView.text = String(badgeValues[index])
          }
        }
    
        for i in 0 ... labelExistsForIndex.count - 1 where !labelExistsForIndex[i] && badgeValues[i] > 0 {
          addBadge(
            index: i,
            value: badgeValues[i],
            color: UIColor(red: 4 / 255, green: 110 / 255, blue: 188 / 255, alpha: 1),
            font: UIFont(name: "Helvetica-Light", size: 11)!
          )
        }
      }
    
      func addBadge(index: Int, value: Int, color: UIColor, font: UIFont) {
        guard let tabBarItems = tabBar.items else { return }
        let itemPosition = CGFloat(index + 1)
        let itemWidth: CGFloat = tabBar.frame.width / CGFloat(tabBarItems.count)
    
        let bgColor = color
    
        let xOffset: CGFloat = 12
        let yOffset: CGFloat = -9
    
        let badgeView = PGTabBadge()
        badgeView.frame.size = CGSize(width: 17, height: 17)
        badgeView.center = CGPoint(x: (itemWidth * itemPosition) - (itemWidth / 2) + xOffset, y: 20 + yOffset)
        badgeView.layer.cornerRadius = badgeView.bounds.width / 2
        badgeView.clipsToBounds = true
        badgeView.textColor = UIColor.white
        badgeView.textAlignment = .center
        badgeView.font = font
        badgeView.text = String(value)
        badgeView.backgroundColor = bgColor
        badgeView.tag = index
        tabBar.addSubview(badgeView)
      }
    }
    
    class PGTabBadge: UILabel {}
    

    示例图片

    【讨论】:

      【解决方案6】:

      对于那些难以将badgeView添加到标签栏项目并为iPad计算其位置的人 - 为了在TimWhiting答案中获取xCenterValue,您可以使用这个(注意:所有这个方法我在UITabBarController的扩展中写了):

        private func configureXCenterValue(index: Int) -> CGFloat {
          let tabbarButtonItems = orderedTabBarItemViews()
          let buttonWithBadge = tabbarButtonItems[index]
          let offsetToButton = buttonWithBadge.frame.minX // important
          let imageOffset = buttonWithBadge.subviews[0].frame.maxX // important
          return offsetToButton + imageOffset
        }
      

      gettung orderedTabbarItemViews 的助手:

        private func orderedTabBarItemViews() -> [UIView] {
          let interactionViews = tabBar.subviews.filter { $0.isUserInteractionEnabled }
          return interactionViews.sorted(by: { $0.frame.minX < $1.frame.minX })
        }
      

      你可以在这个方法中使用它:

        private func getBadgeViewCenterPoint(index: Int) -> CGPoint {
          let yOffset: CGFloat = Device.current.isPad ? -5 : -10 // I am using DeviceKit
          let xCenterValue = configureXCenterValue(index: index)
          let yCenterValue = 20 + yOffset
          let centerPosition = CGPoint(x: xCenterValue, y: yCenterValue)
          return centerPosition
        }
      

      主要思想不是通过除以标签栏项目的数量来计算标签栏中视图的 centerX 位置。 我们只是使用这些项目的偏移量(不是手动计算)。

      【讨论】:

        猜你喜欢
        • 2012-10-31
        • 2021-02-13
        • 1970-01-01
        • 2013-03-10
        • 1970-01-01
        • 1970-01-01
        • 2014-02-23
        • 2017-08-09
        • 2015-06-25
        相关资源
        最近更新 更多