父老乡亲们,我葫芦娃又回来了~
今天我们来侃一侃tabBarItem中动画的另一种实现方式;
前几日学习项目,需要给tabBarItem添加一个类似弹簧效果的动画,原作者的思路是自定义了几个View填充了tabBar
,给这些View设置了手势监听来实现动画效果,代码非常繁琐,如果只是简单的让tabBarItem实现需求的动画,我尝试着有没有更简单的方法来做;原项目的效果如下:
动画的实现,本质来讲就是拿到需要实现动画的UIView
,然后把需求动画添加到它的layer上就可以了;
我们现在的目的就是拿到TabBar
上对应的控件,把对应的动画添加上去;这样就可以既使用系统的tabBar原有的功能,又添加了动画;
假定我现在的需求是只给tabBarItem中的image添加一个弹簧效果;
- 自定义tabBar
- 在自定义的tabBar中拿到点击控件,添加点击的监听事件
- 在监听事件中把动画添加到动画控件的layer上
(1) 由于tabBar
是tabBarController
的只读属性,因此我们用KVC来设置
- (void)viewDidLoad {
[super viewDidLoad];
//使用KVC来进行设置
FGTabBar *myTabBar = [[FGTabBaralloc] init];
[selfsetValue:myTabBar forKey:@"tabBar"];
}
(2) 在自定义的tabBar
中,尝试从tabBar
的子控件中下手;
- (void)layoutSubviews
{
[super layoutSubviews];
NSLog(@"%@",self.subviews);
}
打印结果如下:
"<_UITabBarBackgroundView: 0x7fddb21236e0; frame = (0 0; 375 49); autoresize = W; userInteractionEnabled = NO; layer = <CALayer: 0x7fddb21297d0>>",
"<UITabBarButton: 0x7fddb23bb500; frame = (2 1; 90 48); opaque = NO; layer = <CALayer: 0x7fddb2130880>>",
"<UITabBarButton: 0x7fddb217e1a0; frame = (96 1; 90 48); opaque = NO; layer = <CALayer: 0x7fddb217eec0>>",
"<UITabBarButton: 0x7fddb2184700; frame = (190 1; 89 48); opaque = NO; layer = <CALayer: 0x7fddb2184e20>>",
"<UITabBarButton: 0x7fddb21893c0; frame = (283 1; 90 48); opaque = NO; layer = <CALayer: 0x7fddb2189b60>>",
"<UIImageView: 0x7fddb217ea70; frame = (0 -0.5; 375 0.5); autoresize = W; userInteractionEnabled = NO; layer = <CALayer: 0x7fddb219fa40>>"
中间的四个子控件就是tabBarItem中对应的每个按钮(到这里就可以类比UIButton
的思想来继续了),它有没有可能也是继承自UIControl
的一种按钮类型?
在layoutSubviews
中添加下面的代码:
for (UIView *tabBarButton in self.subviews) {
if ([tabBarButton isKindOfClass:NSClassFromString(@"UITabBarButton")]) { // 之所以这么写是因为UITabBarButton是苹果私有API
NSLog(@"%@",tabBarButton.superclass);
}
}
打印出的结果不出所料正是UIControl
,那么就可以添加addTarget
的监听方法;
(3) 由于需求只是让tabBarButton上的图片进行动画,因此我们通过打印tabBarButton的子控件,可以找到其中展示图片的imageView,把动画添加到这个imageView的layer上就可以了;打印结果如下:
"<UITabBarSwappableImageView: 0x7fd7ebc52760; frame = (32 5.5; 25 25); opaque = NO; userInteractionEnabled = NO; tintColor = UIDeviceWhiteColorSpace 0.572549 1; layer = <CALayer: 0x7fd7ebc52940>>",
"<UITabBarButtonLabel: 0x7fd7ebc4f360; frame = (29.5 35; 30 12); text = '\U8d2d\U7269\U8f66'; opaque = NO; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x7fd7ebc4e090>>"
在监听的方法中,通过与第(2)步类似的步骤,拿到这个ImageView,添加动画就可以了;当然也可以给label添加动画,也可以给整个tabBarButton添加动画;
完整的代码如下:
- (void)layoutSubviews{
[super layoutSubviews];
for (UIControl *tabBarButton in self.subviews) {
if ([tabBarButton isKindOfClass:NSClassFromString(@"UITabBarButton")]) {
[tabBarButton addTarget:selfaction:@selector(tabBarButtonClick:) forControlEvents:UIControlEventTouchUpInside];
}
}
}
- (void)tabBarButtonClick:(UIControl *)tabBarButton
{
for (UIView *imageView in tabBarButton.subviews) {
if ([imageView isKindOfClass:NSClassFromString(@"UITabBarSwappableImageView")]) {
//需要实现的帧动画,这里根据需求自定义
CAKeyframeAnimation *animation = [CAKeyframeAnimationanimation];
animation.keyPath = @"transform.scale";
animation.values = @[@1.0,@1.3,@0.9,@1.15,@0.95,@1.02,@1.0];
animation.duration = 1;
animation.calculationMode = kCAAnimationCubic;
//把动画添加上去就OK了
[imageView.layeraddAnimation:animation forKey:nil];
}
}
}
最后实现的效果如下:
测试动画.gif
总结
因此,如果以后只是单纯的实现tabBarItem上的动画,不需要对tabBar进行大刀阔斧的改动,也可以尝试用这种方法来做;
今天就先侃到这里了,小弟只是抛砖引玉,大家有建议的话可以留言给我,共同玩耍于iOS乐园;
散了散了,回家收衣服了~
网友评论
{
viewController.tabBarItem.qmui_imageView.transform = CGAffineTransformMakeScale(0.6,0.6);
// 弹簧动画,参数分别为:时长,延时,弹性(越小弹性越大),初始速度
[UIView animateWithDuration: 0.7 delay:0 usingSpringWithDamping:0.3 initialSpringVelocity:0.3 options:0 animations:^{
// 放大
viewController.tabBarItem.qmui_imageView.transform = CGAffineTransformMakeScale(1,1);
} completion:nil];
}
还有种方法,设置UITabBarControllerDelegate 也可以
animation.values = @[@1.0,@1.3,@0.9,@1.15,@0.95,@1.02,@1.0];这里面值哪位大大帮我解释一下,感谢
这个数组表示的是属性值animation.keyPath(Demo中使用的是scale,就是transform的缩放比例)在动画过程中的关键帧,每一个元素都是一个缩放比例,这几个关键帧实现了弹簧的效果.
每次都添加不好吧 初始化的完毕的时候 那个button应该就已经存在了。 直接加事件应该可以
我之前也是这么想的,因为我是用alloc init创建的自定义tabBar,然后在initWithFrame的方法中打印tabBar的子控件,发现是空的...
所有就写在了layoutSubviews,这个方法只会调用两次,也不是很频繁