Reputation: 2541
Skype app for iPhone uses animated TabBar icons. For example, during the logging-in the rightmost tab icon shows circulating arrows. While calling the "Call" tab icon softly blinks which is obviously done through animation.
I wonder how is it possible to animate tab bar items' icons.
In my particular case when the user presses the 'Favorite' button it jumps onto the 'Favorites' tab bar item. I have already implemented the jumping animation, but I would like the corresponding tab bar icon to blink at the end of animation to bring the feeling of completeness to it.
Any suggestions about the direction I should look in?
Thanks in advance.
Upvotes: 19
Views: 17449
Reputation: 1794
Keep in mind that the order of the subviews in the UITabBar may be unordered so accessing the correct item from it using an index may not work correctly as Naresh answer suggested. Have a look at this post UITabBar subviews change order
The solution I found is to first filter and sort the views and then access it using the correct index of the tabBarItem.
func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
let orderedTabBarItemViews: [UIView] = {
let interactionViews = tabBar.subviews.filter({ $0 is UIControl })
return interactionViews.sorted(by: { $0.frame.minX < $1.frame.minX })
}()
guard
let index = tabBar.items?.firstIndex(of: item),
let subview = orderedTabBarItemViews[index].subviews.first
else {
return
}
performSpringAnimation(for: subview)
}
func performSpringAnimation(for view: UIView) {
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: .curveEaseInOut, animations: {
view.transform = CGAffineTransform(scaleX: 1.25, y: 1.25)
UIView.animate(withDuration: 0.5, delay: 0.2, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: .curveEaseInOut, animations: {
view.transform = CGAffineTransform(scaleX: 1, y: 1)
}, completion: nil)
}, completion: nil)
}
Upvotes: 5
Reputation: 848
Simple way to animate tab bar item in objective c
In your tabbar controller class
- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item
{
UIVisualEffectView *viv = tabBar.subviews[item.tag].subviews.firstObject;
UIImageView *img = viv.contentView.subviews.firstObject;
// If UIImageView not get use this code
// UIImageView *img = tabBar.subviews[item.tag].subviews.lastObject;
[self shakeAnimation:img];
//[self bounceAnimation:img];
}
- (void)shakeAnimation:(UIImageView *)img
{
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
[animation setDuration:0.05];
[animation setRepeatCount:2];
[animation setAutoreverses:YES];
[animation setFromValue:[NSValue valueWithCGPoint: CGPointMake([img center].x - 10.0f, [img center].y)]];
[animation setToValue:[NSValue valueWithCGPoint: CGPointMake([img center].x + 10.0f, [img center].y)]];
[[img layer] addAnimation:animation forKey:@"position"];
}
- (void)bounceAnimation:(UIImageView *)img
{
img.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.001, 0.001);
[UIView animateWithDuration:0.3/1.5 animations:^{
img.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1.1, 1.1);
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.3/2 animations:^{
img.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.9, 0.9);
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.3/2 animations:^{
img.transform = CGAffineTransformIdentity;
}];
}];
}];
}
Upvotes: 1
Reputation: 1852
Index of UIImageView
in subviews is not guaranteed as fist.
The index of UIImageView is not guaranteed as fist in related subviews.
So it is better to access it via class type, and also check for index out of bounds.
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
guard let idx = tabBar.items?.firstIndex(of: item),
tabBar.subviews.count > idx + 1,
let imageView = tabBar.subviews[idx + 1].subviews.compactMap({ $0 as? UIImageView }).first else {
return
}
imageView.layer.add(bounceAnimation, forKey: nil)
}
This is a sample basic bounce animation for that using CAKeyframeAnimation
:
private var bounceAnimation: CAKeyframeAnimation = {
let bounceAnimation = CAKeyframeAnimation(keyPath: "transform.scale")
bounceAnimation.values = [1.0, 1.3, 0.9, 1.0]
bounceAnimation.duration = TimeInterval(0.3)
bounceAnimation.calculationMode = CAAnimationCalculationMode.cubic
return bounceAnimation
}()
Upvotes: 1
Reputation: 955
I have found a better solution to this problem. Adding custom image view is not a better approach because in iOS 10.0 and later on changing the orientation the icon frame & text position changed. You just need to set the class of UITabBarController & put the following code.
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
let index = self.tabBar.items?.index(of: item)
let subView = tabBar.subviews[index!+1].subviews.first as! UIImageView
self.performSpringAnimation(imgView: subView)
}
//func to perform spring animation on imageview
func performSpringAnimation(imgView: UIImageView) {
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: .curveEaseInOut, animations: {
imgView.transform = CGAffineTransform.init(scaleX: 1.4, y: 1.4)
//reducing the size
UIView.animate(withDuration: 0.5, delay: 0.2, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: .curveEaseInOut, animations: {
imgView.transform = CGAffineTransform.init(scaleX: 1, y: 1)
}) { (flag) in
}
}) { (flag) in
}
}
Upvotes: 10
Reputation: 479
You can animate tabbar icons by getting its view, then do whatever animation as you like for the UIView. Below is a simple example with scale transform, cheer!
func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem){
var tabBarView: [UIView] = []
for i in tabBar.subviews {
if i.isKind(of: NSClassFromString("UITabBarButton")! ) {
tabBarView.append(i)
}
}
if !tabBarView.isEmpty {
UIView.animate(withDuration: 0.15, animations: {
tabBarView[item.tag].transform = CGAffineTransform(scaleX: 1.2, y: 1.2)
}, completion: { _ in
UIView.animate(withDuration: 0.15) {
tabBarView[item.tag].transform = CGAffineTransform.identity
}
})
}
}
ps: please assign tag for each UITabBarItem in order
Upvotes: 1
Reputation: 9990
Actually there is much easier way: https://medium.com/@werry_paxman/bring-your-uitabbar-to-life-animating-uitabbaritem-images-with-swift-and-coregraphics-d3be75eb8d4d#.8o1raapyr
Upvotes: 1
Reputation: 2541
I am surprised how easy the solution was!
Add method to your Application Delegate class .m-file (or any other class that manages your UITabBar) containing the following routine:
addSubview:
method. frame.origin.x
value to place the Image right above the tab bat item you want to animate.Pretty easy, don't you think so?
You can call this method on UIApplicationDelegate instance anywhere you need to animate the tab bar item.
Also it is important to notice that you can tap THROUGH the imageView to select the tab bar item as if there was no image over the tab bar. Many interesting conclusions can be done here on what you can do if you know it...
Upvotes: 13
Reputation: 6147
I haven't done that but I would just try to build a CAAnimation e.g. with a CABasicAnimation and add it to the UITabBarItem you want to be animated.
For details about how to set up a CABasicAnimation see the Core Animation Programming Guide: http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/CoreAnimation_guide/Articles/AnimatingLayers.html#//apple_ref/doc/uid/TP40006085-SW1
Upvotes: 0