专栏首页進无尽的文章实践 -实现一款中间凸起的TabBar

实践 -实现一款中间凸起的TabBar

前言

这是看到一篇文章后感觉很有意思于是就把自己的效果改了改实现了一下,文末有原文链接。

效果

实现步骤

  • 自定义一个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"];
}

参考文章: https://www.jianshu.com/p/5160a1b48679

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 扒虫篇-Bug日志 Ⅵ

    试了试其他的账号也是一样,在账号密码没有输入错误的情况下还是登陆不上。 解决办法:重启电脑就解决了。

    進无尽
  • 绘图- 镂空效果及其动画实现解析

    有时你会看到很多镂空的试图或者是镂空视图的动画效果,感觉很酷炫,其实只要掌握其中实现的原理,想实现怎样的效果就能实现怎样的镂空效果。

    進无尽
  • 动画| 魔性形变之CGAffineTransform的使用

    在介绍UIView的2D、3D形变之前需要知道一个概念,那就是锚点,各种变换就会按照这个点来运动。所以想达到特殊的效果,可以通过修改锚点的位置来达到。

    進无尽
  • Leetcode【24、109、328、455、725】

    这道题是给一个链表,相邻结点数值两两进行交换,要求不修改结点值且只能操作链表本身。

    echobingo
  • 通过python读取ini配置文件

    你可以理解为就是一个配置文件的统称吧。比如test.conf,这样的你可以理解为他就是ini文件,里面一般存放一些配置信息。比如数据库的基本信息,一会我们进行讲...

    py3study
  • 微信小程序模块化引用

    任我行RQ
  • MySQL与Python的交互

    1、交互类型 1、安装引入模块 安装mysql模块,在windows和ubuntu中 ? windows里安装mysql模块 ? Linux里安装mysql模块...

    用户1332428
  • MySQL与Python的交互1.交互类型2.增删改查(CRUD)3.封装

    意气相许的许
  • Python学习 :反射 & 单例模式

      - 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。

    py3study
  • Python|GUI编程Button组件介绍

    接着上一篇python GUI编程的基础介绍,接下来详细介绍一下里面的Button组件,下面我会以最详细的描述介绍这个组件里的参数。先把一个组件放到一个窗口上,...

    算法与编程之美

扫码关注云+社区

领取腾讯云代金券