279 lines
7.9 KiB
Swift
Executable File
279 lines
7.9 KiB
Swift
Executable File
//
|
|
// 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
|
|
}()
|
|
|
|
}
|
|
}
|