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;
//设置icon
self.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;
//设置badge
self.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 *)title
titleFont:(UIFont *)titleFont
image:(UIImage *)image
selectedImage:(UIImage *)selectedImage
titleColor:(UIColor *)titleColor
selectedTitleColor:(UIColor *)selectedTitleColor
badgeColor:(UIColor *)badgeColor;
@end
INSysTabbarItem.m
#import “INSysTabbarItem.h”
@implementation INSysTabbarItem
- (id)initWithTitle:(NSString *)title
titleFont:(UIFont *)titleFont
image:(UIImage *)image
selectedImage:(UIImage *)selectedImage
titleColor:(UIColor *)titleColor
selectedTitleColor:(UIColor *)selectedTitleColor
badgeColor:(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按钮动画效果。
学习记录,每天不停进步。