【问题标题】:Custom TabBarController with active circle具有活动圆圈的自定义 TabBarController
【发布时间】:2019-01-14 09:49:30
【问题描述】:

在阅读了几篇关于自定义 UITabBarControllers 的文章后,我什至比开始研究之前更加困惑。

我的目标是创建一个具有 3 个重要属性的自定义 TabBar:

  • 没有文字,只有图标
  • 活动图标由一个在其后面填充颜色的圆圈标记,因此需要不同的图标颜色

这是我想要达到的目标:

按照另一个 StackOverflow 答案 (Remove tab bar item text, show only image),我已经能够删除文本并将图标居中,尽管该解决方案对我来说似乎是一个 hack。

如何在项目后面创建一个圆圈并更改活动项目的颜色?

另外,有人介意解释一下 XCode 检查器部分“Tab Bar Item”和“Bar Item”之间的区别,它们直接出现在彼此下方吗?

【问题讨论】:

  • 选择项目时添加蓝色圆圈背景图片

标签: swift uitabbarcontroller


【解决方案1】:

第一步很简单:将UITabbarItem的title属性留空应该隐藏标签。

您的第二步实际上可以分为两个步骤:更改图标的颜色并在其后面添加一个圆圈。

这里的第一步很简单:您可以为当前选定的 ViewController 设置不同的图标(我使用 Storyboard,这个过程非常简单)。您要做的是添加一个白色版本的图标,以便在选择该菜单选项时显示。

最后一步是显示圆圈。为此,我们需要以下信息:

  • 当前选择了哪个项目?
  • 图标在屏幕上的位置是什么?

这两个中的第一个很容易找到,但第二个会带来问题:UITabBar 中的图标在屏幕上的间距不均等,因此我们不能仅将标签栏的宽度除以其中的项目数量,然后取其中的一半找到图标的中心。相反,我们将继承 UITabBarController。

注意:UITabBarController 的 tabBar 属性确实有一个 .selectionIndicatorImage 属性。您可以为此分配一个图像,它将显示在您的图标后面。但是,您无法轻松控制此图像的位置,这就是为什么我们仍然求助于 UITabBarController 的子类。

 

class CircledTabBarController: UITabBarController {

    var circle: UIView?

    override func viewDidLoad() {
        super.viewDidLoad()
        let numberOfItems = CGFloat(tabBar.items!.count)
        let tabBarItemSize = CGSize(width: (tabBar.frame.width / numberOfItems) - 20, height: tabBar.frame.height)
        circle = UIView(frame: CGRect(x: 0, y: 0, width: tabBarItemSize.height, height: tabBarItemSize.height))
        circle?.backgroundColor = .darkGray
        circle?.layer.cornerRadius = circle!.frame.width/2
        circle?.alpha = 0
        tabBar.addSubview(circle!)
        tabBar.sendSubview(toBack: circle!)
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        let index = -(tabBar.items?.index(of: tabBar.selectedItem!)?.distance(to: 0))!
        let frame = frameForTabAtIndex(index: index)
        circle?.center.x = frame.origin.x + frame.width/2
        circle?.alpha = 1
    }

    override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
        let index = -(tabBar.items?.index(of: item)?.distance(to: 0))!
        let frame = frameForTabAtIndex(index: index)
        self.circle?.center.x = frame.origin.x + frame.width/2
    }

    func frameForTabAtIndex(index: Int) -> CGRect {
        var frames = tabBar.subviews.compactMap { (view:UIView) -> CGRect? in
            if let view = view as? UIControl {
                for item in view.subviews {
                    if let image = item as? UIImageView {
                        return image.superview!.convert(image.frame, to: tabBar)
                    }
                }
                return view.frame
            }
            return nil
        }
        frames.sort { $0.origin.x < $1.origin.x }
        if frames.count > index {
            return frames[index]
        }
        return frames.last ?? CGRect.zero
    }

}

现在使用 UITabBarController 的这个子类而不是基类。

那么,为什么要采用这种方法而不是简单地将图标更改为带圆圈的图标呢?因为你可以用它做很多不同的事情。 I wrote an article about animating the UITabBarController in a similar manner,如果你愿意,你也可以很容易地使用上面的实现来为你的动画添加动画。

【讨论】:

  • 很好的答案,我喜欢您采用的方法。不过有一个问题:我目前正在使用 TabBar 的tintColor,这适用于所有项目。当我有圆圈时,我需要更改所选项目的色调,但tintColorUITabBar 属性,而不是UITabBarItem 属性。我该怎么做?我真的必须使用不同的图标吗?
  • 据我所知,您添加到标签栏的图像在取消选择时显示为灰色,并且仅在选择该项目时显示在提供的tintColor 中。因此,在您的情况下,您将 tintColor 属性设置为 .white
  • 有道理,我把东西弄混了。感谢您的帮助!
【解决方案2】:

最简单且实际上最干净的方法是设计您的图标并将它们作为图像导入 .xcassets 文件夹。然后你可以为每个 viewController 的不同状态设置不同的图标:

ViewController.tabBarItem = UITabBarItem(title: "", image: yourImage.withRenderingMode(.alwaysOriginal), selectedImage: yourImage)

您选择的图像将是带有圆圈的图像,而图像将是没有圆圈的图像。它比在 xcode 中处理图像要容易得多,而且成本也更低,因为编译器只需渲染图像而不必处理它们。

关于另一个问题 UIBarItem 是

可以添加到出现在屏幕底部的条中的项目的抽象超类。

UITabBarItem 是 UIBarItem 的子类,提供额外的功能。

【讨论】:

  • 谢谢!另一个答案在动画方面允许更大的灵活性,但我非常感谢 TabBarItem vs BarItem 的解释:)
猜你喜欢
  • 1970-01-01
  • 2020-11-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-19
  • 2014-06-06
  • 2017-11-15
  • 2013-10-02
相关资源
最近更新 更多