// // TabBar.swift // Tabbar // // Created by lym on 2021/1/1. // import Lottie import UIKit protocol TabBarDelegate: AnyObject { func tabBar(_ tabBar: TabBar, didSelectItemAt index: TabBarItemIndex) func tabBar(_ tabBar: TabBar, canTapEnterItem index: TabBarItemIndex) -> Bool } class TabBar: UITabBar { weak var tabBarDelegate: TabBarDelegate? var tabItems: [TabbarItem]? { didSet { guard let items = tabItems else { return } containerStack.removeSubviews() for (index, item) in items.enumerated() { containerStack.addArrangedSubview(item) item.addTarget(self, action: #selector(clickItem), for: .touchUpInside) item.selectedStatus = index == 0 } } } static let containerHeight: CGFloat = 52 private var containerInsets = UIEdgeInsets(top: 20, left: 24, bottom: 24, right: 24) private var container: UIView = { let view = UIView() view.backgroundColor = .clear // clear return view }() private var containerStack: UIStackView = { let stack = UIStackView() stack.axis = .horizontal stack.distribution = .fillEqually stack.spacing = 0 return stack }() private lazy var bgView: UIView = { let view = UIView() view.backgroundColor = .c.csdn return view }() override init(frame: CGRect) { super.init(frame: frame) if #available(iOS 13.0, *) { let appearance = self.standardAppearance.copy() appearance.backgroundImage = UIColor.clear.toImage() ?? UIImage() appearance.shadowImage = UIColor.clear.toImage() ?? UIImage() appearance.shadowColor = .clear appearance.configureWithTransparentBackground() self.standardAppearance = appearance } else { backgroundImage = UIColor.clear.toImage() ?? UIImage() shadowImage = UIColor.clear.toImage() ?? UIImage() isTranslucent = true barTintColor = .clear } backgroundColor = .c.cbd addSubview(bgView) bgView.addSubview(container) container.layer.cornerRadius = TabBar.containerHeight / 2 container.addSubview(containerStack) bringSubviewToFront(bgView) bgView.snp.makeConstraints { make in make.edges.equalToSuperview().inset(UIEdgeInsets.zero) } let bottom = safeAreaInsets.bottom > 0 ? safeAreaInsets.bottom : containerInsets.bottom container.snp.makeConstraints { make in make.left.equalToSuperview().offset(16)//(containerInsets.left) make.right.equalToSuperview().offset(-16)//(-containerInsets.right) make.height.equalTo(TabBar.containerHeight) make.bottom.equalToSuperview().offset(-bottom) make.bottom.equalToSuperview() } containerStack.snp.makeConstraints { make in make.edges.equalToSuperview().inset(UIEdgeInsets.zero) } } @available(*, unavailable) required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { if clipsToBounds || alpha == 0 || isHidden { return nil } for item in containerStack.arrangedSubviews.reversed() { let subPoint = item.convert(point, from: self) let imgPoint = (item as! TitleItem).imageView.convert(point, from: self) let flag = item.point(inside: subPoint, with: event) let flag2 = item.point(inside: imgPoint, with: event) if flag || flag2 { return item } } return super.hitTest(point, with: event) } // override func layoutSubviews() { // super.layoutSubviews() // } } extension TabBar { public func setSelected(selected _: Bool, index: TabBarItemIndex) { guard let items = tabItems else { return } items.forEach { item in if item.itemIndex == index { item.selectedStatus = true item.starAnimation() } else { item.selectedStatus = false item.stopAnimation() } } } public func setCount(count: Int, index: TabBarItemIndex) { guard let items = tabItems else { return } items.forEach { item in if item.itemIndex == index { item.count = count } } } } extension TabBar { @objc private func clickItem(_ sender: TitleItem) { switch sender.itemIndex { case .friend, .me, .discover, .home, .add: if let can = tabBarDelegate?.tabBar(self, canTapEnterItem: sender.itemIndex), can == true { setSelected(selected: true, index: sender.itemIndex) tabBarDelegate?.tabBar(self, didSelectItemAt: sender.itemIndex) } // case .add: // tabBarDelegate?.tabBar(self, didSelectItemAt: sender.itemIndex) // } } } } // MARK: - TabBar item enum TabBarItemIndex { case home case friend /// 额外的添加按钮 case add case discover case me } enum TitleItemStyle { case small case large } protocol TabbarItem: UIControl { var selectedStatus: Bool { get set } var count: Int { get set } var itemIndex: TabBarItemIndex { get set } func starAnimation() func stopAnimation() } extension TabbarItem { func starAnimation() {} func stopAnimation() {} } class TitleItem: UIControl, TabbarItem { private var titleLabel: UILabel! //private var bage: PaddingLabel! private var badgeView: BadgeView! // private var lotiView: AnimationView! var imageView: UIImageView! var image: UIImage! var selectedImage: UIImage! var style: TitleItemStyle! var font = UIFont.t.tll // UIFont = .popSemiBold(size: 12) var selectedFont: UIFont = .t.tll // .popSemiBold(size: 12) var textColor: UIColor = .c.ctsn var selectedTextColor: UIColor = .white // .hexEF7000 public var title: String { didSet { titleLabel.text = title } } public var count: Int = 0 { didSet { badgeView.isHidden = count <= 0 badgeView.badgeValue = count// > 99 ? "99+" : "\(count)" } } public var selectedStatus: Bool = false { didSet { if selectedStatus { imageView.image = selectedImage } else { imageView.image = image } } } public var itemIndex: TabBarItemIndex init(title: String, image: UIImage, selectedImage: UIImage, count: Int = 0, style: TitleItemStyle = .small, itemIndex: TabBarItemIndex) { self.title = title self.count = count self.image = image self.selectedImage = selectedImage self.style = style self.itemIndex = itemIndex super.init(frame: CGRect.zero) setUpUI() } @available(*, unavailable) required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } func setUpUI() { backgroundColor = .clear imageView = UIImageView() imageView.image = image imageView.contentMode = .scaleAspectFit addSubview(imageView) imageView.snp.makeConstraints { make in make.centerX.equalToSuperview() make.centerY.equalToSuperview() } badgeView = { let v = BadgeView() v.showMax99 = true addSubview(v) v.snp.makeConstraints { make in make.leading.equalTo(imageView.snp.trailing).offset(-8) make.top.equalTo(imageView).offset(-4) } return v }() } }