iOS开发-实现自定义Tabbar及tabbar按钮动画效果
之前整理了一个继承UITabbarController的Tabbar效果
查看
https://blog.csdn.net/gloryFlow/article/details/132012628
这里是继承与UIViewController的INSysTabbarViewController实现及点击tabbar按钮动画效果。
一、INSysTabbar自定义
INSysTabbar继承UIView,实现tabbarButton效果
INSysTabbar.h
#import <UIKit/UIKit.h>
#import "INSysTabbarButton.h"
#import "INSysTabbarShapeView.h"@protocol INSysTabbarDelegate;
@interface INSysTabbar : UIView@property (nonatomic, weak) id<INSysTabbarDelegate>tabDelegate; //代理
@property (nonatomic, strong) UIImage *bgroundImage; //背景图
@property (nonatomic, strong) INSysTabbarShapeView *tabbarBGShapeView; //背景图@property (nonatomic, strong) UIColor *lineColor; //线条的颜色
@property (nonatomic, strong) NSArray *dataSources; //tabbarItem列表
@property (nonatomic, assign) BOOL showLine; //线条的颜色@property (nonatomic, assign) NSInteger selectedIndex; //选中的tabbar按钮index- (instancetype)initWithFrame:(CGRect)frame;/**默认设置第几个index*/
- (void)resetSysTabbar:(NSInteger)index;/**更新tabbar样式@param tabbarItem item*/
- (void)updateTabbarStyle:(INSysTabbarItem *)tabbarItem;@end@protocol INSysTabbarDelegate <NSObject>- (void)tabBar:(INSysTabbar *)tabBar tabDidSelectedIndex:(NSInteger)index;@end
INSysTabbar.m
#import "INSysTabbar.h"
#import "UIView+SafeEdgeInsets.h"
#import "UIColor+Addition.h"static CGFloat kLineHeight = 1.0;
static CGFloat kPadding = 5.0;@interface INSysTabbar ()@property (nonatomic, strong) UIImageView *bgImageView;
@property (nonatomic, strong) UIImageView *lineImageView;
@property (nonatomic, assign) CGFloat safeInsetBottom;
@property (nonatomic, strong) NSMutableArray *buttonViews;@end@implementation INSysTabbar- (instancetype)initWithFrame:(CGRect)frame {self = [super initWithFrame:frame];if (self) {self.buttonViews = [NSMutableArray arrayWithCapacity:0];[self addSubview:self.bgImageView];[self addSubview:self.lineImageView];[self addSubview:self.tabbarBGShapeView];self.showLine = NO;}return self;
}- (void)layoutSubviews {[super layoutSubviews];self.bgImageView.frame = self.bounds;self.tabbarBGShapeView.frame = self.bounds;self.safeInsetBottom = [UIView baseSafeAreaEdgeInsets].bottom;if (self.dataSources && self.dataSources.count > 0) {CGFloat width = CGRectGetWidth(self.bounds) / self.dataSources.count;CGFloat height = CGRectGetHeight(self.bounds);for (UIView *subView in self.subviews) {if ([subView isKindOfClass:[INSysTabbarButton class]]) {INSysTabbarButton *tabbarButton = (INSysTabbarButton *)subView;CGRect imageBounds = CGRectMake(0.0, 0.0, width, height);CGPoint imageCenter = CGPointMake((tabbarButton.tag + 0.5) * width, height/2 - self.safeInsetBottom/2);tabbarButton.bounds = imageBounds;tabbarButton.center = imageCenter;}}}self.lineImageView.frame = CGRectMake(0.0, 0.0, CGRectGetWidth(self.bgImageView.frame), kLineHeight);[self setTabbarSubview];
}/**更新系统tabbar的选中状态*/
- (void)updateTabbarButtons {for (UIView *subView in self.subviews) {if ([subView isKindOfClass:[INSysTabbarButton class]]) {INSysTabbarButton *tabbarButton = (INSysTabbarButton *)subView;if (tabbarButton.tag == self.selectedIndex) {tabbarButton.selected = YES;} else {tabbarButton.selected = NO;}}}
}/**隐藏系统的tabbarButton*/
- (void)setTabbarSubview {for (UIView *child in self.subviews) {Class class = NSClassFromString(@"UITabBarButton");if ([child isKindOfClass:class]) {child.hidden = YES;}}
}/**重新创建tabbarButtons*/
- (void)setupTabbarButtons {[self.buttonViews removeAllObjects];for (UIView *subView in self.subviews) {if ([subView isKindOfClass:[INSysTabbarButton class]]) {[subView removeFromSuperview];}}for (NSInteger index = 0; index < self.dataSources.count; index ++) {INSysTabbarItem *tabbarItem = [self.dataSources objectAtIndex:index];INSysTabbarButton *tabbarButton = [[INSysTabbarButton alloc] initWithFrame:CGRectZero];tabbarButton.userInteractionEnabled = YES;tabbarButton.tabbarItem = tabbarItem;tabbarButton.tag = index;tabbarButton.maxCircleSize = 40.0;[tabbarButton addTarget:self action:@selector(tabbarButtonSelected:) forControlEvents:UIControlEventTouchUpInside];[self addSubview:tabbarButton];[self.buttonViews addObject:tabbarButton];}[self.bgImageView bringSubviewToFront:self.lineImageView];[self setNeedsLayout];
}- (void)setDataSources:(NSArray *)dataSources {_dataSources = dataSources;[self setupTabbarButtons];[self setNeedsLayout];
}- (void)setBgroundImage:(UIImage *)bgroundImage {_bgroundImage = bgroundImage;self.bgImageView.image = bgroundImage;[self setNeedsLayout];
}- (void)setLineColor:(UIColor *)lineColor {_lineColor = lineColor;self.lineImageView.backgroundColor = lineColor;[self setNeedsLayout];
}- (void)setShowLine:(BOOL)showLine {_showLine = showLine;self.lineImageView.hidden = !showLine;[self setNeedsLayout];
}- (void)setSelectedIndex:(NSInteger)selectedIndex {_selectedIndex = selectedIndex;[self updateTabbarButtons];if (self.tabDelegate && [self.tabDelegate respondsToSelector:@selector(tabBar:tabDidSelectedIndex:)]) {[self.tabDelegate tabBar:self tabDidSelectedIndex:selectedIndex];}
}/**更新tabbar样式@param tabbarItem item*/
- (void)updateTabbarStyle:(INSysTabbarItem *)tabbarItem {for (UIView *subView in self.subviews) {if ([subView isKindOfClass:[INSysTabbarButton class]]) {INSysTabbarButton *tabbarButton = (INSysTabbarButton *)subView;INSysTabbarItem *item = tabbarButton.tabbarItem;if (tabbarItem.identifier && [tabbarItem.identifier isEqualToString:item.identifier]) {//更新tabbar[item copyClone:tabbarItem];tabbarButton.tabbarItem = item;break;}}}
}/**默认设置第几个index*/
- (void)resetSysTabbar:(NSInteger)index {INSysTabbarButton *selectedButton = nil;for (INSysTabbarButton *subButton in self.buttonViews) {if (subButton.tag == index) {selectedButton = subButton;}}if (selectedButton) {[self buttonClick:selectedButton];self.selectedIndex = selectedButton.tag;}
}#pragma mark - Actions
- (void)tabbarButtonSelected:(INSysTabbarButton *)tabbarButton {if (self.selectedIndex != tabbarButton.tag) {[self buttonClick:tabbarButton];}self.selectedIndex = tabbarButton.tag;
}- (void)buttonClick:(INSysTabbarButton *)button {CGRect buttonFrame = button.frame;self.tabbarBGShapeView.anchorPointX = CGRectGetMidX(buttonFrame);for (INSysTabbarButton *subButton in self.buttonViews) {subButton.hasShowedCircle = NO;CGRect subButtonFrame = subButton.frame;subButtonFrame.origin.y = 0.0;subButton.frame = subButtonFrame;[subButton reset];}[button circleAnimationDuration:0.5];
}- (void)addShakeAnimation:(UIView *)view {CABasicAnimation* shake = [CABasicAnimation animationWithKeyPath:@"transform.translation.y"];shake.fromValue = [NSNumber numberWithFloat:-5];shake.toValue = [NSNumber numberWithFloat:5];shake.duration = 0.1;//执行时间shake.autoreverses = YES; //是否重复shake.repeatCount = 1;//次数[view.layer addAnimation:shake forKey:@"shakeAnimation"];
}#pragma mark - GETTER
- (UIImageView *)bgImageView {if (!_bgImageView) {_bgImageView = [[UIImageView alloc] initWithFrame:CGRectZero];_bgImageView.backgroundColor = [UIColor clearColor];_bgImageView.clipsToBounds = YES;}return _bgImageView;
}- (INSysTabbarShapeView *)tabbarBGShapeView {if (!_tabbarBGShapeView) {_tabbarBGShapeView = [[INSysTabbarShapeView alloc] initWithFrame:CGRectZero];_tabbarBGShapeView.buttonSize = 30.0;_tabbarBGShapeView.anchorPointX = 0.0;}return _tabbarBGShapeView;
}- (UIImageView *)lineImageView {if (!_lineImageView) {_lineImageView = [[UIImageView alloc] initWithFrame:CGRectZero];_lineImageView.backgroundColor = [UIColor colorWithHexString:@"f3f3f3" alpha:1.0];}return _lineImageView;
}@end
二、TabbarButton实现
UIButton继承UIControl,我这里继承UIControl实现自定义按钮
INSysTabbarButton.h
#import <UIKit/UIKit.h>
#import "INSysTabbarItem.h"@interface INSysTabbarButton : UIControl@property (nonatomic, strong) UIImageView *bkImageView;
@property (nonatomic, strong) INSysTabbarItem *tabbarItem;
@property (nonatomic, assign) BOOL hasShowedCircle; // 当前显示的
@property (nonatomic) CGFloat maxCircleSize; // circle的size- (instancetype)initWithFrame:(CGRect)frame;- (void)reset;- (void)circleAnimationDuration:(CGFloat)aDuration;@end
INSysTabbarButton.m
#import "INSysTabbarButton.h"
#import "NSString+Size.h"static CGFloat kIconSize = 26.0;
static CGFloat kTitleHeight = 18.0;
static CGFloat kBadgeSize = 8.0;
static CGFloat kPadding = 5.0;
static CGFloat defaultBadgeRadius = 9.0;
static CGFloat defaultDotRadius = 5.0;#define kTabbarDotShown @"dotShown"
#define kTabbarBadge @"badge"@interface INSysTabbarButton ()@property (nonatomic, strong) UIImageView *iconImageView;
@property (nonatomic, strong) UIImageView *badgeImageView;
@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) UILabel *badgeLabel;@end@implementation INSysTabbarButton#pragma mark - INIT
- (instancetype)initWithFrame:(CGRect)frame {self = [super initWithFrame:frame];if (self) {[self addSubview:self.bkImageView];[self addSubview:self.iconImageView];[self addSubview:self.titleLabel];[self addSubview:self.badgeImageView];[self addSubview:self.badgeLabel];}return self;
}- (void)layoutSubviews {[super layoutSubviews];CGSize titleSize = [self.titleLabel.text sizeWithFont:self.titleLabel.font forMaxSize:CGSizeMake(CGRectGetWidth(self.bounds), kTitleHeight)];CGFloat titleHeight = MIN(ceil(titleSize.height), kTitleHeight);CGFloat iconSize = 0.0;if (self.iconImageView.image) {iconSize = kIconSize;}self.titleLabel.frame = CGRectMake(0.0, CGRectGetHeight(self.bounds) - kPadding - titleHeight, CGRectGetWidth(self.bounds), titleHeight);if (self.hasShowedCircle) {self.iconImageView.frame = CGRectMake((CGRectGetWidth(self.bounds) - iconSize)/2, CGRectGetMinY(self.titleLabel.frame) - self.maxCircleSize + (self.maxCircleSize - iconSize)/2, iconSize, iconSize);} else {self.iconImageView.frame = CGRectMake((CGRectGetWidth(self.bounds) - iconSize)/2, CGRectGetMinY(self.titleLabel.frame) - iconSize, iconSize, iconSize);}self.bkImageView.center = self.iconImageView.center;CGSize badgeSize = [self.badgeLabel.text sizeWithFont:self.badgeLabel.font forMaxSize:CGSizeMake(20.0, 20.0)];CGFloat minWidth = MAX(defaultBadgeRadius * 2, badgeSize.width + 10.0);CGFloat minHight = MAX(defaultBadgeRadius * 2, badgeSize.height);CGRect badgeBounds = CGRectMake(0.0, 0.0, minWidth, minHight);CGPoint badgeCenter = CGPointMake(CGRectGetMidX(self.iconImageView.frame) + CGRectGetHeight(badgeBounds), CGRectGetMidY(self.iconImageView.frame) - CGRectGetHeight(badgeBounds)/2 + 5.0);self.badgeLabel.bounds = badgeBounds;self.badgeLabel.center = badgeCenter;self.badgeLabel.layer.cornerRadius = minHight / 2;
}#pragma mark - SETTER
- (void)setTabbarItem:(INSysTabbarItem *)tabbarItem {_tabbarItem = tabbarItem;//设置iconself.iconImageView.image = tabbarItem.image;//设置标题self.titleLabel.font = tabbarItem.titleFont;self.titleLabel.textColor = tabbarItem.titleColor;self.titleLabel.text = [NSString stringWithFormat:@"%@",(tabbarItem.title?tabbarItem.title:@"")];//设置红点self.badgeImageView.hidden = !tabbarItem.dotShown;//设置badgeself.badgeLabel.backgroundColor = tabbarItem.badgeColor;self.badgeLabel.text = [NSString stringWithFormat:@"%@",(tabbarItem.badge?tabbarItem.badge:@"")];if(tabbarItem.badge && tabbarItem.badge.length > 0) {self.badgeLabel.hidden = NO;} else {self.badgeLabel.hidden = YES;}[self addObserver];[self setNeedsLayout];
}- (void)setSelected:(BOOL)selected {[super setSelected:selected];if (selected) {self.titleLabel.textColor = self.tabbarItem.selectedTitleColor;self.iconImageView.image = self.tabbarItem.selectedImage;} else {self.titleLabel.textColor = self.tabbarItem.titleColor;self.iconImageView.image = self.tabbarItem.image;}
}- (void)setHasShowedCircle:(BOOL)hasShowedCircle {_hasShowedCircle = hasShowedCircle;if (hasShowedCircle) {self.bkImageView.alpha = 1.0;} else {self.bkImageView.alpha = 0.0;}
}- (void)circleAnimationDuration:(CGFloat)aDuration {self.hasShowedCircle = YES;self.bkImageView.alpha = 0.0;self.bkImageView.transform = CGAffineTransformMakeScale(0.1, 0.1);CGRect iconFrame = self.iconImageView.frame;iconFrame.origin.y = CGRectGetMinY(self.titleLabel.frame) - self.maxCircleSize + (self.maxCircleSize - iconFrame.size.height)/2;[UIView animateWithDuration:aDuration animations:^{self.bkImageView.transform = CGAffineTransformMakeScale(1.0, 1.0);self.bkImageView.alpha = 1.0;self.iconImageView.frame = iconFrame;} completion:^(BOOL finished) {[self.iconImageView.layer removeAnimationForKey:@"shakeAnimation"];[self startIconShakeAnimation];}];
}- (void)startIconShakeAnimation {CABasicAnimation* shake = [CABasicAnimation animationWithKeyPath:@"transform.translation.y"];shake.fromValue = [NSNumber numberWithFloat:-3];shake.toValue = [NSNumber numberWithFloat:3];shake.duration = 0.15;//执行时间shake.autoreverses = YES; //是否重复shake.repeatCount = 1;//次数[self.iconImageView.layer addAnimation:shake forKey:@"shakeAnimation"];
}- (void)reset {self.hasShowedCircle = NO;[self layoutSubviews];[self.iconImageView.layer removeAnimationForKey:@"shakeAnimation"];
}#pragma mark - GETTER
- (UIImageView *)bkImageView {if (!_bkImageView) {_bkImageView = [[UIImageView alloc] initWithFrame:CGRectZero];_bkImageView.backgroundColor = [UIColor colorWithHexString:@"ff244c" alpha:0.25];_bkImageView.contentMode = UIViewContentModeScaleAspectFit;_bkImageView.clipsToBounds = YES;_bkImageView.frame = CGRectMake(0.0, 0.0, 40.0, 40.0);_bkImageView.layer.cornerRadius = 20.0;_bkImageView.layer.masksToBounds = YES;_bkImageView.alpha = 0.0;}return _bkImageView;
}- (UIImageView *)iconImageView {if (!_iconImageView) {_iconImageView = [[UIImageView alloc] initWithFrame:CGRectZero];_iconImageView.backgroundColor = [UIColor clearColor];_iconImageView.contentMode = UIViewContentModeScaleAspectFit;_iconImageView.clipsToBounds = YES;}return _iconImageView;
}- (UIImageView *)badgeImageView {if (!_badgeImageView) {_badgeImageView = [[UIImageView alloc] initWithFrame:CGRectZero];_badgeImageView.backgroundColor = [UIColor clearColor];_badgeImageView.frame = CGRectMake(0.0, 0.0, kBadgeSize, kBadgeSize);_badgeImageView.layer.cornerRadius = kBadgeSize/2;_badgeImageView.layer.masksToBounds = YES;_badgeImageView.hidden = YES;}return _badgeImageView;
}- (UILabel *)titleLabel {if (!_titleLabel) {_titleLabel = [[UILabel alloc]initWithFrame:CGRectZero];_titleLabel.backgroundColor = [UIColor clearColor];_titleLabel.textAlignment = NSTextAlignmentCenter;}return _titleLabel;
}- (UILabel *)badgeLabel {if (!_badgeLabel) {_badgeLabel = [[UILabel alloc]initWithFrame:CGRectZero];_badgeLabel.backgroundColor = [UIColor clearColor];_badgeLabel.textAlignment = NSTextAlignmentCenter;_badgeLabel.clipsToBounds = YES;_badgeLabel.textColor = [UIColor whiteColor];_badgeLabel.font = [UIFont systemFontOfSize:11];}return _badgeLabel;
}#pragma mark KVO Refresh
- (void)addObserver{__weak typeof(self) weakSelf = self;[self.KVOController observe:self.tabbarItem keyPath:kTabbarBadge options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew block:^(id _Nullable observer, id _Nonnull object, NSDictionary<NSString *,id> * _Nonnull change) {if ([change objectForKey:NSKeyValueChangeNewKey]) {__strong typeof(weakSelf) strongSelf = weakSelf;NSString *badge = weakSelf.tabbarItem.badge;weakSelf.badgeLabel.text = [NSString stringWithFormat:@"%@",(badge?badge:@"")];if(badge && badge.length > 0) {strongSelf.badgeLabel.hidden = NO;} else {strongSelf.badgeLabel.hidden = YES;}[strongSelf setNeedsLayout];}}];[self.KVOController observe:self.tabbarItem keyPath:kTabbarDotShown options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew block:^(id _Nullable observer, id _Nonnull object, NSDictionary<NSString *,id> * _Nonnull change) {if ([change objectForKey:NSKeyValueChangeNewKey]) {__strong typeof(weakSelf) strongSelf = weakSelf;strongSelf.badgeImageView.hidden = !strongSelf.tabbarItem.dotShown;[strongSelf setNeedsLayout];}}];
}- (void)removeObserver{[self.KVOController unobserveAll];
}- (void)dealloc {[self removeObserver];
}
@end
三、实现切换点击按钮动画效果
当点击tabbar按钮时候,被点击的按钮上移,tabbar显示凸起效果。实现CAShapeLayer结合path,最后由CADisplayLink控制动画效果。
代码如下
INSysTabbarShapeView.h
#import <UIKit/UIKit.h>
#import "UIColor+Addition.h"@interface INSysTabbarShapeView : UIView@property (nonatomic, assign) CGFloat anchorPointX; // 圆角的中心点
@property (nonatomic, assign) CGFloat buttonSize; // 按钮的大小@end
INSysTabbarShapeView.m
#import "INSysTabbarShapeView.h"@interface INSysTabbarShapeView ()@property (nonatomic, strong) CAShapeLayer *shapeLayer;
@property (nonatomic, strong) UIBezierPath *path;
@property (nonatomic, strong) CADisplayLink *displayLink;
@property (nonatomic, assign) int currentFrame;
@property (nonatomic, assign) BOOL animationStepOne;
@property (nonatomic, assign) BOOL animationStepTwo;@end@implementation INSysTabbarShapeView- (instancetype)initWithFrame:(CGRect)frame {self = [super initWithFrame:frame];if (self) {[self.layer addSublayer:self.shapeLayer];self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateShapeConfig)];[self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];self.displayLink.paused = YES;[self configPath:0.0 btnSize:0.0];}return self;
}- (void)configPath:(CGFloat)btnScale btnSize:(CGFloat)btnSize{CGFloat width = CGRectGetWidth(self.bounds);CGFloat height = CGRectGetHeight(self.bounds);CGFloat btnWidth = btnScale*btnSize;CGFloat distance = btnScale*10;CGPoint pointA = CGPointMake(0.0, 0.0);CGPoint pointB = CGPointMake(0.0, height);CGPoint pointC = CGPointMake(width, height);CGPoint pointD = CGPointMake(width, 0.0);CGPoint pointF = CGPointMake(self.anchorPointX + btnWidth + distance, 0.0);CGPoint pointE = CGPointMake(self.anchorPointX - btnWidth - distance, 0.0);CGPoint pointK = CGPointMake(pointE.x+distance, 0.0);CGPoint pointL = CGPointMake(pointF.x-distance, 0.0);CGPoint pointH = CGPointMake(pointK.x+distance, -btnWidth/4);CGPoint pointI = CGPointMake(pointL.x-distance, -btnWidth/4);CGPoint pointG = CGPointMake(self.anchorPointX, -btnWidth*3.5/4);UIBezierPath *path = [UIBezierPath bezierPath];[path moveToPoint:pointA];[path addLineToPoint:pointB];[path addLineToPoint:pointC];[path addLineToPoint:pointD];[path addLineToPoint:pointF];[path addQuadCurveToPoint:pointI controlPoint:pointL];[path addQuadCurveToPoint:pointH controlPoint:pointG];[path addQuadCurveToPoint:pointE controlPoint:pointK];[path addLineToPoint:pointA];[path closePath];self.shapeLayer.path = path.CGPath;
}- (void)setAnchorPointX:(CGFloat)anchorPointX {_anchorPointX = anchorPointX;self.currentFrame = 1;self.animationStepOne = NO;self.animationStepTwo = NO;self.displayLink.paused = NO;
}- (void)setButtonSize:(CGFloat)buttonSize {_buttonSize = buttonSize;
}- (void)updateShapeConfig {// 先放大的大一点,之后回到正常的大小if (!self.animationStepOne) {CGFloat animationDuration = 0.5;int maxFrames = animationDuration / self.displayLink.duration;self.currentFrame++;CGFloat scale = 1.0;if (self.currentFrame <= maxFrames) {scale = ((CGFloat)(_currentFrame) / (CGFloat)(maxFrames));}else {scale = 1.0;self.animationStepOne = YES;self.animationStepTwo = NO;// 第二阶段时间为0.15,maxFrames为CGFloat stepTwoAnimationDuration = 0.35;int stepTwoMaxFrames = stepTwoAnimationDuration / self.displayLink.duration;self.currentFrame = stepTwoMaxFrames;}[self configPath:scale btnSize:self.buttonSize*1.1];} else {if (!self.animationStepTwo) {CGFloat animationDuration = 0.35;int maxFrames = animationDuration / self.displayLink.duration;self.currentFrame--;CGFloat scale = 1.0;if (self.currentFrame > 1 && scale > 0.9) {scale = 1.0 - ((CGFloat)(_currentFrame) / (CGFloat)(maxFrames));}else {scale = 0.9;self.currentFrame = 1;self.animationStepTwo = YES;self.displayLink.paused = YES;}if (scale < 0.9) {scale = 0.9;self.currentFrame = 1;self.animationStepTwo = YES;self.displayLink.paused = YES;}[self configPath:scale btnSize:self.buttonSize*1.1];}}
}#pragma mark - SETTER/GETTER
- (CAShapeLayer *)shapeLayer {if (!_shapeLayer) {_shapeLayer = [CAShapeLayer layer];_shapeLayer.fillColor = [UIColor whiteColor].CGColor;_shapeLayer.shadowColor = [UIColor colorWithHexString:@"acacac"].CGColor;_shapeLayer.shadowOffset = CGSizeMake(0, -1);_shapeLayer.shadowOpacity = 0.25;_shapeLayer.shadowRadius = 2.0;}return _shapeLayer;
}@end
四、实现Tabbar的INSysTabbarViewController控制器
INSysTabbarViewController继承UIViewController
通过在viewDidLoad中将Tabbar放置到view。
- (void)viewDidLoad {[super viewDidLoad];// Do any additional setup after loading the view.self.view.exclusiveTouch = YES;// iOS 7.0 以上系统的处理self.automaticallyAdjustsScrollViewInsets = NO;self.extendedLayoutIncludesOpaqueBars = YES;self.edgesForExtendedLayout = UIRectEdgeAll;self.navigationController.navigationBar.translucent = NO;// 将tabbar放置到view上[self.view addSubview:self.sysTabbar];
}
在点击tabbar按钮进行切换显示对应的controller时候,实现tabbar的delegate
#pragma mark - SDTabBarDelegate
- (void)tabBar:(INSysTabbar *)tabBar tabDidSelectedIndex:(NSInteger)index {self.selectedIndex = index;UIViewController *viewController = [self.viewControllers objectAtIndex:index];viewController.view.tag = index;viewController.view.frame = CGRectMake(0.0, 0.0, kTabScreenWidth, kTabScreenHeight);[self.view insertSubview:viewController.view belowSubview:self.sysTabbar];[self addChildViewController:viewController];
}
将需要显示的controller显示的insertSubview。
INSysTabbarViewController代码如下
INSysTabbarViewController.h
#import <UIKit/UIKit.h>
#import "INSysTabbar.h"
#import "UIView+SafeEdgeInsets.h"
#import "UIViewController+SysTabbarItem.h"
#import "SDBaseViewController.h"@interface INSysTabbarViewController : SDBaseViewController// 如果是tabbar嵌套Navigation时候,这个selectedNavigationController不为null
// 如果Navigation嵌套tabbar时候,这个selectedNavigationController可能为null
@property (nonatomic, strong, readonly) UINavigationController *selectedNavigationController;@property (nonatomic, strong) NSArray *tabViewControllers;
@property (nonatomic, strong) INSysTabbar *sysTabbar;
@property (nonatomic, assign) NSInteger selectedIndex;- (void)reset;@end
INSysTabbarViewController.m
#import "INSysTabbarViewController.h"
#import "UIViewController+SysTabbarItem.h"
#import "UIImage+Color.h"#define kTabScreenWidth [UIScreen mainScreen].bounds.size.width
#define kTabScreenHeight [UIScreen mainScreen].bounds.size.height#define K_TAB_DEFAULT_INDEX 0@interface INSysTabbarViewController ()<INSysTabbarDelegate>@property (nonatomic, strong, readwrite) UINavigationController *selectedNavigation;
@property (nonatomic, assign) float systemTabBarHeight;
@property (nonatomic, strong) NSArray *viewControllers;
@property (nonatomic, assign) BOOL isViewApeared;@end@implementation INSysTabbarViewController- (instancetype)init
{self = [super init];if (self) {self.isViewApeared = NO;UIEdgeInsets aSafeEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, 0.0, 0.0);if (@available(iOS 11.0, *)) {UIEdgeInsets safeInsets = [UIApplication sharedApplication].keyWindow.safeAreaInsets;aSafeEdgeInsets = safeInsets;} else {// Fallback on earlier versions}UITabBarController *systemTabbar = [[UITabBarController alloc] init];self.systemTabBarHeight = systemTabbar.tabBar.frame.size.height + aSafeEdgeInsets.bottom;self.sysTabbar = [[INSysTabbar alloc] initWithFrame:CGRectZero];self.sysTabbar.frame = CGRectMake(0.0, kTabScreenHeight - self.systemTabBarHeight, kTabScreenWidth, self.systemTabBarHeight);self.sysTabbar.tabDelegate = self;UIImage *bgImage = [UIImage imageWithColor:[UIColor colorWithWhite:1.0 alpha:1.0]];self.sysTabbar.bgroundImage = bgImage;}return self;
}- (void)viewDidLoad {[super viewDidLoad];// Do any additional setup after loading the view.self.view.exclusiveTouch = YES;// iOS 7.0 以上系统的处理self.automaticallyAdjustsScrollViewInsets = NO;self.extendedLayoutIncludesOpaqueBars = YES;self.edgesForExtendedLayout = UIRectEdgeAll;self.navigationController.navigationBar.translucent = NO;// 将tabbar放置到view上[self.view addSubview:self.sysTabbar];
}- (void)loadView {[super loadView];
}- (void)viewWillAppear:(BOOL)animated {[super viewWillAppear:animated];
}- (void)viewWillDisappear:(BOOL)animated {[super viewWillDisappear:animated];
}- (void)viewDidAppear:(BOOL)animated {[super viewDidAppear:animated];if (!self.isViewApeared) {[self.sysTabbar resetSysTabbar:K_TAB_DEFAULT_INDEX];self.isViewApeared = YES;}
}- (void)viewDidDisappear:(BOOL)animated {[super viewDidDisappear:animated];
}#pragma mark - SETTER
- (void)setTabViewControllers:(NSArray *)tabViewControllers {_tabViewControllers = tabViewControllers;NSMutableArray *tabbarItems = [NSMutableArray arrayWithCapacity:0];for (UIViewController *viewController in tabViewControllers) {INSysTabbarItem *item = nil;if ([viewController isKindOfClass:[UINavigationController class]]) {item = ((UIViewController *)((UINavigationController *)viewController).viewControllers.firstObject).sysTabBarItem;} else {item = viewController.sysTabBarItem;}[tabbarItems addObject:item];// 添加子Controller[self addChildViewController:viewController];}self.sysTabbar.dataSources = tabbarItems;self.viewControllers = tabViewControllers;
}#pragma mark - SDTabBarDelegate
- (void)tabBar:(INSysTabbar *)tabBar tabDidSelectedIndex:(NSInteger)index {self.selectedIndex = index;UIViewController *viewController = [self.viewControllers objectAtIndex:index];viewController.view.tag = index;viewController.view.frame = CGRectMake(0.0, 0.0, kTabScreenWidth, kTabScreenHeight);[self.view insertSubview:viewController.view belowSubview:self.sysTabbar];[self addChildViewController:viewController];
}#pragma mark - reset
- (void)reset {[self.viewControllers enumerateObjectsUsingBlock:^(__kindof UIViewController * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {if ([obj isKindOfClass:[UINavigationController class]]) {[(UINavigationController *)obj popToRootViewControllerAnimated:NO];}}];[self.sysTabbar setSelectedIndex:K_TAB_DEFAULT_INDEX];
}- (UINavigationController *)selectedNavigationController {UIViewController *viewController = [self.viewControllers objectAtIndex:self.selectedIndex];if (viewController.navigationController) {return viewController.navigationController;}return nil;
}#pragma mark - didReceiveMemoryWarning
- (void)didReceiveMemoryWarning {[super didReceiveMemoryWarning];// Dispose of any resources that can be recreated.
}@end
五、使用到的TabbarItem
TabbarItem定义显示的按钮icon,按钮标题,badge等
INSysTabbarItem.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>@interface INSysTabbarItem : NSObject@property (nonatomic, strong) NSString *identifier;
@property (nonatomic, strong) NSString *title;
@property (nonatomic, strong) UIFont *titleFont;
@property (nonatomic, strong) UIImage *image;
@property (nonatomic, strong) UIImage *selectedImage;
@property (nonatomic, strong) UIColor *titleColor;
@property (nonatomic, strong) UIColor *selectedTitleColor;
@property (nonatomic, strong) UIColor *badgeColor;
@property (nonatomic, strong) NSString *badge;
@property (nonatomic, assign) BOOL dotShown;/**赋值@param item item*/
- (void)copyClone:(INSysTabbarItem *)item;- (id)initWithTitle:(NSString *)titletitleFont:(UIFont *)titleFontimage:(UIImage *)imageselectedImage:(UIImage *)selectedImagetitleColor:(UIColor *)titleColorselectedTitleColor:(UIColor *)selectedTitleColorbadgeColor:(UIColor *)badgeColor;@end
INSysTabbarItem.m
#import “INSysTabbarItem.h”
@implementation INSysTabbarItem- (id)initWithTitle:(NSString *)titletitleFont:(UIFont *)titleFontimage:(UIImage *)imageselectedImage:(UIImage *)selectedImagetitleColor:(UIColor *)titleColorselectedTitleColor:(UIColor *)selectedTitleColorbadgeColor:(UIColor *)badgeColor {self = [super init];if (self) {self.title = title;self.titleFont = titleFont;self.image = image;self.selectedImage = selectedImage;self.titleColor = titleColor;self.selectedTitleColor = selectedTitleColor;self.badge = [[NSString alloc] init];self.dotShown = NO;self.badgeColor = badgeColor;}return self;
}/**赋值@param item item*/
- (void)copyClone:(INSysTabbarItem *)item {self.title = item.title;self.image = item.image;self.selectedImage = item.selectedImage;self.titleColor = item.titleColor;self.selectedTitleColor = item.selectedTitleColor;self.badgeColor = item.badgeColor;
}@end
六、为UIViewController添加扩展属性sysTabBarItem
UIViewController+SysTabbarItem.h
#import <UIKit/UIKit.h>
#import "INSysTabbarItem.h"@interface UIViewController (SysTabbarItem)@property (nonatomic, strong) INSysTabbarItem *sysTabBarItem;@end
UIViewController+SysTabbarItem.m
#import "UIViewController+SysTabbarItem.h"
#import <objc/runtime.h>static const void *sysTabBarItemKey = &sysTabBarItemKey;@implementation UIViewController (SysTabbarItem)- (INSysTabbarItem *)sysTabBarItem {return objc_getAssociatedObject(self, sysTabBarItemKey);
}- (void)setSysTabBarItem:(INSysTabbarItem *)sysTabBarItem {objc_setAssociatedObject(self, sysTabBarItemKey, sysTabBarItem, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}@end
七、小结
iOS开发-实现自定义Tabbar及tabbar按钮动画效果。
学习记录,每天不停进步。