前言
这是看到一篇文章后感觉很有意思于是就把自己的效果改了改实现了一下,文末有原文链接。
效果
实现步骤
- 自定义一个UITabBar,中心位置放一个按钮,设置按钮的背景图片,按钮一半超出这个自定义的UITabBar。
- 重写自定义UITabBar 的hitTest 方法,根据点击的位置返回点击的视图是 UITabBar还是 UITabBar上面的按钮。这部分很关键,还要处理点击UITabBar超出试图部分的按钮问题。
- 使用KVC将自定义UITabBar 赋值给 UITabBarController
- 在UITabBarController中给自定义UITabBar上面的按钮绑定事件,来联动UITabBarController的事件。
源码解析
自定义UITabBar并重写 hitTest方法
@interface MCTabBar : UITabBar
@property (nonatomic, strong) UIButton *centerBtn; //中间按钮
@end
@implementation MCTabBar
- (instancetype)init{
if (self = [super init]){
[self initView];
}
return self;
}
- (void)initView{
_centerBtn = [UIButton buttonWithType:UIButtonTypeCustom];
// 设定button大小为适应图片
UIImage *normalImage = [UIImage imageNamed:@"tabbar_add"];
_centerBtn.frame = CGRectMake(0, 0, normalImage.size.width+10, normalImage.size.height+10);
[_centerBtn setImage:normalImage forState:UIControlStateNormal];
//去除选择时高亮
_centerBtn.adjustsImageWhenHighlighted = NO;
//根据图片调整button的位置(图片中心在tabbar的中间最上部,这个时候由于按钮是有一部分超出tabbar的,所以点击无效,要进行处理)
_centerBtn.frame = CGRectMake(([UIScreen mainScreen].bounds.size.width - normalImage.size.width-10)/2.0, - normalImage.size.height/2.0-5, normalImage.size.width+10, normalImage.size.height+10);
[self addSubview:_centerBtn];
}
//处理超出区域点击无效的问题
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
UIView *view = [super hitTest:point withEvent:event];
if (view == nil){
//转换坐标
CGPoint tempPoint = [self.centerBtn convertPoint:point fromView:self];
//判断点击的点是否在按钮区域内
if (CGRectContainsPoint(self.centerBtn.bounds, tempPoint)){
//返回按钮
return _centerBtn;
}
//****************** 或者使用这个方法 ****************
//判断如果这个新的点是在发布按钮身上,那么处理点击事件最合适的view就是发布按钮
if ( [self.centerBtn pointInside:point withEvent:event]) {
return self.centerBtn;
}else{//如果点不在发布按钮身上,直接让系统处理就可以了
return [super hitTest:point withEvent:event];
}
}
return view;
}
这里特别介绍一下下面两个方法:
- (CGPoint)convertPoint:(CGPoint)point toView:(nullable UIView *)view;
- (CGPoint)convertPoint:(CGPoint)point fromView:(nullable UIView *)view;
[fromView convertPoint:point toView:toView];
[toView convertPoint:point fromView:fromView];
这两句代码的意思都是将fromView中的点p(40,30)转换为相对toView的坐标。可以看到两段代码的结果是一样的。
处理UITabBarController
注意是
vc2.title=@"医疗";
而不是
vc2.tabBarItem.title =@"医疗";
如果是第二种方法,在设置图片为空的时候,Tabbar下面的文字也不会显示了。
MedicalViewController *vc2=[[MedicalViewController alloc] init];
vc2.title=@"医疗";
vc2.tabBarItem.image=[[UIImage imageNamed:@""] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
vc2.tabBarItem.selectedImage=[[UIImage imageNamed:@""] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
由于UITabBarController的UITabBar属性是readonly,所以无法直接赋值
_mcTabbar = [[MCTabBar alloc] init];
[_mcTabbar.centerBtn addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
//选中时的颜色
_mcTabbar.tintColor = [UIColor colorWithRed:27.0/255.0 green:118.0/255.0 blue:208/255.0 alpha:1];
//透明设置为NO,显示白色,view的高度到tabbar顶部截止,YES的话到底部
_mcTabbar.translucent = NO;
//利用KVC 将自己的tabbar赋给系统tabBar
[self setValue:_mcTabbar forKeyPath:@"tabBar"];
自定义UITabBar上面的按钮绑定事件,来联动UITabBarController的事件。
- (void)buttonAction:(UIButton *)button{
self.selectedIndex = 1;//关联中间按钮
[self rotationAnimation];
}
//tabbar选择时的代理
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController{
if (tabBarController.selectedIndex == 1){//选中中间的按钮
[self rotationAnimation];
}else {
[_mcTabbar.centerBtn.layer removeAllAnimations];
}
}
//旋转动画
- (void)rotationAnimation{
CABasicAnimation *rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
rotationAnimation.toValue = [NSNumber numberWithFloat:M_PI*2.0];
rotationAnimation.duration = 3.0;
rotationAnimation.repeatCount = HUGE;
[_mcTabbar.centerBtn.layer addAnimation:rotationAnimation forKey:@"key"];
}
网友评论