在我的 Swift 应用程序中,我有一个处理
UITabBar
的类。
class CustomTabBar: UITabBar {
override func awakeFromNib() {
super.awakeFromNib()
}
}
当用户点击项目时,如何为项目设置动画? 我的意思是
CGAffine(scaleX: 1.1, y: 1.1)
那么我如何才能为标签栏的项目设置动画呢?
UITabBarController
,如下所示:
import UIKit
enum TabbarItemTag: Int {
case firstViewController = 101
case secondViewConroller = 102
}
class CustomTabBarController: UITabBarController {
var firstTabbarItemImageView: UIImageView!
var secondTabbarItemImageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
let firstItemView = tabBar.subviews.first!
firstTabbarItemImageView = firstItemView.subviews.first as? UIImageView
firstTabbarItemImageView.contentMode = .center
let secondItemView = self.tabBar.subviews[1]
self.secondTabbarItemImageView = secondItemView.subviews.first as? UIImageView
self.secondTabbarItemImageView.contentMode = .center
}
private func animate(_ imageView: UIImageView) {
UIView.animate(withDuration: 0.1, animations: {
imageView.transform = CGAffineTransform(scaleX: 1.25, y: 1.25)
}) { _ in
UIView.animate(withDuration: 0.25, delay: 0.0, usingSpringWithDamping: 0.5, initialSpringVelocity: 3.0, options: .curveEaseInOut, animations: {
imageView.transform = CGAffineTransform(scaleX: 1.0, y: 1.0)
}, completion: nil)
}
}
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
guard let tabbarItemTag = TabbarItemTag(rawValue: item.tag) else {
return
}
switch tabbarItemTag {
case .firstViewController:
animate(firstTabbarItemImageView)
case .secondViewConroller:
animate(secondTabbarItemImageView)
}
}
}
tag
的 tabBarItem
值:
第一个视图控制器:
import UIKit
class FirstViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
tabBarItem.tag = TabbarItemTag.firstViewController.rawValue
}
}
第二个视图控制器:
import UIKit
class SecondViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
tabBarItem.tag = TabbarItemTag.secondViewConroller.rawValue
}
}
确保一切都已通过故事板设置完毕(如果您正在使用故事板),仅此而已!
输出:
您可以检查存储库:
https://github.com/AhmadFayyas/Animated-TabbarItem/tree/master
用于演示答案。
这对我有用:
class MyCustomTabController: UITabBarController {
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
guard let barItemView = item.value(forKey: "view") as? UIView else { return }
let timeInterval: TimeInterval = 0.3
let propertyAnimator = UIViewPropertyAnimator(duration: timeInterval, dampingRatio: 0.5) {
barItemView.transform = CGAffineTransform.identity.scaledBy(x: 0.9, y: 0.9)
}
propertyAnimator.addAnimations({ barItemView.transform = .identity }, delayFactor: CGFloat(timeInterval))
propertyAnimator.startAnimation()
}
}
由于
UITabBarItem
不是 UIView
子类,而是 NSObject
子类,因此没有直接的方法可以在点击时为项目设置动画。
您要么必须挖掘属于该项目的
UIView
并为其设置动画,要么创建一个自定义选项卡栏。
这里有一些挖掘
UIView
的想法。 例如这里如何在点击项目时触发。但使用这种方法要非常小心:
UITabBar
的实现,这可能会打破这一点。顺便说一下,不需要子类化
UITabBar
。您所需要的只是实现 UITabBarDelegate
。
实际上,我建议您坚持使用标准的
UITabBar
行为和蒙皮选项,然后稍后再解决,或者根本不解决。诸如此类的事情会消耗您的时间,而无需为应用程序添加太多内容。
这是具有任意数量控制器的更优化的解决方案。 查看代码中的注释可以更好地理解逻辑。
class TabBarViewController: UITabBarController, UITabBarControllerDelegate {
// MARK: - UI Properties
private var firstVC = UIViewController()
private var secondVC = UIViewController()
private let thirdVC = UIViewController()
private var tabBarImageViews: [UIImageView] = []
public lazy var tabBarHeight = tabBarController?.tabBar.frame.size.height
// Tag to set tabBar items and images to animate
private let startTagValue = 100
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
setControllers()
// Set images to animate possibility
let tabBarSubviews = tabBar.subviews
var imageViewTag = startTagValue
for subview in tabBarSubviews {
if let imageView = subview.subviews.first as? UIImageView {
imageView.contentMode = .center
imageView.tag = imageViewTag
imageViewTag += 1
tabBarImageViews.append(imageView)
}
}
}
// MARK: - Methods
private func setControllers() {
let controllers = [firstVC, secondVC, thirdVC]
viewControllers = controllers.map { UINavigationController(rootViewController: $0)}
// Set tag to each tabBarItem to know what imageView to animate
var controllerItemTag = startTagValue
controllers.forEach { controller in
controller.tabBarItem.tag = controllerItemTag
controllerItemTag += 1
}
}
private func animate(_ imageView: UIImageView) {
UIView.animate(withDuration: 0.1, animations: {
imageView.transform = CGAffineTransform(scaleX: 1.15, y: 1.15)
}) { _ in
UIView.animate(withDuration: 0.25, delay: 0.0, usingSpringWithDamping: 0.5, initialSpringVelocity: 3.0, options: .curveEaseInOut, animations: {
imageView.transform = CGAffineTransform(scaleX: 1.0, y: 1.0)
}, completion: nil)
}
}
// MARK: - Delegate Methods
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
if let imageToAnimate = tabBarImageViews.first(where: { $0.tag == item.tag }) {
animate(imageToAnimate)
}
}
}
也可以将动画应用到 UIView 层。这是一个例子
class TabBarController: UITabBarController {
private var tapAnimation: CAKeyframeAnimation {
let animation = CAKeyframeAnimation(keyPath: "transform.scale")
animation.values = [1.0, 0.75, 1.0]
animation.duration = 0.2
return animation
}
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
guard let index = self.tabBar.items?.firstIndex(of: item) else { return }
let tabView = tabBar.subviews[index + 1]
tabView.layer.add(tapAnimation, forKey: nil)
}
}