iOS开发-实现自定义Tabbar及tabbar按钮动画效果

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按钮动画效果。

学习记录,每天不停进步。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/16388.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

qt源码--事件系统之QAbstractEventDispatcher

1、QAbstractEventDispatcher内容较少&#xff0c;其主要是定义了一些注册接口&#xff0c;如定时器事件、socket事件、注册本地事件、自定义事件等等。其源码如下&#xff1a; 其主要定义了大量的纯虚函数&#xff0c;具体的实现会根据不同的系统平台&#xff0c;实现对应的方…

软件测试员的非技术必备技能

成为软件测试人员所需的技能 非技术技能 以下技能对于成为优秀的软件测试人员至关重要。 将您的技能组合与以下清单进行比较&#xff0c;以确定软件测试是否适合您 - 分析技能&#xff1a;优秀的软件测试人员应具备敏锐的分析能力。 分析技能将有助于将复杂的软件系统分解为…

LeetCode每日一题Day1——买卖股票的最佳时机

✨博主&#xff1a;命运之光 &#x1f984;专栏&#xff1a;算法修炼之练气篇&#xff08;C\C版&#xff09; &#x1f353;专栏&#xff1a;算法修炼之筑基篇&#xff08;C\C版&#xff09; &#x1f433;专栏&#xff1a;算法修炼之练气篇&#xff08;Python版&#xff09; ✨…

Ribbon源码

学了feign源码之后感觉&#xff0c;这部分还是按运行流程分块学合适。核心组件什么的&#xff0c;当专业术语学妥了。序章&#xff1a;认识真正のRibbon 但只用认识一点点 之前我们学习Ribbon的简单使用时&#xff0c;都是集成了Eureka-client或者Feign等组件&#xff0c;甚至在…

开发一个RISC-V上的操作系统(五)—— 协作式多任务

目录 往期文章传送门 一、什么是多任务 二、代码实现 三、测试 往期文章传送门 开发一个RISC-V上的操作系统&#xff08;一&#xff09;—— 环境搭建_riscv开发环境_Patarw_Li的博客-CSDN博客 开发一个RISC-V上的操作系统&#xff08;二&#xff09;—— 系统引导程序&a…

Mac下certificate verify failed: unable to get local issuer certificate

出现这个问题&#xff0c;可以安装证书 在finder中查找 Install Certificates.command找到后双击&#xff0c;或者使用其他终端打开 安装完即可

【机器学习】Cost Function

Cost Function 1、计算 cost2、cost 函数的直观理解3、cost 可视化总结附录 首先&#xff0c;导入所需的库&#xff1a; import numpy as np %matplotlib widget import matplotlib.pyplot as plt from lab_utils_uni import plt_intuition, plt_stationary, plt_update_onclic…

【Github】自动监测 SSL 证书过期的轻量级监控方案 - Domain Admin

在现代的企业网络中&#xff0c;网站安全和可靠性是至关重要的。一个不注意的SSL证书过期可能导致网站出现问题&#xff0c;给公司业务带来严重的影响。针对这个问题&#xff0c;手动检测每个域名和机器的证书状态需要花费大量的时间和精力。为了解决这个问题&#xff0c;我想向…

【bar堆叠图形绘制】

绘制条形图示例 在数据可视化中&#xff0c;条形图是一种常用的图表类型&#xff0c;用于比较不同类别的数据值。Python的matplotlib库为我们提供了方便易用的功能来绘制条形图。 1. 基本条形图 首先&#xff0c;我们展示如何绘制基本的条形图。假设我们有一个包含十个类别的…

VS附加到进程调试

操作&#xff1a; 要附加到进程中调试外部可执行文件&#xff0c;您需要使用Visual Studio的“调试附加”功能。以下是附加到进程中调试外部可执行文件的步骤&#xff1a; 打开您要调试的源代码文件或可执行文件。打开Visual Studio。选择“调试”菜单&#xff0c;然后选择“…

轮趣科技教育版ros小车键盘控制运动

我之前买的ros小车是单独买的底板&#xff0c;以为随便一个树莓派就可以&#xff0c;因为我以前有一个树莓派3B&#xff0c;后来买了单独的小车之后&#xff0c;发现只能使用树莓派4B&#xff0c;然后又单独买了一个树莓派4B&#xff0c;给装上镜像&#xff0c;安装ros-melodic…

kotlin 编写一个简单的天气预报app(二)增加搜索城市功能

增加界面显示openweathermap返回的信息。 在activity_main.xml里增加输入框来输入城市&#xff0c;在输入款旁边增加搜索按钮来进行查询。 然后原来显示helloworld的TextView用来显示结果。 1. 增加输入城市名字的EditText <EditTextandroid:id"id/editTextCity"…

用于永磁同步电机驱动器的自适应SDRE非线性无传感器速度控制(MatlabSimulink实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f308;4 Matlab代码&Simulink仿真实现 &#x1f4a5;1 概述 本文方法基于状态依赖的里卡蒂方程&#xff08;SDRE&#xff09;控制技术及其梯度型神经网络的实时计算方法&#xff0c;允许…

理解构建LLM驱动的聊天机器人时的向量数据库检索的局限性 - (第1/3部分)

本博客是一系列文章中的第一篇&#xff0c;解释了为什么使用大型语言模型&#xff08;LLM&#xff09;部署专用领域聊天机器人的主流管道成本太高且效率低下。在第一篇文章中&#xff0c;我们将讨论为什么矢量数据库尽管最近流行起来&#xff0c;但在实际生产管道中部署时从根本…

使用Spring Boot AOP实现日志记录

目录 介绍 1.1 什么是AOP 1.2 AOP体系与概念 AOP简单实现 2.1 新建一个SpringBoot项目&#xff0c;无需选择依赖 2.2 设置好本地Maven配置后&#xff0c;在pom.xml文件里添加添加maven依赖 2.3 创建一个业务类接口 2.4 在实体类实现接口业务 2.5 在单元测试运行结果 …

IDEA Writing classes... 比较慢

IDEA配置修改如下&#xff1a; 1、File -> Settings… 2、Build&#xff0c;Execution&#xff0c;Deployment -> Compiler Build process heap size 配置为 20483、Build&#xff0c;Execution&#xff0c;Deployment -> Compiler -> ActionScript & Flex C…

vue基础-diff算法

vue基础-diff算法 1、根元素改变2、根元素不变 1、根元素改变 同级比较-根元素的变化-整个dom树删除重建 2、根元素不变 同级比较&#xff0c;根元素不变-属性改变更新属性

SpringBoot自动装配介绍

SpringBoot是对Spring的一种扩展&#xff0c;其中比较重要的扩展功能就是自动装配&#xff1a;通过注解对常用的配置做默认配置&#xff0c;简化xml配置内容。本文会对Spring的自动配置的原理和部分源码进行解析&#xff0c;本文主要参考了Spring的官方文档。 自动装配的组件 …

[每日习题]进制转换 参数解析——牛客习题

hello,大家好&#xff0c;这里是bang___bang_&#xff0c;本篇记录2道牛客习题&#xff0c;进制转换&#xff08;简单&#xff09;&#xff0c;参数解析&#xff08;中等&#xff09;&#xff0c;如有需要&#xff0c;希望能有所帮助&#xff01; 目录 1️⃣进制转换 2️⃣参…

python 自动化数据提取之正则表达式

>>>> 前 言 我们在做接口自动化的时候&#xff0c;处理接口依赖的相关数据时&#xff0c;通常会使用正则表达式来进行提取相关的数据&#xff0c;今天在这边和大家聊聊如何在python中使用正则表达式。 正则表达式&#xff0c;又称正规表示式、正规表示法、正规…