前言
最近根據(jù)產(chǎn)品的需求趾唱,要求實(shí)現(xiàn)tabBar的動(dòng)畫,自己之前做過類似的站欺,純自定義tabBar來加載想要的動(dòng)畫姨夹。這次的需求里還添加了一個(gè)plusButton,類似閑魚的tabBar所以基于CYLTabBarController實(shí)現(xiàn)了更加方便定制的tabBar矾策,然后加上自己的動(dòng)畫效果磷账。最后的效果如下(當(dāng)然,這是參考Demo):
先簡單介紹一下CYLTabBarController的使用
-
由于需要手動(dòng)修改一些方法贾虽,所以不建議使用cocoapods逃糟,而是手動(dòng)集成代碼結(jié)構(gòu)
- 接下來初始化TabBarController,這里參考CYLTabBarController采取Config的方式。
CYLTabBarControllerConfig.himage
CYLTabBarControllerConfig.mimageimageimageimage
這里只顯示了部分绰咽,詳細(xì)的請(qǐng)參考Demo蛉抓。 -
自定義PlusButton。image
需要繼承CYLPlusButton剃诅,以及添加協(xié)議CYLPlusButtonSubclassing巷送。定制想要的樣式。
-
AppDelegate中矛辕。image
(方便大家直接可以看笑跛,所以這里放的是截圖,代碼在Demo里都有)
接下來講述一下動(dòng)畫的定制聊品。
翻轉(zhuǎn)動(dòng)畫
我們想要實(shí)現(xiàn)的效果是水平翻轉(zhuǎn)動(dòng)畫飞蹂。簡單而言,對(duì)于實(shí)現(xiàn)翻轉(zhuǎn)動(dòng)畫翻屈,方式有很多陈哑。
使用Pop
Facebook的Pop動(dòng)畫是很強(qiáng)大的,遇到想要實(shí)現(xiàn)動(dòng)畫的地方第一反應(yīng)就是它伸眶。
POPBasicAnimation *rotateAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerRotationY];
rotateAnimation.fromValue = @(0);
rotateAnimation.toValue = @(M_PI * 2);
rotateAnimation.duration = 0.6; // 0.5 0.3
[view.layer pop_addAnimation:rotateAnimation forKey:@"layerRotateAnimation"];
[rotateAnimation setCompletionBlock:^(POPAnimation *animation, BOOL finished) {
if (finished) {
[UIView animateWithDuration:0.3 animations:^{
// Pop 選擇動(dòng)畫有時(shí)會(huì)發(fā)生動(dòng)畫停止的時(shí)候位置有稍微偏移的情況惊窖,所以最好在動(dòng)畫結(jié)束后恢復(fù)一下
view.transform = CGAffineTransformIdentity;
} completion:nil];
}
}];
使用CABasicAnimation
系統(tǒng)動(dòng)畫,比較直接厘贼,這里同樣也可以使用關(guān)鍵幀動(dòng)畫界酒,可以做得更加自然一點(diǎn)
CABasicAnimation *rotateAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
// 設(shè)定動(dòng)畫選項(xiàng)
rotateAnimation.duration = 1.2; // 持續(xù)時(shí)間
rotateAnimation.repeatCount = 1; // 重復(fù)次數(shù)
// 設(shè)定旋轉(zhuǎn)角度
rotateAnimation.fromValue = @(0); // 起始角度
rotateAnimation.toValue = @(M_PI * 2); // 終止角度
[view.layer addAnimation:rotateAnimation forKey:@"rotateAnimation"];
使用transform動(dòng)畫
[UIView animateWithDuration:0.32 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
view.layer.transform = CATransform3DMakeRotation(M_PI, 0, 1, 0);
} completion:nil];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[UIView animateWithDuration:0.70 delay:0 usingSpringWithDamping:1 initialSpringVelocity:0.2 options:UIViewAnimationOptionCurveEaseOut animations:^{
view.layer.transform = CATransform3DMakeRotation(2 * M_PI, 0, 1, 0);
} completion:nil];
});
我采用的是第三種,其他二者都是可以的嘴秸。之所以寫得有點(diǎn)繁瑣是為了看起來更加自然一點(diǎn)毁欣。
tabBar中添加動(dòng)畫
tabBar的自定義過程中我采取了CYLTabBarController的,另外還可以完全自定義岳掐,完全自定義的話凭疮,所有的tabBarItem都是自定義的Button,動(dòng)畫直接在event中添加即可串述,這里就不詳述执解,有興趣的話可以私下交流一下。
這里來講述CYLTabBarController的tabBar動(dòng)畫剖煌。
在CYLTabBar中的
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;
添加位置如下:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
BOOL canNotResponseEvent = self.hidden || (self.alpha <= 0.01f) || (self.userInteractionEnabled == NO);
if (canNotResponseEvent) {
return nil;
}
if (!CYLExternPlusButton && ![self pointInside:point withEvent:event]) {
return nil;
}
if (CYLExternPlusButton) {
CGRect plusButtonFrame = self.plusButton.frame;
BOOL isInPlusButtonFrame = CGRectContainsPoint(plusButtonFrame, point);
if (!isInPlusButtonFrame && (point.y < 0) ) {
return nil;
}
if (isInPlusButtonFrame) {
self.times ++;
if (self.times % 2 == 0) {
// 這里添加動(dòng)畫
[self addRotateAnimationOnPlusButton];
}
return CYLExternPlusButton;
}
}
NSArray *tabBarButtons = self.tabBarButtonArray;
if (self.tabBarButtonArray.count == 0) {
tabBarButtons = [self tabBarButtonFromTabBarSubviews:self.subviews];
}
for (NSUInteger index = 0; index < tabBarButtons.count; index++) {
UIView *selectedTabBarButton = tabBarButtons[index];
CGRect selectedTabBarButtonFrame = selectedTabBarButton.frame;
if (CGRectContainsPoint(selectedTabBarButtonFrame, point)) {
self.times ++;
if (self.times % 2 == 1) {
// 這里添加動(dòng)畫
[self addRotateAnimation:selectedTabBarButton];
}
return selectedTabBarButton;
}
}
return nil;
}
動(dòng)畫 上述兩個(gè)位置加的動(dòng)畫實(shí)現(xiàn)一樣材鹦,區(qū)分開來方便分開定制
- (void)addRotateAnimationOnPlusButton {
// 這里動(dòng)畫
[UIView animateWithDuration:0.32 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
_plusButton.layer.transform = CATransform3DMakeRotation(M_PI, 0, 1, 0);
} completion:nil];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[UIView animateWithDuration:0.70 delay:0 usingSpringWithDamping:1 initialSpringVelocity:0.2 options:UIViewAnimationOptionCurveEaseOut animations:^{
_plusButton.layer.transform = CATransform3DMakeRotation(2 * M_PI, 0, 1, 0);
} completion:nil];
});
}
由于hit的響應(yīng)比較頻繁逝淹,所以采取了折半耕姊。
重要提示
在設(shè)置tabBar的過程中,如果沒有設(shè)置背景圖片栅葡,即為透明的話茉兰,動(dòng)畫是正常的。但是如果為了需要設(shè)置了背景圖片欣簇,比如:
[[UITabBar appearance] setBackgroundImage:[UIImage imageNamed:@"tab_bar"]];
那么動(dòng)畫會(huì)有明顯的異常规脸。
很明顯的異常坯约。這個(gè)問題我想了挺長時(shí)間,開始一直以為是我動(dòng)畫方法的問題莫鸭,所以嘗試了很多動(dòng)畫闹丐,但都一樣。最后和別人討論了一下問題的原因被因,弄了個(gè)解決方法卿拴。
背景與按鈕圖片處于同一層次,當(dāng)按鈕圖片旋轉(zhuǎn)時(shí)梨与,轉(zhuǎn)軸就在背景圖上堕花,所以會(huì)有一部分在背景圖之下 所以會(huì)有一半被遮住的情況出現(xiàn)。
兩個(gè)在同一圖層粥鞋,所以動(dòng)畫出現(xiàn)了異常缘挽。那么如何解決呢?
- 可以自定義UIimageView放在tabBar上代替tabBarItem呻粹,然后將imageView.layer.zPosition = 最大圖片寬度
- 找到tabbar中放置圖片的imageView壕曼,調(diào)整zPosition
我這里采取了第一種方法。
for (UIView *tabBarButton in self.tabBar.subviews) {
tabBarButton.layer.zPosition = 65.f / 2;//最大圖片寬度的一半
}
還有一點(diǎn)等浊,這個(gè)設(shè)置需要放在TabBarViewController的viewWillAppear方法中
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
for (UIView *tabBarButton in self.tabBar.subviews) {
tabBarButton.layer.zPosition = 65.f / 2;//最大圖片寬度的一半
}
}
為了定制方便窝稿,建議大家繼承CYLTabBarController,使用自己的凿掂,添加功能伴榔,以及這個(gè)設(shè)置。
詳情參考Demo庄萎,希望大家指出我的不足以及改進(jìn)之處踪少,共同學(xué)習(xí)進(jìn)步
附github地址:
https://github.com/hllGitHub/CYLTabBarController
也可以加入群:(139852091)Demo不用寫,說就行 一起交流糠涛。