可动态化配置的中央按钮凸起的UITabBarController

最近快要过节了,因此项目中有一个需求,四个按钮的image经过后台返回的图片来进行配置。同时中间的凸起按钮是否展示也经过后台来配置。git

自定义TabBar类

由于项目比较急,之前没有中间凸起按钮的设计,因此首先考虑实现的是新建一个继承UITaBar的类,而后经过valueForKeyPath来替换系统的tabbar。github

自定义WWTabBar面试

class WWTabBar: UITabBar {
        var oldSafeAreaInsets = UIEdgeInsets.zero
        // tabbar高度49
        let TabbarHeight: CGFloat = 49.0
        let centerWidth: CGFloat = 62.0
        let centerHeight: CGFloat = 48.0

        // 中间按钮
        public var centerBtn: UIButton = UIButton(type: .custom)
        // 中间按钮图片url
        var centerImageUrl: String? {
            didSet {
                        centerBtn.kf.setImage(with: URL(string: centerImageUrl ?? ""), for: .normal)
            }
        }

        override init(frame: CGRect) {
            super.init(frame: frame)
            centerBtn.adjustsImageWhenHighlighted = false
            addSubview(centerBtn)
        }

        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }

        override func layoutSubviews() {
            super.layoutSubviews()

            centerBtn.frame = CGRect(x: (UIScreen.main.bounds.size.width - centerWidth) / 2, y: -5, width: centerWidth, height: centerHeight)

            //系统自带的按钮类型是UITabBarButton,找出这些类型的按钮,而后从新排布位置,空出中间的位置
            let btnWidth = self.frame.size.width / 5
            for btn in self.subviews {
                if btn.isKind(of: NSClassFromString("UITabBarButton")!.self) {
                    let label = btn.value(forKeyPath: "_label") as! UILabel

                    switch (label.text ?? "") {
                    case "首页":
                        btn.frame = CGRect(x: 0,
                                y: 0,
                                width: btnWidth,
                                height: TabbarHeight)

                    case "探索":
                        btn.frame = CGRect(x: btnWidth,
                                y: 0,
                                width: btnWidth,
                                height: TabbarHeight)
                    case "发现":
                        btn.frame = CGRect(x: btnWidth * 3,
                                y: 0,
                                width: btnWidth,
                                height: TabbarHeight)


                    case "个人":
                        btn.frame = CGRect(x: btnWidth * 4,
                                y: 0,
                                width: btnWidth,
                                height: TabbarHeight)
                    default:
                        return
                    }


                }

            }
        }

        // 处理超出tabbar部分按钮点击无效的问题
        override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
            if !self.isHidden {
                // 转换坐标
                let tempPoint = centerBtn.convert(point, from: self)
                // 判断点击的点是否在按钮区域内
                if centerBtn.bounds.contains(tempPoint) {
                    // 返回按钮
                    return centerBtn
                }
            }
            return super.hitTest(point, with: event)
        }
    }
复制代码

动态配置中间按钮,自定义UITabBarController。若是配置中间按钮,使用WWTabar替换,若不配置,使用默认TabBar。 为了扩展性,咱们先定义一个WWTabBarControllerbash

class WWTabBarController: UITabBarController {
    var isShow = false
    var tabIcon: UIImage?
    var tabIconUrl: String?
    var toUrl: String?
    var customTabbar: WWTabBar?

    init(isShowPlus: Bool, icon: UIImage?, iconUrl: String?, uri: String?) {
        isShow = isShowPlus
        tabIcon = icon
        tabIconUrl = iconUrl
        toUrl = uri
        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        if isShow {
            customTabbar = WWTabBar(frame: .zero)
            setValue(customTabbar, forKeyPath: "tabBar")
            customTabbar?.centerBtn.addTarget(self, action: #selector(centerBtnAction), for: .touchUpInside)
        }
    }

    // 中间按钮点击
    @objc func centerBtnAction() {
//        LocalRouter.shared.open(url: toUrl ?? "")
    }
}
复制代码

这里有中间按钮的图片、跳转连接等等,经过isShow属性来决定是否用自定义tabbar来替换系统的。中间按钮路径跳转到toUrl,这里须要本身的路由实现。 使用时,新建类来继承这个WWTabBarController微信

class TestTabBarController: WWTabBarController {

    override func viewDidLoad() {
        super.viewDidLoad()
        addChildViewControllers()
    }

    //添加子控制器
    func addChildViewControllers() {
        addChildViewController(ViewController(), title: "首页", imageName: "tab1")
        addChildViewController(ViewController(), title: "探索", imageName: "tab2")
        addChildViewController(ViewController(), title: "发现", imageName: "tab3")
        addChildViewController(ViewController(), title: "个人", imageName: "tab4")
    }

    // 添加子vc
    func addChildViewController(_ childController: UIViewController, title: String, imageName: String) {
        childController.title = title
        if imageName.count > 0{
            childController.tabBarItem.image = UIImage(named: imageName)
            childController.tabBarItem.selectedImage = UIImage(named: imageName)
        }
        let nav = UINavigationController(rootViewController: childController)
        addChild(nav)
    }
}
复制代码

在这里配置四个tabbaritem和对应的页面 使用时,从后台拿到配置,而后进行初始化网络

使用系统tababr

self.window?.rootViewController = TestTabBarController(isShowPlus: false, icon: nil, iconUrl: nil, uri: nil)
复制代码

添加中间凸起按钮

self.window?.rootViewController = TestTabBarController(isShowPlus: true, icon: image, iconUrl: "iconurl", uri: "yoururl")
复制代码

由于可能会碰见网络很差的状况。因此项目一开始使用系统的TabBar,请求配置文件并保存下来。第二次再使用本地的配置文件来初始化。因此我建议不要直接使用URl来加载图片,将图片down下来而后设置到TabBar中。在上面的WWTabBar中我是设置的url,须要修改一下。ide

因为咱们项目中首页对应的TabBarItem Icon是会变化的,再滑动必定距离后,首页Icon会变成刷新图标,因此会再次调用layoutSubviews方法,这个layout过程会被用户看见,因此这个方法不可行。因此尝试自定义View,不继承系统UITabBar。 这里先挖个坑。若是没有这个需求,能够用上述方法。 github.com/FrunkPiano/…ui

最近加了一些iOS开发相关的QQ群和微信群,可是感受都比较水,里面对于技术的讨论比较少,因此本身建了一个iOS开发进阶讨论群,欢迎对技术有热情的同窗扫码加入,加入之后你能够获得:url

  1. 技术方案的讨论,会有在大厂工做的高级开发工程师尽量抽出时间给你们解答问题
  2. 每周按期会写一些文章,而且转发到群里,你们一块儿讨论,也鼓励加入的同窗积极得写技术文章,提高本身的技术
  3. 若是有想进大厂的同窗,里面的高级开发工程师也能够给你们内推,而且针对性得给出一些面试建议 群已经满100人了,想要加群的小伙伴们能够扫码加这个微信,备注:“加群+昵称”,拉你进群,谢谢了

相关文章
相关标签/搜索