Repository: ChenYilong/CYLTabBarController Branch: master Commit: ea46eb68f712 Files: 156 Total size: 560.0 KB Directory structure: gitextract_oavmoe9b/ ├── .gitattributes ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── -en-bug-report--cn-bug---.md │ │ ├── -en-feature-request--cn---------.md │ │ └── qa----.md │ ├── issue_template.md │ └── pull_request_template.md ├── .gitignore ├── CHANGELOG.md ├── CYLTabBarController/ │ ├── CAAnimation+CYLBadgeExtention.h │ ├── CAAnimation+CYLBadgeExtention.m │ ├── CYLBadgeProtocol.h │ ├── CYLBaseNavigationController.h │ ├── CYLBaseNavigationController.m │ ├── CYLBaseTableViewController.h │ ├── CYLBaseTableViewController.m │ ├── CYLBaseViewController.h │ ├── CYLBaseViewController.m │ ├── CYLConstants.h │ ├── CYLPlusButton.h │ ├── CYLPlusButton.m │ ├── CYLTabBar+CYLTabBarControllerExtention.h │ ├── CYLTabBar+CYLTabBarControllerExtention.m │ ├── CYLTabBar.h │ ├── CYLTabBar.m │ ├── CYLTabBarController.h │ ├── CYLTabBarController.m │ ├── NSObject+CYLTabBarControllerExtention.h │ ├── NSObject+CYLTabBarControllerExtention.m │ ├── UIBarButtonItem+CYLBadgeExtention.h │ ├── UIBarButtonItem+CYLBadgeExtention.m │ ├── UIColor+CYLTabBarControllerExtention.h │ ├── UIColor+CYLTabBarControllerExtention.m │ ├── UIControl+CYLTabBarControllerExtention.h │ ├── UIControl+CYLTabBarControllerExtention.m │ ├── UIImage+CYLTabBarControllerExtention.h │ ├── UIImage+CYLTabBarControllerExtention.m │ ├── UITabBarItem+CYLBadgeExtention.h │ ├── UITabBarItem+CYLBadgeExtention.m │ ├── UITabBarItem+CYLTabBarControllerExtention.h │ ├── UITabBarItem+CYLTabBarControllerExtention.m │ ├── UIView+CYLBadgeExtention.h │ ├── UIView+CYLBadgeExtention.m │ ├── UIView+CYLTabBarControllerExtention.h │ ├── UIView+CYLTabBarControllerExtention.m │ ├── UIViewController+CYLNavigationControllerExtention.h │ ├── UIViewController+CYLNavigationControllerExtention.m │ ├── UIViewController+CYLTabBarControllerExtention.h │ └── UIViewController+CYLTabBarControllerExtention.m ├── CYLTabBarController.podspec ├── CYLTabBarController.xcodeproj/ │ ├── project.pbxproj │ └── xcshareddata/ │ └── xcschemes/ │ └── CYLTabBarController.xcscheme ├── CYLTabBarControllerTests/ │ ├── CYLTabBarControllerTests.m │ └── Info.plist ├── Example/ │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Base.lproj/ │ │ ├── LaunchScreen.xib │ │ └── Main.storyboard │ ├── CYLMainRootViewController.h │ ├── CYLMainRootViewController.m │ ├── Classes/ │ │ ├── Module/ │ │ │ ├── Home/ │ │ │ │ ├── CYLHomeViewController.h │ │ │ │ └── CYLHomeViewController.m │ │ │ ├── Message/ │ │ │ │ ├── CYLMessageViewController.h │ │ │ │ └── CYLMessageViewController.m │ │ │ ├── Mine/ │ │ │ │ ├── CYLMineViewController.h │ │ │ │ └── CYLMineViewController.m │ │ │ ├── Other/ │ │ │ │ ├── CYLPlusDemoChildViewController.h │ │ │ │ └── CYLPlusDemoChildViewController.m │ │ │ └── SameCity/ │ │ │ ├── CYLDetailsViewController.h │ │ │ ├── CYLDetailsViewController.m │ │ │ ├── CYLSameCityViewController.h │ │ │ └── CYLSameCityViewController.m │ │ ├── Other/ │ │ │ └── LottieResources/ │ │ │ ├── gray_tabbar_home_animation.json │ │ │ ├── gray_tabbar_me_animation.json │ │ │ ├── gray_tabbar_message_animation.json │ │ │ ├── green_lottie_tab_discover.json │ │ │ ├── green_lottie_tab_home.json │ │ │ ├── green_lottie_tab_mine.json │ │ │ ├── green_lottie_tab_news.json │ │ │ ├── tab_home_animate.json │ │ │ ├── tab_me_animate.json │ │ │ ├── tab_message_animate.json │ │ │ └── tab_search_animate.json │ │ └── View/ │ │ ├── CYLPlusButtonSubclass.h │ │ └── CYLPlusButtonSubclass.m │ ├── Images.xcassets/ │ │ ├── AppIcon.appiconset/ │ │ │ └── Contents.json │ │ ├── Contents.json │ │ ├── LaunchImage.launchimage/ │ │ │ └── Contents.json │ │ ├── NavBar/ │ │ │ ├── Contents.json │ │ │ ├── home_bar_scan.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── home_title_slogan.imageset/ │ │ │ │ └── Contents.json │ │ │ └── icon_search.imageset/ │ │ │ └── Contents.json │ │ ├── TabBarIcon/ │ │ │ ├── Contents.json │ │ │ ├── TabBar_Bg_Shadow.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── account/ │ │ │ │ ├── Contents.json │ │ │ │ ├── account_highlight.imageset/ │ │ │ │ │ └── Contents.json │ │ │ │ └── account_normal.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── fishpond/ │ │ │ │ ├── Contents.json │ │ │ │ ├── fishpond_highlight.imageset/ │ │ │ │ │ └── Contents.json │ │ │ │ └── fishpond_normal.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── home/ │ │ │ │ ├── Contents.json │ │ │ │ ├── home_highlight.imageset/ │ │ │ │ │ └── Contents.json │ │ │ │ └── home_normal.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── home_select_cover.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── lottie_placeholder/ │ │ │ │ ├── Contents.json │ │ │ │ ├── gray_tabbar_home_animation_lottie_placeholder.imageset/ │ │ │ │ │ └── Contents.json │ │ │ │ ├── gray_tabbar_me_animation_lottie_placeholder.imageset/ │ │ │ │ │ └── Contents.json │ │ │ │ └── gray_tabbar_message_animation_lottie_placeholder.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── message/ │ │ │ │ ├── Contents.json │ │ │ │ ├── message_highlight.imageset/ │ │ │ │ │ └── Contents.json │ │ │ │ └── message_normal.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── post/ │ │ │ │ ├── Contents.json │ │ │ │ ├── post_highlight.imageset/ │ │ │ │ │ └── Contents.json │ │ │ │ └── post_normal.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── tabbarBg.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── tabbar_background.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── tapbar_top_line.imageset/ │ │ │ │ └── Contents.json │ │ │ └── videoback.imageset/ │ │ │ └── Contents.json │ │ ├── home-float-icon.imageset/ │ │ │ └── Contents.json │ │ ├── icon_tabbar_plus.imageset/ │ │ │ └── Contents.json │ │ └── navigationbar_background_tall.imageset/ │ │ └── Contents.json │ ├── Info.plist │ ├── MainTabBarController.h │ ├── MainTabBarController.m │ └── main.m ├── Example-Swift/ │ ├── AppDelegate.swift │ ├── CYLTabbarController-Swift.xcodeproj/ │ │ └── project.pbxproj │ ├── MainTabBarController.swift │ ├── Module/ │ │ ├── Connection/ │ │ │ └── Controller/ │ │ │ └── ConnectionViewController.swift │ │ ├── Home/ │ │ │ └── Controller/ │ │ │ └── HomeViewController.swift │ │ ├── Message/ │ │ │ └── Controller/ │ │ │ └── MessageViewController.swift │ │ ├── Personal/ │ │ │ └── Controller/ │ │ │ └── PersonalViewController.swift │ │ └── Publish/ │ │ └── Controller/ │ │ └── PublishViewController.swift │ ├── Other/ │ │ ├── Assets.xcassets/ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ └── Contents.json │ │ │ ├── Contents.json │ │ │ ├── LaunchImage.launchimage/ │ │ │ │ └── Contents.json │ │ │ └── TabBarIcon/ │ │ │ ├── Contents.json │ │ │ ├── account_highlight.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── account_normal.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── home_highlight.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── home_normal.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── message_highlight.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── message_normal.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── mycity_highlight.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── mycity_normal.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── post_normal.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── tabbar_background.imageset/ │ │ │ │ └── Contents.json │ │ │ └── tapbar_top_line.imageset/ │ │ │ └── Contents.json │ │ ├── Base.lproj/ │ │ │ ├── LaunchScreen.storyboard │ │ │ └── Main.storyboard │ │ └── Info.plist │ ├── Podfile │ └── View/ │ └── CYLPlusButtonSubclass.swift ├── LICENSE ├── Podfile ├── README.md └── package.json ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitattributes ================================================ *.h linguist-detectable=false *.m linguist-detectable=false ================================================ FILE: .github/ISSUE_TEMPLATE/-en-bug-report--cn-bug---.md ================================================ --- name: "[EN]Bug report.[CN]bug反馈." about: Create a report to help us improve title: "[bug]:" labels: bug assignees: ChenYilong ---

--------------------------------------------

-------------------------------------------- ## Base Info for this issue 1. Version:Latest Version as [here](https://github.com/ChenYilong/CYLTabBarController/blob/master/CYLTabBarController.podspec) 2. Language of App :Objective-C/Swift 4. iOS System Version:iOS12 5. Prototype(是否是真机):YES 6. Issue Type:Crash、Bug、Enhancement(希望能支持一个新需求)、Q-A ## 1. How to reproduce the problem. ## 2. Please help me in this way. ## 3. Here is a Demo. ## 4. Here is my Debug log ----------

================================================ FILE: .github/ISSUE_TEMPLATE/-en-feature-request--cn---------.md ================================================ --- name: "[EN]Feature request.[CN]希望添加新功能." about: Suggest an idea for this project title: "[Feature request]希望添加新功能:" labels: enhancement assignees: ChenYilong ---

--------------------------------------------

-------------------------------------------- **Is your feature request related to a problem? Please describe.** **Describe the solution you'd like** **Describe alternatives you've considered** **Additional context** ================================================ FILE: .github/ISSUE_TEMPLATE/qa----.md ================================================ --- name: QA问题询问 about: 使用方法或者不确定是否为bug,可选用本模版 title: "[Q-A]使用方法询问:" labels: Q-A assignees: ChenYilong ---

--------------------------------------------

-------------------------------------------- ## My issue: ================================================ FILE: .github/issue_template.md ================================================ ![enter image description here](http://i68.tinypic.com/ifyhoo.jpg) ----------

---------- ## Base Info for this issue 1. Version:Latest Version as [here](https://github.com/ChenYilong/CYLTabBarController/blob/master/CYLTabBarController.podspec) 2. Language of App :Objective-C/Swift 4. iOS System Version:iOS12 5. Prototype(是否是真机):YES 6. Issue Type:Crash、Bug、Enhancement(希望能支持一个新需求)、Q-A ## 1. How to reproduce the problem. ## 2. Please help me in this way. ## 3. Here is a Demo. ## 4. Here is my Debug log ----------

================================================ FILE: .github/pull_request_template.md ================================================

--------------------------------------------

-------------------------------------------- ## My issue: ## What I have done: ================================================ FILE: .gitignore ================================================ .DS_Store CYLTabBarController.xcodeproj/project.xcworkspace/xcuserdata/chenyilong.xcuserdatad/UserInterfaceState.xcuserstate build/ *.pbxuser !default.pbxuser *.mode1v3 !default.mode1v3 *.mode2v3 !default.mode2v3 *.perspectivev3 !default.perspectivev3 !default.xcworkspace xcuserdata *.moved-aside *.mobileprovision DerivedData .idea/ Pods Podfile.lock *.xcworkspace CYLTabBarController.xcodeproj/xcuserdata/chenyilong.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist *.xcuserstate *.xcbkptlist *.xcuserstate *.xcbkptlist ================================================ FILE: CHANGELOG.md ================================================ ================================================ FILE: CYLTabBarController/CAAnimation+CYLBadgeExtention.h ================================================ /* //  CYLTabBarController //  CYLTabBarController // //  Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 03/06/19. //  Copyright © 2019 https://github.com/ChenYilong . All rights reserved. */ #import #import NS_ASSUME_NONNULL_BEGIN typedef NS_ENUM(NSUInteger, CYLAxis) { CYLAxisX = 0, CYLAxisY, CYLAxisZ }; // Degrees to radians #define CYL_DEGREES_TO_RADIANS(angle) ((angle) / 180.0 * M_PI) #define CYL_RADIANS_TO_DEGREES(radians) ((radians) * (180.0 / M_PI)) @interface CAAnimation (CYLBadgeExtention) /** * breathing forever * * @param time duritaion, from clear to fully seen * * @return animation obj */ + (CABasicAnimation *)cyl_opacityForever_Animation:(float)time; /** * breathing with fixed repeated times * * @param repeatTimes times * @param time duritaion, from clear to fully seen * * @return animation obj */ + (CABasicAnimation *)cyl_opacityTimes_Animation:(float)repeatTimes durTimes:(float)time; /** * //rotate * * @param dur duration * @param degree rotate degree in radian(弧度) * @param axis axis * @param repeatCount repeat count * * @return animation obj */ + (CABasicAnimation *)cyl_rotation:(float)dur degree:(float)degree direction:(CYLAxis)axis repeatCount:(int)repeatCount; /** * scale animation * * @param fromScale the original scale value, 1.0 by default * @param toScale target scale * @param time duration * @param repeatTimes repeat counts * * @return animaiton obj */ + (CABasicAnimation *)cyl_scaleFrom:(CGFloat)fromScale toScale:(CGFloat)toScale durTimes:(float)time rep:(float)repeatTimes; /** * shake * * @param repeatTimes time * @param time duration * @param obj always be CALayer at present * @return aniamtion obj */ + (CAKeyframeAnimation *)cyl_shake_AnimationRepeatTimes:(float)repeatTimes durTimes:(float)time forObj:(id)obj; /** * bounce * * @param repeatTimes time * @param time duration * @param obj always be CALayer at present * @return aniamtion obj */ + (CAKeyframeAnimation *)cyl_bounce_AnimationRepeatTimes:(float)repeatTimes durTimes:(float)time forObj:(id)obj; @end NS_ASSUME_NONNULL_END ================================================ FILE: CYLTabBarController/CAAnimation+CYLBadgeExtention.m ================================================ /* //  CYLTabBarController //  CYLTabBarController // //  Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 03/06/19. //  Copyright © 2019 https://github.com/ChenYilong . All rights reserved. */ #import "CAAnimation+CYLBadgeExtention.h" #import @implementation CAAnimation (CYLBadgeExtention) /** * breathing forever * * @param time duritaion, from clear to fully seen * * @return animation obj */ + (CABasicAnimation *)cyl_opacityForever_Animation:(float)time { CABasicAnimation *animation=[CABasicAnimation animationWithKeyPath:@"opacity"]; animation.fromValue=[NSNumber numberWithFloat:1.0]; animation.toValue=[NSNumber numberWithFloat:0.1]; animation.autoreverses=YES; animation.duration=time; animation.repeatCount=FLT_MAX; animation.removedOnCompletion=NO; animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; animation.fillMode=kCAFillModeForwards; return animation; } /** * breathing with fixed repeated times * * @param repeatTimes times * @param time duritaion, from clear to fully seen * * @return animation obj */ + (CABasicAnimation *)cyl_opacityTimes_Animation:(float)repeatTimes durTimes:(float)time { CABasicAnimation *animation=[CABasicAnimation animationWithKeyPath:@"opacity"]; animation.fromValue=[NSNumber numberWithFloat:1.0]; animation.toValue=[NSNumber numberWithFloat:0.4]; animation.repeatCount=repeatTimes; animation.duration=time; animation.removedOnCompletion=NO; animation.fillMode=kCAFillModeForwards; animation.timingFunction=[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]; animation.autoreverses=YES; return animation; } /** * //rotate * * @param dur duration * @param degree rotate degree in radian(弧度) * @param axis axis * @param repeatCount repeat count * * @return animation obj */ + (CABasicAnimation *)cyl_rotation:(float)dur degree:(float)degree direction:(CYLAxis)axis repeatCount:(int)repeatCount { CABasicAnimation* animation; NSArray *axisArr = @[@"transform.rotation.x", @"transform.rotation.y", @"transform.rotation.z"]; animation = [CABasicAnimation animationWithKeyPath:axisArr[axis]]; animation.fromValue = [NSNumber numberWithFloat:0]; animation.toValue= [NSNumber numberWithFloat:degree]; animation.duration= dur; animation.autoreverses= NO; animation.cumulative= YES; animation.removedOnCompletion=NO; animation.fillMode=kCAFillModeForwards; animation.repeatCount= repeatCount; return animation; } /** * scale animation * * @param fromScale the original scale value, 1.0 by default * @param toScale target scale * @param time duration * @param repeatTimes repeat counts * * @return animaiton obj */ + (CABasicAnimation *)cyl_scaleFrom:(CGFloat)fromScale toScale:(CGFloat)toScale durTimes:(float)time rep:(float)repeatTimes { CABasicAnimation *animation=[CABasicAnimation animationWithKeyPath:@"transform.scale"]; animation.fromValue = @(fromScale); animation.toValue = @(toScale); animation.duration = time; animation.autoreverses = YES; animation.repeatCount = repeatTimes; animation.removedOnCompletion = NO; animation.fillMode = kCAFillModeForwards; return animation; } /** * shake * * @param repeatTimes time * @param time duration * @param obj always be CALayer * @return aniamtion obj */ + (CAKeyframeAnimation *)cyl_shake_AnimationRepeatTimes:(float)repeatTimes durTimes:(float)time forObj:(id)obj { NSAssert([obj isKindOfClass:[CALayer class]] , @"invalid target"); CGPoint originPos = CGPointZero; CGSize originSize = CGSizeZero; if ([obj isKindOfClass:[CALayer class]]) { originPos = [(CALayer *)obj position]; originSize = [(CALayer *)obj bounds].size; } CGFloat hOffset = originSize.width / 4; CAKeyframeAnimation* anim=[CAKeyframeAnimation animation]; anim.keyPath=@"position"; anim.values=@[ [NSValue valueWithCGPoint:CGPointMake(originPos.x, originPos.y)], [NSValue valueWithCGPoint:CGPointMake(originPos.x-hOffset, originPos.y)], [NSValue valueWithCGPoint:CGPointMake(originPos.x, originPos.y)], [NSValue valueWithCGPoint:CGPointMake(originPos.x+hOffset, originPos.y)], [NSValue valueWithCGPoint:CGPointMake(originPos.x, originPos.y)] ]; anim.repeatCount = repeatTimes; anim.duration = time; anim.fillMode = kCAFillModeForwards; return anim; } /** * bounce * * @param repeatTimes time * @param time duration * @param obj always be CALayer * @return aniamtion obj */ + (CAKeyframeAnimation *)cyl_bounce_AnimationRepeatTimes:(float)repeatTimes durTimes:(float)time forObj:(id)obj { NSAssert([obj isKindOfClass:[CALayer class]] , @"invalid target"); CGPoint originPos = CGPointZero; CGSize originSize = CGSizeZero; if ([obj isKindOfClass:[CALayer class]]) { originPos = [(CALayer *)obj position]; originSize = [(CALayer *)obj bounds].size; } CGFloat hOffset = originSize.height / 4; CAKeyframeAnimation* anim=[CAKeyframeAnimation animation]; anim.keyPath=@"position"; anim.values=@[ [NSValue valueWithCGPoint:CGPointMake(originPos.x, originPos.y)], [NSValue valueWithCGPoint:CGPointMake(originPos.x, originPos.y-hOffset)], [NSValue valueWithCGPoint:CGPointMake(originPos.x, originPos.y)], [NSValue valueWithCGPoint:CGPointMake(originPos.x, originPos.y+hOffset)], [NSValue valueWithCGPoint:CGPointMake(originPos.x, originPos.y)] ]; anim.repeatCount=repeatTimes; anim.duration=time; anim.fillMode = kCAFillModeForwards; return anim; } @end ================================================ FILE: CYLTabBarController/CYLBadgeProtocol.h ================================================ /* //  CYLTabBarController //  CYLTabBarController // //  Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 03/06/19. //  Copyright © 2019 https://github.com/ChenYilong . All rights reserved. */ //CYLBadgeProtocol is a protocol which any Class supported (such UIView and UIBarButtonItem) should confirm //At present, there are two classes support CYLBadgeExtention(UIView and UIBarButtonItem). However, there may be more classes to support. Thus, it is necessary to abstract a protocol. 20150812. #ifndef CYLBadgeDemo_CYLBadgeProtocol_h #define CYLBadgeDemo_CYLBadgeProtocol_h #pragma mark -- types definition #define CYLBadgeBreatheAnimationKey @"breathe" #define CYLBadgeRotateAnimationKey @"rotate" #define CYLBadgeShakeAnimationKey @"shake" #define CYLBadgeScaleAnimationKey @"scale" #define CYLBadgeBounceAnimationKey @"bounce" typedef NS_ENUM(NSUInteger, CYLBadgeStyle) { CYLBadgeStyleRedDot = 1, /* red dot style */ CYLBadgeStyleNumber, /* badge with number */ CYLBadgeStyleNew, /* badge with a fixed text "new" */ CYLBadgeStyleOther /* badge with a fixed text */ }; typedef NS_ENUM(NSUInteger, CYLBadgeAnimationType) { CYLBadgeAnimationTypeNone = 0, /* without animation, badge stays still */ CYLBadgeAnimationTypeScale, /* scale effect */ CYLBadgeAnimationTypeShake, /* shaking effect */ CYLBadgeAnimationTypeBounce, /* bouncing effect */ CYLBadgeAnimationTypeBreathe /* breathing light effect, which makes badge more attractive */ }; #pragma mark -- protocol definition @protocol CYLBadgeProtocol @required @property (nonatomic, strong, getter=cyl_badge, setter=cyl_setBadge:) UILabel *cyl_badge; /* badge entity, which is adviced not to set manually */ @property (nonatomic, strong, getter=cyl_badgeFont, setter=cyl_setBadgeFont:) UIFont *cyl_badgeFont; /* [UIFont boldSystemFontOfSize:9] by default if not set */ @property (nonatomic, strong, getter=cyl_badgeBackgroundColor, setter=cyl_setBadgeBackgroundColor:) UIColor *cyl_badgeBackgroundColor; /* red color by default if not set */ @property (nonatomic, strong, getter=cyl_badgeTextColor, setter=cyl_setBadgeTextColor:) UIColor *cyl_badgeTextColor; /* white color by default if not set */ @property (nonatomic, assign, getter=cyl_badgeFrame, setter=cyl_setBadgeFrame:) CGRect cyl_badgeFrame; /* we have optimized the badge frame and center. This property is adviced not to set manually */ @property (nonatomic, assign, getter=cyl_badgeCenterOffset, setter=cyl_setBadgeCenterOffset:) CGPoint cyl_badgeCenterOffset; /* offset from right-top corner. {0,0} by default */ /* For x, negative number means left offset For y, negative number means bottom offset */ @property (nonatomic, assign, getter=cyl_badgeAnimationType, setter=cyl_setBadgeAnimationType:) CYLBadgeAnimationType cyl_badgeAnimationType;/* NOTE that this is not animation type of badge's // appearing, nor hidding*/ @property (nonatomic, assign, getter=cyl_badgeMaximumBadgeNumber, setter=cyl_setBadgeMaximumBadgeNumber:) NSInteger cyl_badgeMaximumBadgeNumber; /*for CYLBadgeStyleNumber style badge, if badge value is above badgeMaximumBadgeNumber, "badgeMaximumBadgeNumber+" will be printed. */ @property (nonatomic, assign, getter=cyl_badgeRadius, setter=cyl_setBadgeRadius:) CGFloat cyl_badgeRadius; @property (nonatomic, assign, getter=cyl_badgeMargin, setter=cyl_setBadgeMargin:) CGFloat cyl_badgeMargin; /**< // normal use for text and number style of badge */ @property (nonatomic, assign, getter=cyl_badgeCornerRadius, setter=cyl_setBadgeCornerRadius:) CGFloat cyl_badgeCornerRadius; - (BOOL)cyl_isShowBadge; /** * show badge with red dot style and CYLBadgeAnimationTypeNone by default. */ - (void)cyl_showBadge; /** * * @param value String value, default is `nil`. if value equal @"" means red dot style. * @param animationType animationType * @attention - 调用该方法前已经添加了系统的角标,调用该方法后,系统的角标并未被移除,只是被隐藏,调用 `-cyl_removeTabBadgePoint` 后会重新展示。 - 不支持 CYLPlusChildViewController 对应的 TabBarItem 角标设置,调用会被忽略。 */ - (void)cyl_showBadgeValue:(NSString *)value animationType:(CYLBadgeAnimationType)animationType; /** * clear badge(hide badge) */ - (void)cyl_clearBadge; /** * make bage(if existing) not hiden */ - (void)cyl_resumeBadge; - (BOOL)cyl_isPauseBadge; @end #endif ================================================ FILE: CYLTabBarController/CYLBaseNavigationController.h ================================================ /* //  CYLTabBarController //  CYLTabBarController // //  Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 03/06/19. //  Copyright © 2019 https://github.com/ChenYilong . All rights reserved. */ #import NS_ASSUME_NONNULL_BEGIN @interface CYLBaseNavigationController : UINavigationController @end NS_ASSUME_NONNULL_END ================================================ FILE: CYLTabBarController/CYLBaseNavigationController.m ================================================ /* //  CYLTabBarController //  CYLTabBarController // //  Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 03/06/19. //  Copyright © 2019 https://github.com/ChenYilong . All rights reserved. */ #import "CYLBaseNavigationController.h" @interface CYLBaseNavigationController () @end @implementation CYLBaseNavigationController - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated { // 当前导航栏, 只有第一个viewController push的时候设置隐藏 if (self.viewControllers.count == 1) { viewController.hidesBottomBarWhenPushed = YES; } else { viewController.hidesBottomBarWhenPushed = NO; } [super pushViewController:viewController animated:animated]; } //fix https://github.com/ChenYilong/CYLTabBarController/issues/483 - (void)setViewControllers:(NSArray *)viewControllers animated:(BOOL)animated { if (self.viewControllers.count > 1) { UIViewController *viewController = [self.viewControllers lastObject]; viewController.hidesBottomBarWhenPushed = YES; } [super setViewControllers:viewControllers animated:animated]; } @end ================================================ FILE: CYLTabBarController/CYLBaseTableViewController.h ================================================ /* //  CYLTabBarController //  CYLTabBarController // //  Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 03/06/19. //  Copyright © 2019 https://github.com/ChenYilong . All rights reserved. */ #import NS_ASSUME_NONNULL_BEGIN @interface CYLBaseTableViewController : UITableViewController @end NS_ASSUME_NONNULL_END ================================================ FILE: CYLTabBarController/CYLBaseTableViewController.m ================================================ /* //  CYLTabBarController //  CYLTabBarController // //  Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 03/06/19. //  Copyright © 2019 https://github.com/ChenYilong . All rights reserved. */ #import "CYLBaseTableViewController.h" #import "CYLTabBarController.h" @interface CYLBaseTableViewController () @end @implementation CYLBaseTableViewController #pragma mark - #pragma mark - UIViewController Life - (void)viewDidLoad { [super viewDidLoad]; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [self cyl_viewWillAppearNavigationSetting:animated]; } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; [self cyl_viewDidAppearNavigationSetting:animated]; } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; [self cyl_viewWillDisappearNavigationSetting:animated]; } - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; [self cyl_viewDidDisappearNavigationSetting:animated]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; } - (void)dealloc { [self cyl_deallocNavigationSetting]; } @end ================================================ FILE: CYLTabBarController/CYLBaseViewController.h ================================================ /* //  CYLTabBarController //  CYLTabBarController // //  Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 03/06/19. //  Copyright © 2019 https://github.com/ChenYilong . All rights reserved. */ #import NS_ASSUME_NONNULL_BEGIN @interface CYLBaseViewController : UIViewController @end NS_ASSUME_NONNULL_END ================================================ FILE: CYLTabBarController/CYLBaseViewController.m ================================================ /* //  CYLTabBarController //  CYLTabBarController // //  Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 03/06/19. //  Copyright © 2019 https://github.com/ChenYilong . All rights reserved. */ #import "CYLBaseViewController.h" #import "CYLTabBarController.h" @interface CYLBaseViewController () @end @implementation CYLBaseViewController #pragma mark - #pragma mark - UIViewController Life - (void)viewDidLoad { [super viewDidLoad]; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [self cyl_viewWillAppearNavigationSetting:animated]; } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; [self cyl_viewDidAppearNavigationSetting:animated]; } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; [self cyl_viewWillDisappearNavigationSetting:animated]; } - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; [self cyl_viewDidDisappearNavigationSetting:animated]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; } - (void)dealloc { [self cyl_deallocNavigationSetting]; } @end ================================================ FILE: CYLTabBarController/CYLConstants.h ================================================ // // CYLTabBarController.h // CYLTabBarController // // v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/20/15. // Copyright © 2018 https://github.com/ChenYilong . All rights reserved. // #ifndef CYLConstants_h #define CYLConstants_h #define CYL_DEPRECATED(explain) __attribute__((deprecated(explain))) #define CYL_IS_IPHONE (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) #define CYL_IS_IOS_11 ([[[UIDevice currentDevice] systemVersion] floatValue] >= 11.f) #define CYL_IS_IPHONE_X (CYL_IS_IOS_11 && CYL_IS_IPHONE && (MIN([UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height) >= 375 && MAX([UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height) >= 812)) #define CYL_SYSTEM_VERSION_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame) #define CYL_SYSTEM_VERSION_GREATER_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending) #define CYL_SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending) #define CYL_SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending) #define CYL_SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending) #endif /* CYLConstants_h */ ================================================ FILE: CYLTabBarController/CYLPlusButton.h ================================================ // // CYLPlusButton.h // CYLTabBarController // // v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/20/15. // Copyright © 2018 https://github.com/ChenYilong . All rights reserved. // #import #import "CYLConstants.h" NS_ASSUME_NONNULL_BEGIN @class CYLPlusButton; @protocol CYLPlusButtonSubclassing @required + (id)plusButton; @optional /*! * 用来自定义加号按钮的位置,如果不实现默认居中。 * @attention 以下两种情况下,必须实现该协议方法,否则 CYLTabBarController 会抛出 exception 来进行提示: 1. 添加了 PlusButton 且 TabBarItem 的个数是奇数。 2. 实现了 `+plusChildViewController`。 * @return 用来自定义加号按钮在 TabBar 中的位置。 * */ + (NSUInteger)indexOfPlusButtonInTabBar; /*! * 该方法是为了调整 PlusButton 中心点Y轴方向的位置,建议在按钮超出了 tabbar 的边界时实现该方法。 * @attention 如果不实现该方法,内部会自动进行比对,预设一个较为合适的位置,如果实现了该方法,预设的逻辑将失效。 * @return 返回值是自定义按钮中心点Y轴方向的坐标除以 tabbar 的高度, 内部实现时,会使用该返回值来设置 PlusButton 的 centerY 坐标,公式如下: `PlusButtonCenterY = multiplierOfTabBarHeight * tabBarHeight + constantOfPlusButtonCenterYOffset;` 也就是说:如果 constantOfPlusButtonCenterYOffset 为0,同时 multiplierOfTabBarHeight 的值是0.5,表示 PlusButton 居中,小于0.5表示 PlusButton 偏上,大于0.5则表示偏下。 * */ + (CGFloat)multiplierOfTabBarHeight:(CGFloat)tabBarHeight; /*! * 见 `+multiplierOfTabBarHeight:` 注释: * `PlusButtonCenterY = multiplierOfTabBarHeight * tabBarHeight + constantOfPlusButtonCenterYOffset;` * 也就是说: constantOfPlusButtonCenterYOffset 大于0会向下偏移,小于0会向上偏移。 * @attention 实现了该方法,但没有实现 `+multiplierOfTabBarHeight:` 方法,在这种情况下,会在预设逻辑的基础上进行偏移。 */ + (CGFloat)constantOfPlusButtonCenterYOffsetForTabBarHeight:(CGFloat)tabBarHeight; /*! * 实现该方法后,能让 PlusButton 的点击效果与跟点击其他 TabBar 按钮效果一样,跳转到该方法指定的 UIViewController 。 * @attention 必须同时实现 `+indexOfPlusButtonInTabBar` 来指定 PlusButton 的位置。 * @return 指定 PlusButton 点击后跳转的 UIViewController。 * */ + (UIViewController *)plusChildViewController; /*! * Asks the delegate whether the specified view controller should be made active. Return YES if the view controller’s tab should be selected or NO if the current tab should remain active. Returns YES true if the view controller’s tab should be selected or NO false if the current tab should remain active. */ + (BOOL)shouldSelectPlusChildViewController; #pragma mark - Deprecated API + (CGFloat)multiplerInCenterY CYL_DEPRECATED("Deprecated in 1.6.0. Use `+multiplierOfTabBarHeight:` instead."); + (NSString *)tabBarContext; @end @class CYLTabBar; FOUNDATION_EXTERN UIButton *CYLExternPlusButton; FOUNDATION_EXTERN UIViewController *CYLPlusChildViewController; @interface CYLPlusButton : UIButton + (void)registerPlusButton; + (void)removePlusButton; - (void)plusChildViewControllerButtonClicked:(UIButton *)sender; @end #pragma mark - Deprecated API @interface CYLPlusButton (CYLPlusButtonDeprecated) + (void)registerSubclass CYL_DEPRECATED("Deprecated in 1.6.0. Use `+[CYLPlusButton registerPlusButton]` instead."); @end NS_ASSUME_NONNULL_END ================================================ FILE: CYLTabBarController/CYLPlusButton.m ================================================ // // CYLPlusButton.m // CYLTabBarController // // v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/20/15. // Copyright © 2018 https://github.com/ChenYilong . All rights reserved. // #import "CYLPlusButton.h" #import "CYLTabBarController.h" #import "UIViewController+CYLTabBarControllerExtention.h" CGFloat CYLPlusButtonWidth = 0.0f; UIButton *CYLExternPlusButton = nil; UIViewController *CYLPlusChildViewController = nil; @implementation CYLPlusButton #pragma mark - #pragma mark - public Methods + (void)registerPlusButton { if (![self conformsToProtocol:@protocol(CYLPlusButtonSubclassing)]) { return; } Class class = self; UIButton *plusButton = [class plusButton]; CYLExternPlusButton = plusButton; CYLPlusButtonWidth = plusButton.frame.size.width; if ([[self class] respondsToSelector:@selector(plusChildViewController)]) { CYLPlusChildViewController = [class plusChildViewController]; if ([[self class] respondsToSelector:@selector(tabBarContext)]) { NSString *tabBarContext = [class tabBarContext]; if (tabBarContext && tabBarContext.length) { [CYLPlusChildViewController cyl_setContext:tabBarContext]; } } else { [CYLPlusChildViewController cyl_setContext:NSStringFromClass([CYLTabBarController class])]; } [[self class] addSelectViewControllerTarget:plusButton]; if ([[self class] respondsToSelector:@selector(indexOfPlusButtonInTabBar)]) { CYLPlusButtonIndex = [[self class] indexOfPlusButtonInTabBar]; } else { [NSException raise:NSStringFromClass([CYLTabBarController class]) format:@"If you want to add PlusChildViewController, you must realizse `+indexOfPlusButtonInTabBar` in your custom plusButton class.【Chinese】如果你想使用PlusChildViewController样式,你必须同时在你自定义的plusButton中实现 `+indexOfPlusButtonInTabBar`,来指定plusButton的位置"]; } } } + (void)removePlusButton { CYLExternPlusButton = nil; [CYLPlusChildViewController cyl_setPlusViewControllerEverAdded:NO]; CYLPlusChildViewController = nil; } + (void)registerSubclass { [self registerPlusButton]; } - (void)plusChildViewControllerButtonClicked:(UIButton *)sender { BOOL notNeedConfigureSelectionStatus = [[self class] respondsToSelector:@selector(shouldSelectPlusChildViewController)] && ![[self class] shouldSelectPlusChildViewController]; if (notNeedConfigureSelectionStatus) { return; } CYLTabBarController *tabBarController = [sender cyl_tabBarController]; NSInteger index = [tabBarController.viewControllers indexOfObject:CYLPlusChildViewController]; if (NSNotFound != index && (index < tabBarController.viewControllers.count)) { [tabBarController setSelectedIndex:index]; } } #pragma mark - #pragma mark - Private Methods + (void)addSelectViewControllerTarget:(UIButton *)plusButton { id target = self; NSArray *selectorNamesArray = [plusButton actionsForTarget:target forControlEvent:UIControlEventTouchUpInside]; if (selectorNamesArray.count == 0) { target = plusButton; selectorNamesArray = [plusButton actionsForTarget:target forControlEvent:UIControlEventTouchUpInside]; } [selectorNamesArray enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { SEL selector = NSSelectorFromString(obj); [plusButton removeTarget:target action:selector forControlEvents:UIControlEventTouchUpInside]; }]; [plusButton addTarget:plusButton action:@selector(plusChildViewControllerButtonClicked:) forControlEvents:UIControlEventTouchUpInside]; } /** * 按钮选中状态下点击先显示normal状态的颜色,松开时再回到selected状态下颜色。 * 重写此方法即不会出现上述情况,与 UITabBarButton 相似 */ - (void)setHighlighted:(BOOL)highlighted {} @end ================================================ FILE: CYLTabBarController/CYLTabBar+CYLTabBarControllerExtention.h ================================================ /* //  CYLTabBarController //  CYLTabBarController // //  Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 03/06/19. //  Copyright © 2019 https://github.com/ChenYilong . All rights reserved. */ #import #import "CYLTabBar.h" NS_ASSUME_NONNULL_BEGIN @interface CYLTabBar (CYLTabBarControllerExtention) - (NSArray *)cyl_visibleControls; - (NSArray *)cyl_subTabBarButtons; - (NSArray *)cyl_subTabBarButtonsWithoutPlusButton; - (UIControl *)cyl_tabBarButtonWithTabIndex:(NSUInteger)tabIndex; - (void)cyl_animationLottieImageWithSelectedControl:(UIControl *)selectedControl lottieURL:(NSURL *)lottieURL size:(CGSize)size defaultSelected:(BOOL)defaultSelected; - (void)cyl_stopAnimationOfAllLottieView; - (NSArray *)cyl_originalTabBarButtons; - (BOOL)cyl_hasPlusChildViewController; @end NS_ASSUME_NONNULL_END ================================================ FILE: CYLTabBarController/CYLTabBar+CYLTabBarControllerExtention.m ================================================ /* //  CYLTabBarController //  CYLTabBarController // //  Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 03/06/19. //  Copyright © 2019 https://github.com/ChenYilong . All rights reserved. */ #import "CYLTabBar+CYLTabBarControllerExtention.h" #import "UIView+CYLTabBarControllerExtention.h" #import "UIControl+CYLTabBarControllerExtention.h" #import "CYLTabBarController.h" #import #import "CYLTabBar.h" #if __has_include() #import #else #endif @implementation CYLTabBar (CYLTabBarControllerExtention) - (BOOL)cyl_hasPlusChildViewController { NSString *context = CYLPlusChildViewController.cyl_context; BOOL isSameContext = [context isEqualToString:self.context] && (context && (context.length > 0) && self.context && self.context.length > 0); BOOL isAdded = [[self cyl_tabBarController].viewControllers containsObject:CYLPlusChildViewController]; BOOL isEverAdded = CYLPlusChildViewController.cyl_plusViewControllerEverAdded; if (CYLPlusChildViewController && isSameContext && isAdded && isEverAdded) { return YES; } return NO; } - (NSArray *)cyl_originalTabBarButtons { NSArray *tabBarButtons = [self cyl_tabBarButtonFromTabBarSubviews:[self cyl_sortedSubviews]]; return tabBarButtons; } - (NSArray *)cyl_sortedSubviews { if (self.subviews.count == 0) { return self.subviews; } NSMutableArray *tabBarButtonArray = [NSMutableArray arrayWithCapacity:self.subviews.count]; [self.subviews enumerateObjectsUsingBlock:^(__kindof UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { if ([obj cyl_isTabButton]) { [tabBarButtonArray addObject:obj]; } }]; NSArray *sortedSubviews = [[tabBarButtonArray copy] sortedArrayUsingComparator:^NSComparisonResult(UIView * formerView, UIView * latterView) { CGFloat formerViewX = formerView.frame.origin.x; CGFloat latterViewX = latterView.frame.origin.x; return (formerViewX > latterViewX) ? NSOrderedDescending : NSOrderedAscending; }]; return sortedSubviews; } - (NSArray *)cyl_tabBarButtonFromTabBarSubviews:(NSArray *)tabBarSubviews { if (tabBarSubviews.count == 0) { return tabBarSubviews; } NSMutableArray *tabBarButtonMutableArray = [NSMutableArray arrayWithCapacity:tabBarSubviews.count]; [tabBarSubviews enumerateObjectsUsingBlock:^(UIControl * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { if ([obj cyl_isTabButton]) { [tabBarButtonMutableArray addObject:obj]; [obj cyl_setTabBarChildViewControllerIndex:idx]; } }]; if ([self cyl_hasPlusChildViewController]) { @try { UIControl *control = tabBarButtonMutableArray[CYLPlusButtonIndex]; control.userInteractionEnabled = NO; control.hidden = YES; } @catch (NSException *exception) {} } return [tabBarButtonMutableArray copy]; } - (NSArray *)cyl_visibleControls { NSMutableArray *originalTabBarButtons = [NSMutableArray arrayWithArray:[self.cyl_originalTabBarButtons copy]]; BOOL notAdded = (NSNotFound == [originalTabBarButtons indexOfObject:CYLExternPlusButton]); if (CYLExternPlusButton && notAdded) { [originalTabBarButtons addObject:CYLExternPlusButton]; } if (originalTabBarButtons.count == 0) { return nil; } NSMutableArray *tabBarButtonArray = [NSMutableArray arrayWithCapacity:originalTabBarButtons.count]; [originalTabBarButtons enumerateObjectsUsingBlock:^(__kindof UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { CGFloat width = obj.frame.size.width; BOOL isInvisiable = obj.cyl_canNotResponseEvent; BOOL isNotSubView = (width < 10); BOOL canNotResponseEvent = isInvisiable || isNotSubView ; if (canNotResponseEvent) { return; } if (([obj cyl_isTabButton] || [obj cyl_isPlusButton] ) ) { [tabBarButtonArray addObject:obj]; } }]; NSArray *sortedSubviews = [[tabBarButtonArray copy] sortedArrayUsingComparator:^NSComparisonResult(UIView * formerView, UIView * latterView) { CGFloat formerViewX = formerView.frame.origin.x; CGFloat latterViewX = latterView.frame.origin.x; return (formerViewX > latterViewX) ? NSOrderedDescending : NSOrderedAscending; }]; return sortedSubviews; } - (NSArray *)cyl_subTabBarButtons { NSMutableArray *subControls = [NSMutableArray arrayWithCapacity:self.cyl_visibleControls.count]; [self.cyl_visibleControls enumerateObjectsUsingBlock:^(UIControl * _Nonnull control, NSUInteger idx, BOOL * _Nonnull stop) { if ([control cyl_isPlusButton] && !CYLPlusChildViewController.cyl_plusViewControllerEverAdded) { return; } [subControls addObject:control]; }]; return subControls; } - (NSArray *)cyl_subTabBarButtonsWithoutPlusButton { NSMutableArray *subControls = [NSMutableArray arrayWithCapacity:self.cyl_visibleControls.count]; [self.cyl_visibleControls enumerateObjectsUsingBlock:^(UIControl * _Nonnull control, NSUInteger idx, BOOL * _Nonnull stop) { if ([control cyl_isPlusButton]) { return; } [subControls addObject:control]; }]; return subControls; } - (UIControl *)cyl_tabBarButtonWithTabIndex:(NSUInteger)tabIndex { UIControl *selectedControl = [self cyl_visibleControlWithIndex:tabIndex]; NSInteger plusViewControllerIndex = [self.cyl_tabBarController.viewControllers indexOfObject:CYLPlusChildViewController]; BOOL isPlusViewControllerAdded = CYLPlusChildViewController.cyl_plusViewControllerEverAdded && (plusViewControllerIndex != NSNotFound); if (isPlusViewControllerAdded) { return selectedControl; } @try { selectedControl = [self cyl_subTabBarButtonsWithoutPlusButton][tabIndex]; } @catch (NSException *exception) { NSLog(@"🔴类名与方法名:%@(在第%@行),描述:%@", @(__PRETTY_FUNCTION__), @(__LINE__), exception.reason); } return selectedControl; } - (UIControl *)cyl_visibleControlWithIndex:(NSUInteger)index { UIControl *selectedControl; @try { NSArray *subControls = self.cyl_visibleControls; selectedControl = subControls[index]; } @catch (NSException *exception) { NSLog(@"🔴类名与方法名:%@(在第%@行),描述:%@", @(__PRETTY_FUNCTION__), @(__LINE__), exception.reason); } return selectedControl; } - (void)cyl_animationLottieImageWithSelectedControl:(UIControl *)selectedControl lottieURL:(NSURL *)lottieURL size:(CGSize)size defaultSelected:(BOOL)defaultSelected { #if __has_include() [selectedControl cyl_addLottieImageWithLottieURL:lottieURL size:size]; [self cyl_stopAnimationOfAllLottieView]; LOTAnimationView *lottieView = selectedControl.cyl_lottieAnimationView; if (!lottieView) { [selectedControl cyl_addLottieImageWithLottieURL:lottieURL size:size]; } if (lottieView && [lottieView isKindOfClass:[LOTAnimationView class]]) { if (defaultSelected) { lottieView.animationProgress = 1; [lottieView forceDrawingUpdate]; return; } lottieView.animationProgress = 0; [lottieView play]; } #else #endif } - (void)cyl_stopAnimationOfAllLottieView { #if __has_include() [self.cyl_visibleControls enumerateObjectsUsingBlock:^(UIControl * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { [obj.cyl_lottieAnimationView stop]; }]; #else #endif } @end ================================================ FILE: CYLTabBarController/CYLTabBar.h ================================================ // // CYLTabBar.h // CYLTabBarController // // v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/20/15. // Copyright © 2018 https://github.com/ChenYilong . All rights reserved. // #import NS_ASSUME_NONNULL_BEGIN @interface CYLTabBar : UITabBar /*! * 让 `TabImageView` 垂直居中时,所需要的默认偏移量。 * @attention 该值将在设置 top 和 bottom 时被同时使用,具体的操作等价于如下行为: * `viewController.tabBarItem.imageInsets = UIEdgeInsetsMake(tabImageViewDefaultOffset, 0, -tabImageViewDefaultOffset, 0);` */ @property (nonatomic, assign, readonly) CGFloat tabImageViewDefaultOffset; @property (nonatomic, copy) NSString *context; @end NS_ASSUME_NONNULL_END ================================================ FILE: CYLTabBarController/CYLTabBar.m ================================================ // // CYLTabBar.m // CYLTabBarController // // v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/20/15. // Copyright © 2018 https://github.com/ChenYilong . All rights reserved. // #import "CYLTabBar.h" #import "CYLPlusButton.h" #import "CYLTabBarController.h" #import "CYLConstants.h" #import #import "UIControl+CYLTabBarControllerExtention.h" #import "CYLTabBar+CYLTabBarControllerExtention.h" static void *const CYLTabBarContext = (void*)&CYLTabBarContext; @interface CYLTabBar () /** 发布按钮 */ @property (nonatomic, strong) UIButton *plusButton; @property (nonatomic, assign) CGFloat tabBarItemWidth; @property (nonatomic, copy) NSArray *tabBarButtonArray; @property (nonatomic, assign, getter=hasAddPlusButton) BOOL addPlusButton; @end @implementation CYLTabBar @synthesize plusButton = _plusButton; #pragma mark - #pragma mark - LifeCycle Method - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { self = [self sharedInit]; } return self; } - (instancetype)initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; if (self) { self = [self sharedInit]; } return self; } - (void)setPlusButton:(UIButton *)plusButton { if (!plusButton) { return; } _plusButton = plusButton; if (!self.hasAddPlusButton) { NSString *tabBarContext = self.plusButtonTabBarContext; BOOL isFirstAdded = (_plusButton.superview == nil); BOOL isSameContext = [tabBarContext isEqualToString:self.context] && (tabBarContext && self.context); if (_plusButton && isSameContext && isFirstAdded) { [self addSubview:(UIButton *)_plusButton]; self.addPlusButton = YES; [_plusButton cyl_setTabBarController:[self cyl_tabBarController]]; } } } - (void)setContext:(NSString *)context { _context = context; self.plusButton = CYLExternPlusButton; } - (instancetype)sharedInit { // KVO注册监听 _tabBarItemWidth = CYLTabBarItemWidth; [self addObserver:self forKeyPath:@"tabBarItemWidth" options:NSKeyValueObservingOptionNew context:CYLTabBarContext]; return self; } - (CGSize)sizeThatFits:(CGSize)size { CGSize sizeThatFits = [super sizeThatFits:size]; CGFloat height = [self cyl_tabBarController].tabBarHeight; if (height > 0) { sizeThatFits.height = height; } return sizeThatFits; } /** * lazy load tabBarButtonArray * * @return NSArray */ - (NSArray *)tabBarButtonArray { if (_tabBarButtonArray == nil) { _tabBarButtonArray = @[]; } return _tabBarButtonArray; } - (NSString *)plusButtonTabBarContext { NSString *tabBarContext; if ([[_plusButton class] respondsToSelector:@selector(tabBarContext)]) { tabBarContext = [[_plusButton class] tabBarContext]; } if (tabBarContext && tabBarContext.length > 0) { return tabBarContext; } tabBarContext = NSStringFromClass([CYLTabBarController class]); return tabBarContext; } - (UIButton *)plusButton { if (!CYLExternPlusButton || !_plusButton) { return nil; } NSString *plusButtonTabBarContext = self.plusButtonTabBarContext; BOOL addedToTabBar = [_plusButton.superview isEqual:self]; BOOL isSameContext = [plusButtonTabBarContext isEqualToString:self.context] && (plusButtonTabBarContext && self.context);//|| (!tabBarContext && !self.context); if (_plusButton && addedToTabBar && isSameContext) { return _plusButton; } return nil; } - (void)presetUnselectedItemTintColor { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 if (@available(iOS 13.0, *)) { if (self.unselectedItemTintColor) { return; } __block UIColor *tabLabelTextColor = nil;//for iOS13+ tabLabelTextColor = [UIColor cyl_systemGrayColor]; [self.tabBarButtonArray enumerateObjectsUsingBlock:^(UIControl * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { UIControl *childView = obj; if (childView.selected) { return; } if (childView.cyl_tabEffectView && childView.cyl_tabLabel ) { tabLabelTextColor = childView.cyl_tabLabel.textColor; } }]; self.unselectedItemTintColor = tabLabelTextColor; } #endif } - (void)layoutSubviews { [super layoutSubviews]; self.tabBarButtonArray = [self cyl_originalTabBarButtons]; if (self.tabBarButtonArray.count == 0) { return; } [self presetUnselectedItemTintColor]; [self setupTabImageViewDefaultOffset:self.tabBarButtonArray[0]]; CGFloat tabBarWidth = self.bounds.size.width; CGFloat tabBarHeight = self.bounds.size.height; if (!self.addPlusButton) { return; } BOOL addedToTabBar = [_plusButton.superview isEqual:self]; if (!addedToTabBar) { CYLTabBarItemWidth = (tabBarWidth) / CYLTabbarItemsCount; [self.tabBarButtonArray enumerateObjectsUsingBlock:^(UIControl * _Nonnull childView, NSUInteger buttonIndex, BOOL * _Nonnull stop) { //仅修改childView的x和宽度,yh值不变 CGFloat childViewX = buttonIndex * CYLTabBarItemWidth; [self changeXForChildView:childView childViewX:childViewX tabBarItemWidth:CYLTabBarItemWidth index:buttonIndex ]; }]; return; } CYLTabBarItemWidth = (tabBarWidth - CYLPlusButtonWidth) / CYLTabbarItemsCount; CGFloat multiplierOfTabBarHeight = [self multiplierOfTabBarHeight:tabBarHeight]; CGFloat constantOfPlusButtonCenterYOffset = [self constantOfPlusButtonCenterYOffsetForTabBarHeight:tabBarHeight]; _plusButton.center = CGPointMake(tabBarWidth * 0.5, tabBarHeight * multiplierOfTabBarHeight + constantOfPlusButtonCenterYOffset); NSUInteger plusButtonIndex = [self plusButtonIndex]; [self.tabBarButtonArray enumerateObjectsUsingBlock:^(UIControl * _Nonnull childView, NSUInteger buttonIndex, BOOL * _Nonnull stop) { //调整UITabBarItem的位置 CGFloat childViewX; CGFloat visiableTabIndex = buttonIndex; CGFloat tabBarItemWidth = CYLTabBarItemWidth; if ([self cyl_hasPlusChildViewController]) { if (buttonIndex <= plusButtonIndex) { childViewX = buttonIndex * CYLTabBarItemWidth; } else { childViewX = (buttonIndex - 1) * CYLTabBarItemWidth + CYLPlusButtonWidth; } if (buttonIndex == plusButtonIndex) { tabBarItemWidth = CYLPlusButtonWidth; } } else { if (buttonIndex >= plusButtonIndex) { childViewX = buttonIndex * CYLTabBarItemWidth + CYLPlusButtonWidth; visiableTabIndex = buttonIndex + 1; } else { childViewX = buttonIndex * CYLTabBarItemWidth; } } [childView cyl_setTabBarChildViewControllerIndex:buttonIndex]; [self changeXForChildView:childView childViewX:childViewX tabBarItemWidth:tabBarItemWidth index:visiableTabIndex ]; //仅修改childView的x和宽度,yh值不变 }]; //bring the plus button to top [self bringSubviewToFront:_plusButton]; } - (void)changeXForChildView:(UIControl *)childView childViewX:(CGFloat)childViewX tabBarItemWidth:(CGFloat)tabBarItemWidth index:(NSUInteger)index { //仅修改childView的x和宽度,yh值不变 childView.frame = CGRectMake(childViewX, CGRectGetMinY(childView.frame), tabBarItemWidth, CGRectGetHeight(childView.frame) ); [childView cyl_setTabBarItemVisibleIndex:index]; } #pragma mark - #pragma mark - Private Methods + (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key { return NO; } // KVO监听执行 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if(context != CYLTabBarContext) { [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; return; } if(context == CYLTabBarContext) { [[NSNotificationCenter defaultCenter] postNotificationName:CYLTabBarItemWidthDidChangeNotification object:self]; if (CYL_IS_IPHONE_X) { [self layoutIfNeeded]; } } } - (void)dealloc { // KVO反注册 [self removeObserver:self forKeyPath:@"tabBarItemWidth"]; } - (void)setTabBarItemWidth:(CGFloat )tabBarItemWidth { if (_tabBarItemWidth != tabBarItemWidth) { [self willChangeValueForKey:@"tabBarItemWidth"]; _tabBarItemWidth = tabBarItemWidth; [self didChangeValueForKey:@"tabBarItemWidth"]; } } - (void)setTabImageViewDefaultOffset:(CGFloat)tabImageViewDefaultOffset { if (tabImageViewDefaultOffset != 0.f) { [self willChangeValueForKey:@"tabImageViewDefaultOffset"]; _tabImageViewDefaultOffset = tabImageViewDefaultOffset; [self didChangeValueForKey:@"tabImageViewDefaultOffset"]; } } - (CGFloat)multiplierOfTabBarHeight:(CGFloat)tabBarHeight { CGFloat multiplierOfTabBarHeight; if ([[self.plusButton class] respondsToSelector:@selector(multiplierOfTabBarHeight:)]) { multiplierOfTabBarHeight = [[self.plusButton class] multiplierOfTabBarHeight:tabBarHeight]; } #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" else if ([[self.plusButton class] respondsToSelector:@selector(multiplerInCenterY)]) { multiplierOfTabBarHeight = [[self.plusButton class] multiplerInCenterY]; } #pragma clang diagnostic pop else { CGSize sizeOfPlusButton = self.plusButton.frame.size; CGFloat heightDifference = sizeOfPlusButton.height - self.bounds.size.height; if (heightDifference < 0) { multiplierOfTabBarHeight = 0.5; } else { CGPoint center = CGPointMake(self.bounds.size.height * 0.5, self.bounds.size.height * 0.5); center.y = center.y - heightDifference * 0.5; multiplierOfTabBarHeight = center.y / self.bounds.size.height; } } return multiplierOfTabBarHeight; } - (CGFloat)constantOfPlusButtonCenterYOffsetForTabBarHeight:(CGFloat)tabBarHeight { CGFloat constantOfPlusButtonCenterYOffset = 0.f; if ([[self.plusButton class] respondsToSelector:@selector(constantOfPlusButtonCenterYOffsetForTabBarHeight:)]) { constantOfPlusButtonCenterYOffset = [[self.plusButton class] constantOfPlusButtonCenterYOffsetForTabBarHeight:tabBarHeight]; } return constantOfPlusButtonCenterYOffset; } - (NSUInteger)plusButtonIndex { NSUInteger plusButtonIndex; if ([[self.plusButton class] respondsToSelector:@selector(indexOfPlusButtonInTabBar)]) { plusButtonIndex = [[self.plusButton class] indexOfPlusButtonInTabBar]; } else { if (CYLTabbarItemsCount % 2 != 0) { [NSException raise:NSStringFromClass([CYLTabBarController class]) format:@"If the count of CYLTabbarControllers is odd,you must realizse `+indexOfPlusButtonInTabBar` in your custom plusButton class.【Chinese】如果CYLTabbarControllers的个数是奇数,你必须在你自定义的plusButton中实现`+indexOfPlusButtonInTabBar`,来指定plusButton的位置"]; } plusButtonIndex = CYLTabbarItemsCount * 0.5; } CGFloat childViewX = plusButtonIndex * CYLTabBarItemWidth; CGFloat tabBarItemWidth = CGRectGetWidth(self.plusButton.frame); [self changeXForChildView:self.plusButton childViewX:childViewX tabBarItemWidth:tabBarItemWidth index:plusButtonIndex ]; CYLPlusButtonIndex = plusButtonIndex; return plusButtonIndex; } - (void)setupTabImageViewDefaultOffset:(UIView *)tabBarButton { if (self.tabImageViewDefaultOffset > 0) { return; } __block BOOL shouldCustomizeImageView = YES; __block CGFloat tabImageViewDefaultOffset = 0.f; CGFloat tabButtonCenterY = tabBarButton.center.y; [tabBarButton.subviews enumerateObjectsUsingBlock:^(__kindof UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { if ([obj cyl_isTabLabel]) { shouldCustomizeImageView = NO; } CGFloat tabImageViewCenterY = obj.center.y; BOOL isTabImageView = [obj cyl_isTabImageView]; if (isTabImageView) { tabImageViewDefaultOffset = (tabButtonCenterY - tabImageViewCenterY) * 0.5; } if (isTabImageView && tabImageViewDefaultOffset == 0.f) { shouldCustomizeImageView = NO; } }]; if (shouldCustomizeImageView) { self.tabImageViewDefaultOffset = tabImageViewDefaultOffset; } } /*! * Capturing touches on a subview outside the frame of its superview. */ - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { //1. 边界情况:不能响应点击事件 BOOL canNotResponseEvent = self.cyl_canNotResponseEvent; if (canNotResponseEvent) { return [super hitTest:point withEvent:event]; } //2. 优先处理 PlusButton (包括其突出的部分)、TabBarItems 未凸出的部分 //这一步主要是在处理只有两个 TabBarItems 的场景。 // 2.1先考虑clipsToBounds情况:子view超出部分没有显示出来 if (self.clipsToBounds && ![self pointInside:point withEvent:event]) { return [super hitTest:point withEvent:event]; } if (self.plusButton) { CGRect plusButtonFrame = self.plusButton.frame; BOOL isInPlusButtonFrame = CGRectContainsPoint(plusButtonFrame, point); if (isInPlusButtonFrame) { return self.plusButton; } } NSArray *tabBarButtons = self.tabBarButtonArray; if (self.tabBarButtonArray.count == 0) { tabBarButtons = [self cyl_visibleControls]; } for (NSUInteger index = 0; index < tabBarButtons.count; index++) { UIView *selectedTabBarButton = tabBarButtons[index]; CGRect selectedTabBarButtonFrame = selectedTabBarButton.frame; BOOL isTabBarButtonFrame = CGRectContainsPoint(selectedTabBarButtonFrame, point); if (isTabBarButtonFrame && !selectedTabBarButton.hidden) { return selectedTabBarButton; } } //3. 最后处理 TabBarItems 凸出的部分、添加到 TabBar 上的自定义视图、点击到 TabBar 上的空白区域 UIView *result = [super hitTest:point withEvent:event]; if (result) { return result; } for (UIView *subview in self.subviews.reverseObjectEnumerator) { CGPoint subPoint = [subview convertPoint:point fromView:self]; result = [subview hitTest:subPoint withEvent:event]; if (result) { return result; } } return [super hitTest:point withEvent:event]; } @end ================================================ FILE: CYLTabBarController/CYLTabBarController.h ================================================ // // CYLTabBarController.h // CYLTabBarController // // v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/20/15. // Copyright © 2018 https://github.com/ChenYilong . All rights reserved. // #import "CYLPlusButton.h" #import "UIViewController+CYLTabBarControllerExtention.h" #import "UIViewController+CYLNavigationControllerExtention.h" #import "UIView+CYLTabBarControllerExtention.h" #import "UITabBarItem+CYLTabBarControllerExtention.h" #import "UIControl+CYLTabBarControllerExtention.h" #import "CYLBaseViewController.h" #import "CYLBaseTableViewController.h" #import "CYLBaseNavigationController.h" #import "CYLTabBar+CYLTabBarControllerExtention.h" #import "UITabBarItem+CYLBadgeExtention.h" #import "UIBarButtonItem+CYLBadgeExtention.h" #import "UIView+CYLBadgeExtention.h" #import "NSObject+CYLTabBarControllerExtention.h" #import "UIColor+CYLTabBarControllerExtention.h" NS_ASSUME_NONNULL_BEGIN @class CYLTabBarController; typedef void(^CYLViewDidLayoutSubViewsBlock)(CYLTabBarController *tabBarController); FOUNDATION_EXTERN NSString *const CYLTabBarItemTitle; FOUNDATION_EXTERN NSString *const CYLTabBarItemImage; FOUNDATION_EXTERN NSString *const CYLTabBarItemSelectedImage; FOUNDATION_EXTERN NSString *const CYLTabBarLottieURL; FOUNDATION_EXTERN NSString *const CYLTabBarLottieSize; FOUNDATION_EXTERN NSString *const CYLTabBarItemImageInsets; FOUNDATION_EXTERN NSString *const CYLTabBarItemTitlePositionAdjustment; FOUNDATION_EXTERN NSUInteger CYLTabbarItemsCount; FOUNDATION_EXTERN NSUInteger CYLPlusButtonIndex; FOUNDATION_EXTERN CGFloat CYLPlusButtonWidth; FOUNDATION_EXTERN CGFloat CYLTabBarItemWidth; FOUNDATION_EXTERN CGFloat CYLTabBarHeight; @protocol CYLTabBarControllerDelegate @optional /*! * @param tabBarController The tab bar controller containing viewController. * @param control Selected UIControl in TabBar. */ - (void)tabBarController:(UITabBarController *)tabBarController didSelectControl:(UIControl *)control; @end @interface CYLTabBarController : UITabBarController @property (nonatomic, copy) CYLViewDidLayoutSubViewsBlock viewDidLayoutSubviewsBlock; - (void)setViewDidLayoutSubViewsBlock:(CYLViewDidLayoutSubViewsBlock)viewDidLayoutSubviewsBlock; - (void)setViewDidLayoutSubViewsBlockInvokeOnce:(BOOL)invokeOnce block:(CYLViewDidLayoutSubViewsBlock)viewDidLayoutSubviewsBlock; /*! * An array of the root view controllers displayed by the tab bar interface. */ @property (nonatomic, readwrite, copy) NSArray *viewControllers; /*! * The Attributes of items which is displayed on the tab bar. */ @property (nonatomic, readwrite, copy) NSArray *tabBarItemsAttributes; /*! * Customize UITabBar height */ @property (nonatomic, assign) CGFloat tabBarHeight; /*! * To set both UIBarItem image view attributes in the tabBar, * default is UIEdgeInsetsZero. */ @property (nonatomic, readonly, assign) UIEdgeInsets imageInsets; @property (nonatomic, strong) CYLTabBar *tabBar; /*! * To set both UIBarItem label text attributes in the tabBar, * use the following to tweak the relative position of the label within the tab button (for handling visual centering corrections if needed because of custom text attributes) */ @property (nonatomic, readonly, assign) UIOffset titlePositionAdjustment; @property (nonatomic, readonly, copy) NSString *context; - (instancetype)initWithViewControllers:(NSArray *)viewControllers tabBarItemsAttributes:(NSArray *)tabBarItemsAttributes; + (instancetype)tabBarControllerWithViewControllers:(NSArray *)viewControllers tabBarItemsAttributes:(NSArray *)tabBarItemsAttributes; - (instancetype)initWithViewControllers:(NSArray *)viewControllers tabBarItemsAttributes:(NSArray *)tabBarItemsAttributes imageInsets:(UIEdgeInsets)imageInsets titlePositionAdjustment:(UIOffset)titlePositionAdjustment; + (instancetype)tabBarControllerWithViewControllers:(NSArray *)viewControllers tabBarItemsAttributes:(NSArray *)tabBarItemsAttributes imageInsets:(UIEdgeInsets)imageInsets titlePositionAdjustment:(UIOffset)titlePositionAdjustment; - (instancetype)initWithViewControllers:(NSArray *)viewControllers tabBarItemsAttributes:(NSArray *)tabBarItemsAttributes imageInsets:(UIEdgeInsets)imageInsets titlePositionAdjustment:(UIOffset)titlePositionAdjustment context:(NSString *)context; + (instancetype)tabBarControllerWithViewControllers:(NSArray *)viewControllers tabBarItemsAttributes:(NSArray *)tabBarItemsAttributes imageInsets:(UIEdgeInsets)imageInsets titlePositionAdjustment:(UIOffset)titlePositionAdjustment context:(NSString *)context; - (void)updateSelectionStatusIfNeededForTabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController; - (void)updateSelectionStatusIfNeededForTabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController shouldSelect:(BOOL)shouldSelect; - (void)hideTabBarShadowImageView; - (void)setTintColor:(UIColor *)tintColor; /*! * Judge if there is plus button. */ + (BOOL)havePlusButton; /*! * @attention Include plusButton if exists. */ + (NSUInteger)allItemsInTabBarCount; - (id)appDelegate; - (UIWindow *)rootWindow; @end @interface NSObject (CYLTabBarControllerReferenceExtension) /*! * If `self` is kind of `UIViewController`, this method will return the nearest ancestor in the view controller hierarchy that is a tab bar controller. If `self` is not kind of `UIViewController`, it will return the `rootViewController` of the `rootWindow` as long as you have set the `CYLTabBarController` as the `rootViewController`. Otherwise return nil. (read-only) */ @property (nonatomic, setter=cyl_setTabBarController:) CYLTabBarController *cyl_tabBarController; @end #pragma mark - Deprecated API @interface CYLTabBarController (CYLTabBarControllerDeprecated) - (void)hideTabBadgeBackgroundSeparator CYL_DEPRECATED("Deprecated in 1.27.0. Use `-[CYLTabBarController hideTabBarShadowImageView]` instead."); @end FOUNDATION_EXTERN NSString *const CYLTabBarItemWidthDidChangeNotification; NS_ASSUME_NONNULL_END ================================================ FILE: CYLTabBarController/CYLTabBarController.m ================================================ // // CYLTabBarController.m // CYLTabBarController // // v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/20/15. // Copyright © 2018 https://github.com/ChenYilong . All rights reserved. // #import "CYLTabBarController.h" #import "CYLTabBar.h" #import #import "UIViewController+CYLTabBarControllerExtention.h" #import "UIControl+CYLTabBarControllerExtention.h" #import "UIImage+CYLTabBarControllerExtention.h" #if __has_include() #import #else #endif NSString *const CYLTabBarItemTitle = @"CYLTabBarItemTitle"; NSString *const CYLTabBarItemImage = @"CYLTabBarItemImage"; NSString *const CYLTabBarItemSelectedImage = @"CYLTabBarItemSelectedImage"; NSString *const CYLTabBarItemImageInsets = @"CYLTabBarItemImageInsets"; NSString *const CYLTabBarItemTitlePositionAdjustment = @"CYLTabBarItemTitlePositionAdjustment"; NSString *const CYLTabBarLottieURL = @"CYLTabBarLottieURL"; NSString *const CYLTabBarLottieSize = @"CYLTabBarLottieSize"; NSUInteger CYLTabbarItemsCount = 0; NSUInteger CYLPlusButtonIndex = 0; CGFloat CYLTabBarItemWidth = 0.0f; CGFloat CYLTabBarHeight = 0.0f; NSString *const CYLTabBarItemWidthDidChangeNotification = @"CYLTabBarItemWidthDidChangeNotification"; static void * const CYLTabImageViewDefaultOffsetContext = (void*)&CYLTabImageViewDefaultOffsetContext; @interface CYLTabBarController () @property (nonatomic, assign, getter=isObservingTabImageViewDefaultOffset) BOOL observingTabImageViewDefaultOffset; @property (nonatomic, assign, getter=shouldInvokeOnceViewDidLayoutSubViewsBlock) BOOL invokeOnceViewDidLayoutSubViewsBlock; @property (nonatomic, strong) NSMutableArray *lottieURLs; @property (nonatomic, strong) NSMutableArray *lottieSizes; @property (nonatomic, assign, getter=isLottieViewAdded) BOOL lottieViewAdded; @property (nonatomic, strong) UIImage *tabItemPlaceholderImage; @end @implementation CYLTabBarController @synthesize viewControllers = _viewControllers; #pragma mark - #pragma mark - Life Cycle - (void)viewDidLoad { [super viewDidLoad]; if (CYL_IS_IPHONE_X) { self.tabBarHeight = 83; } // 处理tabBar,使用自定义 tabBar 添加 发布按钮 [self setUpTabBar]; // KVO注册监听 if (!self.isObservingTabImageViewDefaultOffset) { [self.tabBar addObserver:self forKeyPath:@"tabImageViewDefaultOffset" options:NSKeyValueObservingOptionNew context:CYLTabImageViewDefaultOffsetContext]; self.observingTabImageViewDefaultOffset = YES; } } - (void)setSelectedIndex:(NSUInteger)selectedIndex { [super setSelectedIndex:selectedIndex]; [self updateSelectionStatusIfNeededForTabBarController:nil shouldSelectViewController:nil]; UIControl *selectedControl = [self.tabBar cyl_tabBarButtonWithTabIndex:selectedIndex]; if (selectedControl) { [self didSelectControl:selectedControl]; } } - (void)setViewDidLayoutSubViewsBlockInvokeOnce:(BOOL)invokeOnce block:(CYLViewDidLayoutSubViewsBlock)viewDidLayoutSubviewsBlock { self.viewDidLayoutSubviewsBlock = viewDidLayoutSubviewsBlock; self.invokeOnceViewDidLayoutSubViewsBlock = YES; } - (void)setViewDidLayoutSubViewsBlock:(CYLViewDidLayoutSubViewsBlock)viewDidLayoutSubviewsBlock { _viewDidLayoutSubviewsBlock = viewDidLayoutSubviewsBlock; } - (void)viewDidLayoutSubviews { [super viewDidLayoutSubviews]; [self.tabBar layoutSubviews];//Fix issue #93 #392 CYLTabBar *tabBar = (CYLTabBar *)self.tabBar; // add callback for visiable control, included all plusButton. [tabBar.cyl_visibleControls enumerateObjectsUsingBlock:^(UIControl * _Nonnull control, NSUInteger idx, BOOL * _Nonnull stop) { //to avoid invoking didSelectControl twice, because plusChildViewControllerButtonClicked will invoke setSelectedIndex if ([control cyl_isChildViewControllerPlusButton]) { return; } UILabel *tabLabel = control.cyl_tabLabel; tabLabel.textAlignment = NSTextAlignmentCenter; SEL actin = @selector(didSelectControl:); [control addTarget:self action:actin forControlEvents:UIControlEventTouchUpInside]; if (idx == self.selectedIndex && ![control isKindOfClass:[CYLPlusButton class]]) { control.selected = YES; } }]; do { if (self.isLottieViewAdded) { break; } //FIXME: NSArray *subTabBarButtonsWithoutPlusButton = tabBar.cyl_subTabBarButtonsWithoutPlusButton; BOOL isLottieEnabled = [self isLottieEnabled]; if(!isLottieEnabled || (subTabBarButtonsWithoutPlusButton.count != self.lottieURLs.count)) { self.lottieViewAdded = YES; break; } dispatch_async(dispatch_get_main_queue(),^{ [subTabBarButtonsWithoutPlusButton enumerateObjectsUsingBlock:^(UIControl * _Nonnull control, NSUInteger idx, BOOL * _Nonnull stop) { UIControl *tabButton = control; BOOL defaultSelected = NO; if (idx == self.selectedIndex) { defaultSelected = YES; } [self addLottieImageWithControl:tabButton animation:defaultSelected defaultSelected:defaultSelected]; }]; self.lottieViewAdded = YES; }); break; } while (NO); if (self.shouldInvokeOnceViewDidLayoutSubViewsBlock) { //在对象生命周期内,不添加 flag 属性的情况下,防止多次调进这个方法 if (objc_getAssociatedObject(self, _cmd)) { return; } else { !self.viewDidLayoutSubviewsBlock ?: self.viewDidLayoutSubviewsBlock(self); objc_setAssociatedObject(self, _cmd, @"shouldInvokeOnceViewDidLayoutSubViewsBlock", OBJC_ASSOCIATION_RETAIN); } return; } !self.viewDidLayoutSubviewsBlock ?: self.viewDidLayoutSubviewsBlock(self); } - (void)viewWillLayoutSubviews { [super viewWillLayoutSubviews]; if (!(self.tabBarHeight > 0)) { return; } self.tabBar.frame = ({ CGRect frame = self.tabBar.frame; CGFloat tabBarHeight = self.tabBarHeight; frame.size.height = tabBarHeight; frame.origin.y = self.view.frame.size.height - tabBarHeight; frame; }); } - (void)setTabBarHeight:(CGFloat)tabBarHeight { _tabBarHeight = tabBarHeight; CYLTabBarHeight = tabBarHeight; } - (UIInterfaceOrientationMask)supportedInterfaceOrientations { UIViewController *controller = self.selectedViewController; if ([controller isKindOfClass:[UINavigationController class]]) { UINavigationController *navigationController = (UINavigationController *)controller; return navigationController.topViewController.supportedInterfaceOrientations; } else { return controller.supportedInterfaceOrientations; } } - (void)dealloc { UIButton *plusButton = CYLExternPlusButton; if (plusButton.superview && (plusButton.superview == self.tabBar)) { plusButton.selected = NO; [plusButton removeFromSuperview]; } BOOL isAdded = [self isPlusViewControllerAdded:_viewControllers]; BOOL hasPlusChildViewController = [self hasPlusChildViewController] && isAdded; if (isAdded && hasPlusChildViewController && CYLPlusChildViewController.cyl_plusViewControllerEverAdded == YES) { [CYLPlusChildViewController cyl_setPlusViewControllerEverAdded:NO]; } // KVO反注册 if (self.tabBar && self.isObservingTabImageViewDefaultOffset) { @try { [self.tabBar removeObserver:self forKeyPath:@"tabImageViewDefaultOffset"]; } @catch(NSException *e) { } } } #pragma mark - #pragma mark - public Methods - (instancetype)initWithViewControllers:(NSArray *)viewControllers tabBarItemsAttributes:(NSArray *)tabBarItemsAttributes { return [self initWithViewControllers:viewControllers tabBarItemsAttributes:tabBarItemsAttributes imageInsets:UIEdgeInsetsZero titlePositionAdjustment:UIOffsetZero context:nil]; } - (instancetype)initWithViewControllers:(NSArray *)viewControllers tabBarItemsAttributes:(NSArray *)tabBarItemsAttributes imageInsets:(UIEdgeInsets)imageInsets titlePositionAdjustment:(UIOffset)titlePositionAdjustment { return [self initWithViewControllers:viewControllers tabBarItemsAttributes:tabBarItemsAttributes imageInsets:imageInsets titlePositionAdjustment:titlePositionAdjustment context:nil]; } - (instancetype)initWithViewControllers:(NSArray *)viewControllers tabBarItemsAttributes:(NSArray *)tabBarItemsAttributes imageInsets:(UIEdgeInsets)imageInsets titlePositionAdjustment:(UIOffset)titlePositionAdjustment context:(NSString *)context { if (self = [super init]) { _imageInsets = imageInsets; _titlePositionAdjustment = titlePositionAdjustment; _tabBarItemsAttributes = tabBarItemsAttributes; self.context = context; self.viewControllers = viewControllers; } return self; } - (void)setContext:(NSString *)context { if (context && context.length > 0) { _context = [context copy]; } else { _context = NSStringFromClass([CYLTabBarController class]); } [self.tabBar setValue:_context forKey:@"context"]; } + (instancetype)tabBarControllerWithViewControllers:(NSArray *)viewControllers tabBarItemsAttributes:(NSArray *)tabBarItemsAttributes imageInsets:(UIEdgeInsets)imageInsets titlePositionAdjustment:(UIOffset)titlePositionAdjustment context:(NSString *)context { return [[self alloc] initWithViewControllers:viewControllers tabBarItemsAttributes:tabBarItemsAttributes imageInsets:imageInsets titlePositionAdjustment:titlePositionAdjustment context:context]; } + (instancetype)tabBarControllerWithViewControllers:(NSArray *)viewControllers tabBarItemsAttributes:(NSArray *)tabBarItemsAttributes imageInsets:(UIEdgeInsets)imageInsets titlePositionAdjustment:(UIOffset)titlePositionAdjustment { return [[self alloc] initWithViewControllers:viewControllers tabBarItemsAttributes:tabBarItemsAttributes imageInsets:imageInsets titlePositionAdjustment:titlePositionAdjustment context:nil]; } + (instancetype)tabBarControllerWithViewControllers:(NSArray *)viewControllers tabBarItemsAttributes:(NSArray *)tabBarItemsAttributes { return [self tabBarControllerWithViewControllers:viewControllers tabBarItemsAttributes:tabBarItemsAttributes imageInsets:UIEdgeInsetsZero titlePositionAdjustment:UIOffsetZero]; } - (void)hideTabBadgeBackgroundSeparator { [self hideTabBarShadowImageView]; } - (void)hideTabBarShadowImageView { [self.tabBar layoutIfNeeded]; UIImageView *imageView = self.tabBar.cyl_tabShadowImageView; imageView.hidden = YES;//iOS13+ imageView.alpha = 0; } + (BOOL)havePlusButton { if (CYLExternPlusButton) { return YES; } return NO; } + (NSUInteger)allItemsInTabBarCount { NSUInteger allItemsInTabBar = CYLTabbarItemsCount; if ([CYLTabBarController havePlusButton]) { allItemsInTabBar += 1; } return allItemsInTabBar; } - (id)appDelegate { return [UIApplication sharedApplication].delegate; } - (UIWindow *)rootWindow { UIWindow *result = nil; do { if ([self.appDelegate respondsToSelector:@selector(window)]) { result = [self.appDelegate window]; } if (result) { break; } } while (NO); return result; } #pragma mark - #pragma mark - Private Methods /** * 利用 KVC 把系统的 tabBar 类型改为自定义类型。 */ - (void)setUpTabBar { CYLTabBar *tabBar = [[CYLTabBar alloc] init]; [self setValue:tabBar forKey:@"tabBar"]; [tabBar cyl_setTabBarController:self]; } - (BOOL)hasPlusChildViewController { NSString *context = CYLPlusChildViewController.cyl_context; BOOL isSameContext = [context isEqualToString:self.context] && (context && self.context); // || (!context && !self.context); BOOL hasPlusChildViewController = CYLPlusChildViewController && isSameContext;//&& !isAdded; return hasPlusChildViewController; } - (BOOL)isPlusViewControllerAdded:(NSArray *)viewControllers { if ([_viewControllers containsObject:CYLPlusChildViewController]) { return YES; } __block BOOL isAdded = NO; [_viewControllers enumerateObjectsUsingBlock:^(UIViewController * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { if ([self isEqualViewController:obj compairedViewController:CYLPlusChildViewController]) { isAdded = YES; *stop = YES; return; } }]; return isAdded;; } - (void)setViewControllers:(NSArray *)viewControllers { if (_viewControllers && _viewControllers.count) { for (UIViewController *viewController in _viewControllers) { [viewController willMoveToParentViewController:nil]; [viewController.view removeFromSuperview]; [viewController removeFromParentViewController]; } BOOL isAdded = [self isPlusViewControllerAdded:_viewControllers]; BOOL hasPlusChildViewController = [self hasPlusChildViewController] && !isAdded; if (hasPlusChildViewController) { [CYLPlusChildViewController willMoveToParentViewController:nil]; [CYLPlusChildViewController.view removeFromSuperview]; [CYLPlusChildViewController removeFromParentViewController]; } } if (viewControllers && [viewControllers isKindOfClass:[NSArray class]]) { if ((!_tabBarItemsAttributes) || (_tabBarItemsAttributes.count != viewControllers.count)) { [NSException raise:NSStringFromClass([CYLTabBarController class]) format:@"The count of CYLTabBarControllers is not equal to the count of tabBarItemsAttributes.【Chinese】设置_tabBarItemsAttributes属性时,请确保元素个数与控制器的个数相同,并在方法`-setViewControllers:`之前设置"]; } BOOL isAdded = [self isPlusViewControllerAdded:_viewControllers]; BOOL addedFlag = [CYLPlusChildViewController cyl_plusViewControllerEverAdded]; BOOL hasPlusChildViewController = [self hasPlusChildViewController] && !isAdded && !addedFlag; if (hasPlusChildViewController) { NSMutableArray *viewControllersWithPlusButton = [NSMutableArray arrayWithArray:viewControllers]; [viewControllersWithPlusButton insertObject:CYLPlusChildViewController atIndex:CYLPlusButtonIndex]; _viewControllers = [viewControllersWithPlusButton copy]; [CYLPlusChildViewController cyl_setPlusViewControllerEverAdded:YES]; [CYLExternPlusButton cyl_setTabBarChildViewControllerIndex:CYLPlusButtonIndex]; } else { _viewControllers = [viewControllers copy]; [CYLExternPlusButton cyl_setTabBarChildViewControllerIndex:NSNotFound]; } CYLTabbarItemsCount = [viewControllers count]; CYLTabBarItemWidth = ([UIScreen mainScreen].bounds.size.width - CYLPlusButtonWidth) / (CYLTabbarItemsCount); NSUInteger idx = 0; for (UIViewController *viewController in _viewControllers) { NSString *title = nil; id normalImageInfo = nil; id selectedImageInfo = nil; UIOffset titlePositionAdjustment = UIOffsetZero; UIEdgeInsets imageInsets = UIEdgeInsetsZero; NSURL *lottieURL = nil; NSValue *lottieSizeValue = nil; if (viewController != CYLPlusChildViewController) { if (@available(iOS 13.0, *)) { //fix https://github.com/ChenYilong/CYLTabBarController/issues/437 title = _tabBarItemsAttributes[idx][CYLTabBarItemTitle] ?: @""; } else { title = _tabBarItemsAttributes[idx][CYLTabBarItemTitle]; } normalImageInfo = _tabBarItemsAttributes[idx][CYLTabBarItemImage]; selectedImageInfo = _tabBarItemsAttributes[idx][CYLTabBarItemSelectedImage]; lottieURL = _tabBarItemsAttributes[idx][CYLTabBarLottieURL]; lottieSizeValue = _tabBarItemsAttributes[idx][CYLTabBarLottieSize]; NSValue *offsetValue = _tabBarItemsAttributes[idx][CYLTabBarItemTitlePositionAdjustment]; UIOffset offset = [offsetValue UIOffsetValue]; titlePositionAdjustment = offset; NSValue *insetsValue = _tabBarItemsAttributes[idx][CYLTabBarItemImageInsets]; UIEdgeInsets insets = [insetsValue UIEdgeInsetsValue]; imageInsets = insets; } else { idx--; /**如果是CYLPlusChildViewController ,title设置为空字符串,解决把第一个tabbarItem设置成plusButton后,其他的 tabbarItem会不显示title问题  见: https://github.com/ChenYilong/CYLTabBarController/issues/563 **/ title = @""; } [self addOneChildViewController:viewController WithTitle:title normalImageInfo:normalImageInfo selectedImageInfo:selectedImageInfo titlePositionAdjustment:titlePositionAdjustment imageInsets:imageInsets lottieURL:lottieURL lottieSizeValue:lottieSizeValue ]; [[viewController cyl_getViewControllerInsteadOfNavigationController] cyl_setTabBarController:self]; idx++; } } else { for (UIViewController *viewController in _viewControllers) { [[viewController cyl_getViewControllerInsteadOfNavigationController] cyl_setTabBarController:nil]; } _viewControllers = nil; } } - (void)setTintColor:(UIColor *)tintColor { if ([[[UIDevice currentDevice] systemVersion] floatValue] < 8.f) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" [self.tabBar setSelectedImageTintColor:tintColor]; #pragma clang diagnostic pop } self.tabBar.tintColor = tintColor; } /** * lazy load tabItemPlaceholderImage * * @return UIImage */ - (UIImage *)tabItemPlaceholderImage { if (_tabItemPlaceholderImage == nil) { CGSize placeholderSize = CGSizeMake(22, 22); UIImage *placeholderImage = [UIImage cyl_imageWithColor:[UIColor whiteColor] size:placeholderSize]; UIImage *tabItemPlaceholderImage = placeholderImage; _tabItemPlaceholderImage = tabItemPlaceholderImage; } return _tabItemPlaceholderImage; } /** * 添加一个子控制器 * * @param viewController 控制器 * @param title 标题 * @param normalImageInfo 图片 * @param selectedImageInfo 选中图片 */ - (void)addOneChildViewController:(UIViewController *)viewController WithTitle:(NSString *)title normalImageInfo:(id)normalImageInfo selectedImageInfo:(id)selectedImageInfo titlePositionAdjustment:(UIOffset)titlePositionAdjustment imageInsets:(UIEdgeInsets)imageInsets lottieURL:(NSURL *)lottieURL lottieSizeValue:(NSValue *)lottieSizeValue { viewController.tabBarItem.title = title; UIImage *normalImage = nil; if (normalImageInfo) { normalImage = [self getImageFromImageInfo:normalImageInfo]; } else { normalImage = self.tabItemPlaceholderImage; } viewController.tabBarItem.image = normalImage; UIImage *selectedImage = nil; if (selectedImageInfo) { selectedImage = [self getImageFromImageInfo:selectedImageInfo]; } else { selectedImage = self.tabItemPlaceholderImage; } viewController.tabBarItem.selectedImage = selectedImage; if (self.shouldCustomizeImageInsets || ([self isNOTEmptyForImageInsets:imageInsets])) { UIEdgeInsets insets = (([self isNOTEmptyForImageInsets:imageInsets]) ? imageInsets : self.imageInsets); viewController.tabBarItem.imageInsets = insets; } if (self.shouldCustomizeTitlePositionAdjustment || [self isNOTEmptyForTitlePositionAdjustment:titlePositionAdjustment]) { UIOffset offset = (([self isNOTEmptyForTitlePositionAdjustment:titlePositionAdjustment]) ? titlePositionAdjustment : self.titlePositionAdjustment); viewController.tabBarItem.titlePositionAdjustment = offset; } if (lottieURL) { [self.lottieURLs addObject:lottieURL]; NSValue *tureLottieSizeValue = nil; do { if (!CGSizeEqualToSize(CGSizeZero, [lottieSizeValue CGSizeValue])) { tureLottieSizeValue = lottieSizeValue; break; } if (normalImage && !CGSizeEqualToSize(CGSizeZero, normalImage.size)) { tureLottieSizeValue = [NSValue valueWithCGSize:normalImage.size]; break; } CGSize placeholderSize = CGSizeMake(22, 22); tureLottieSizeValue = [NSValue valueWithCGSize:placeholderSize]; break; } while (NO); [self.lottieSizes addObject:tureLottieSizeValue]; } [self addChildViewController:viewController]; } - (UIImage *)getImageFromImageInfo:(id)imageInfo { UIImage *image = nil; if ([imageInfo isKindOfClass:[NSString class]]) { image = [UIImage imageNamed:imageInfo]; image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; } else if ([imageInfo isKindOfClass:[UIImage class]]) { image = (UIImage *)imageInfo; } return image; } - (BOOL)shouldCustomizeImageInsets { BOOL shouldCustomizeImageInsets = [self isNOTEmptyForImageInsets:self.imageInsets]; return shouldCustomizeImageInsets; } - (BOOL)shouldCustomizeTitlePositionAdjustment { BOOL shouldCustomizeTitlePositionAdjustment = [self isNOTEmptyForTitlePositionAdjustment:self.titlePositionAdjustment]; return shouldCustomizeTitlePositionAdjustment; } - (BOOL)isNOTEmptyForImageInsets:(UIEdgeInsets)imageInsets { if (imageInsets.top != 0 || imageInsets.left != 0 || imageInsets.bottom != 0 || imageInsets.right != 0) { return YES; } return NO; } - (BOOL)isNOTEmptyForTitlePositionAdjustment:(UIOffset)titlePositionAdjustment { if (titlePositionAdjustment.horizontal != 0 || titlePositionAdjustment.vertical != 0) { return YES; } return NO; } - (BOOL)isNOTEmptyForSize:(UIOffset)titlePositionAdjustment { if (titlePositionAdjustment.horizontal != 0 || titlePositionAdjustment.vertical != 0) { return YES; } return NO; } #pragma mark - #pragma mark - KVO Method // KVO监听执行 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if(context != CYLTabImageViewDefaultOffsetContext) { [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; return; } if(context == CYLTabImageViewDefaultOffsetContext) { CGFloat tabImageViewDefaultOffset = [change[NSKeyValueChangeNewKey] floatValue]; [self offsetTabBarTabImageViewToFit:tabImageViewDefaultOffset]; } } - (void)offsetTabBarTabImageViewToFit:(CGFloat)tabImageViewDefaultOffset { if (self.shouldCustomizeImageInsets) { return; } NSArray *tabBarItems = self.tabBar.items; [tabBarItems enumerateObjectsUsingBlock:^(UITabBarItem * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { UIEdgeInsets imageInset = UIEdgeInsetsMake(tabImageViewDefaultOffset, 0, -tabImageViewDefaultOffset, 0); obj.imageInsets = imageInset; if (!self.shouldCustomizeTitlePositionAdjustment) { obj.titlePositionAdjustment = UIOffsetMake(0, MAXFLOAT); } }]; } #pragma mark - delegate - (void)updateSelectionStatusIfNeededForTabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController { [self updateSelectionStatusIfNeededForTabBarController:tabBarController shouldSelectViewController:viewController shouldSelect:YES]; } - (void)updateSelectionStatusIfNeededForTabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController shouldSelect:(BOOL)shouldSelect { [[viewController.tabBarItem cyl_tabButton] cyl_setShouldNotSelect:!shouldSelect]; if (!shouldSelect) { return; } UIButton *plusButton = CYLExternPlusButton; if (!viewController) { viewController = self.selectedViewController; } BOOL isCurrentViewController = [self isEqualViewController:viewController compairedViewController:CYLPlusChildViewController]; BOOL shouldConfigureSelectionStatus = (!isCurrentViewController); plusButton.selected = !shouldConfigureSelectionStatus; if (!shouldConfigureSelectionStatus) { [self.tabBar cyl_stopAnimationOfAllLottieView]; } } - (BOOL)isEqualViewController:(UIViewController *)viewController compairedViewController:(UIViewController *)compairedViewController { if ([viewController isEqual:compairedViewController]) { return YES; } if ([[viewController cyl_getViewControllerInsteadOfNavigationController] isEqual:[compairedViewController cyl_getViewControllerInsteadOfNavigationController]]) { return YES; } return NO; } - (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController { [self updateSelectionStatusIfNeededForTabBarController:tabBarController shouldSelectViewController:viewController]; return YES; } - (void)tabBarController:(UITabBarController *)tabBarController didSelectControl:(UIControl *)control { } - (BOOL)isLottieEnabled { NSInteger lottieURLCount = self.lottieURLs.count; BOOL isLottieEnabled = lottieURLCount > 0 ; return isLottieEnabled; } - (void)didSelectControl:(UIControl *)control { SEL actin = @selector(tabBarController:didSelectControl:); BOOL shouldSelectViewController = YES; @try { shouldSelectViewController = (!control.cyl_shouldNotSelect) && (!control.hidden) ; } @catch (NSException *exception) { NSLog(@"🔴类名与方法名:%@(在第%@行),描述:%@", @(__PRETTY_FUNCTION__), @(__LINE__), exception.reason); } BOOL isSelected = control.cyl_isSelected; if (shouldSelectViewController) { [self.tabBar.cyl_visibleControls enumerateObjectsUsingBlock:^(UIControl * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { obj.selected = NO; }]; control.selected = YES; UIControl *tabButton = control; BOOL isChildViewControllerPlusButton = [control cyl_isChildViewControllerPlusButton]; BOOL isLottieEnabled = [self isLottieEnabled]; if (!isSelected && isLottieEnabled && !isChildViewControllerPlusButton) { [self addLottieImageWithControl:tabButton animation:YES]; } } if ([self.delegate respondsToSelector:actin] && shouldSelectViewController) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" [self.delegate performSelector:actin withObject:self withObject:control ?: self.selectedViewController.tabBarItem.cyl_tabButton]; #pragma clang diagnostic pop } } - (void)addLottieImageWithControl:(UIControl *)control animation:(BOOL)animation { [self addLottieImageWithControl:control animation:animation defaultSelected:NO]; } - (void)addLottieImageWithControl:(UIControl *)control animation:(BOOL)animation defaultSelected:(BOOL)defaultSelected { NSUInteger index = [self.tabBar.cyl_subTabBarButtonsWithoutPlusButton indexOfObject:control]; if (NSNotFound == index) { return; } if (control.cyl_isPlusButton) { return; } NSURL *lottieURL = self.lottieURLs[index]; NSValue *lottieSizeValue = self.lottieSizes[index]; CGSize lottieSize = [lottieSizeValue CGSizeValue]; [control cyl_addLottieImageWithLottieURL:lottieURL size:lottieSize]; if (animation) { [self.tabBar cyl_animationLottieImageWithSelectedControl:control lottieURL:lottieURL size:lottieSize defaultSelected:defaultSelected]; } } - (id)rootViewController { CYLTabBarController *tabBarController = nil; id delegate = ((id)[[UIApplication sharedApplication] delegate]); UIWindow *window = delegate.window; UIViewController *rootViewController = [window.rootViewController cyl_getViewControllerInsteadOfNavigationController];; if ([rootViewController isKindOfClass:[CYLTabBarController class]]) { tabBarController = (CYLTabBarController *)rootViewController; } return tabBarController; } /** * lazy load lottieURLs * * @return NSMutableArray */ - (NSMutableArray *)lottieURLs { if (_lottieURLs == nil) { NSMutableArray *lottieURLs = [[NSMutableArray alloc] init]; _lottieURLs = lottieURLs; } return _lottieURLs; } /** * lazy load lottieSizes * * @return NSMutableArray */ - (NSMutableArray *)lottieSizes { if (_lottieSizes == nil) { NSMutableArray *lottieSizes = [[NSMutableArray alloc] init]; _lottieSizes = lottieSizes; } return _lottieSizes; } @end @implementation NSObject (CYLTabBarControllerReferenceExtension) - (void)cyl_setTabBarController:(CYLTabBarController *)tabBarController { //OBJC_ASSOCIATION_ASSIGN instead of OBJC_ASSOCIATION_RETAIN_NONATOMIC to avoid retain circle id __weak weakObject = tabBarController; id (^block)(void) = ^{ return weakObject; }; objc_setAssociatedObject(self, @selector(cyl_tabBarController), block, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } static inline UIWindow *getMainWindow(){ UIWindow *window = nil; if ([UIApplication.sharedApplication.delegate respondsToSelector:@selector(window)]) { //兼容新版项目结构,也就是AppDelegate没有window的情况 window = UIApplication.sharedApplication.delegate.window; } if (!window) { if (@available(iOS 13.0, *)) { for (UIWindowScene* wScene in [UIApplication sharedApplication].connectedScenes) { if (wScene.activationState == UISceneActivationStateForegroundActive) { window = wScene.windows.firstObject; break; } } } } return window; } //TODO: 更新实现,多实例场景下进行栈操作,弹出最新一个。 - (CYLTabBarController *)cyl_tabBarController { CYLTabBarController *tabBarController; id (^block)(void) = objc_getAssociatedObject(self, @selector(cyl_tabBarController)); tabBarController = (block ? block() : nil); if (tabBarController && [tabBarController isKindOfClass:[CYLTabBarController class]]) { return tabBarController; } if ([self isKindOfClass:[UIViewController class]] && [(UIViewController *)self parentViewController]) { tabBarController = [[(UIViewController *)self parentViewController] cyl_tabBarController]; if ([tabBarController isKindOfClass:[CYLTabBarController class]]) { return tabBarController; } } // id delegate = ((id)[[UIApplication sharedApplication] delegate]); // UIWindow *window = delegate.window; UIWindow *window = getMainWindow(); UIViewController *rootViewController = [window.rootViewController cyl_getViewControllerInsteadOfNavigationController];; if ([rootViewController isKindOfClass:[CYLTabBarController class]]) { tabBarController = (CYLTabBarController *)rootViewController; } return tabBarController; } @end ================================================ FILE: CYLTabBarController/NSObject+CYLTabBarControllerExtention.h ================================================ // // CYLTabBarController.h // CYLTabBarController // // v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/20/15. // Copyright © 2018 https://github.com/ChenYilong . All rights reserved. // #import NS_ASSUME_NONNULL_BEGIN @interface NSObject (CYLTabBarControllerExtention) @property (nonatomic, assign, getter=cyl_isForceLandscape, setter=cyl_setIsForceLandscape:) BOOL cyl_isForceLandscape; - (void)cyl_forceUpdateInterfaceOrientation:(UIInterfaceOrientation)orientation; - (UIResponder *)cyl_sharedAppDelegate; + (UIViewController * __nullable)cyl_topmostViewController; + (UINavigationController * __nullable)cyl_currentNavigationController; + (void)cyl_dismissAll:(void (^ __nullable)(void))completion; @end NS_ASSUME_NONNULL_END ================================================ FILE: CYLTabBarController/NSObject+CYLTabBarControllerExtention.m ================================================ // // CYLTabBarController.h // CYLTabBarController // // v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/20/15. // Copyright © 2018 https://github.com/ChenYilong . All rights reserved. // #import "NSObject+CYLTabBarControllerExtention.h" #import @implementation NSObject (CYLTabBarControllerExtention) - (BOOL)cyl_isForceLandscape { NSNumber *isForceLandscapeObject = objc_getAssociatedObject(self, @selector(cyl_isForceLandscape)); return [isForceLandscapeObject boolValue]; } - (void)cyl_setIsForceLandscape:(BOOL)isForceLandscape { NSNumber *isForceLandscapeObject = @(isForceLandscape); objc_setAssociatedObject(self, @selector(cyl_isForceLandscape), isForceLandscapeObject, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (UIResponder *)cyl_sharedAppDelegate { id appDelegate = [UIApplication sharedApplication].delegate; return (UIResponder *)appDelegate; } - (void)cyl_forceUpdateInterfaceOrientation:(UIInterfaceOrientation)orientation { UIResponder *appDelegate = [self cyl_sharedAppDelegate]; BOOL isForceLandscape = (UIInterfaceOrientationLandscapeLeft == orientation) || (UIInterfaceOrientationLandscapeRight == orientation); appDelegate.cyl_isForceLandscape = isForceLandscape; if ([appDelegate respondsToSelector:@selector(application:supportedInterfaceOrientationsForWindow:)]) { [appDelegate application:[UIApplication sharedApplication] supportedInterfaceOrientationsForWindow:UIApplication.sharedApplication.keyWindow]; } if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)]) { NSNumber *num = [[NSNumber alloc]initWithInt:UIInterfaceOrientationPortrait]; [[UIDevice currentDevice] performSelector:@selector(setOrientation:)withObject:(id)num]; [UIViewController attemptRotationToDeviceOrientation]; SEL selector = NSSelectorFromString(@"setOrientation:"); NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[UIDevice instanceMethodSignatureForSelector:selector]]; [invocation setSelector:selector]; [invocation setTarget:[UIDevice currentDevice]]; int val = [@(orientation) intValue]; [invocation setArgument:&val atIndex:2]; [invocation invoke]; } } + (UIViewController * __nullable)cyl_topmostViewController { UIViewController *topViewController = [[[UIApplication sharedApplication] keyWindow] rootViewController]; if (topViewController == nil) { return nil; } while (true) { if (topViewController.presentedViewController != nil) { topViewController = topViewController.presentedViewController; } else if ([topViewController isKindOfClass:[UINavigationController class]]) { UINavigationController *navi = (UINavigationController *)topViewController; topViewController = navi.topViewController; } else if ([topViewController isKindOfClass:[UITabBarController class]]) { UITabBarController *tab = (UITabBarController *)topViewController; topViewController = tab.selectedViewController; } else { break; } } return topViewController; } + (UINavigationController * __nullable)cyl_currentNavigationController { return [[UIViewController cyl_topmostViewController] navigationController]; } + (void)cyl_dismissAll:(void (^ __nullable)(void))completion { UIViewController *topViewController = [[[UIApplication sharedApplication] keyWindow] rootViewController]; if (topViewController == nil) { !completion ?: completion(); return; } NSMutableArray *list = [NSMutableArray new]; while (true) { if (topViewController.presentedViewController != nil) { topViewController = topViewController.presentedViewController; [list addObject:topViewController]; } else if ([topViewController isKindOfClass:[UINavigationController class]]) { UINavigationController *navi = (UINavigationController *)topViewController; topViewController = navi.topViewController; } else if ([topViewController isKindOfClass:[UITabBarController class]]) { UITabBarController *tab = (UITabBarController *)topViewController; topViewController = tab.selectedViewController; } else { break; } } if (list.count == 0) { if (completion) { completion(); } return; } for (NSInteger i = list.count - 1; i >=0 ; i--) { UIViewController *vc = list[i]; if (i == 0) { if ([vc isKindOfClass:[UINavigationController class]]) { [(UINavigationController *)vc popToRootViewControllerAnimated:NO]; } [vc dismissViewControllerAnimated:NO completion:completion]; } else { if ([vc isKindOfClass:[UINavigationController class]]) { [(UINavigationController *)vc popToRootViewControllerAnimated:NO]; } [vc dismissViewControllerAnimated:NO completion:nil]; } } } @end ================================================ FILE: CYLTabBarController/UIBarButtonItem+CYLBadgeExtention.h ================================================ /* //  CYLTabBarController //  CYLTabBarController // //  Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 03/06/19. //  Copyright © 2019 https://github.com/ChenYilong . All rights reserved. */ #import #import "UIView+CYLBadgeExtention.h" #import "CYLBadgeProtocol.h" NS_ASSUME_NONNULL_BEGIN @interface UIBarButtonItem (CYLBadgeExtention) - (BOOL)cyl_isShowBadge; /** * show badge with red dot style and CYLBadgeAnimationTypeNone by default. */ - (void)cyl_showBadge; /** * cyl_showBadge * * @param value String value, default is `nil`. if value equal @"" means red dot style. * @param animationType animationType */ - (void)cyl_showBadgeValue:(NSString *)value animationType:(CYLBadgeAnimationType)animationType; /** * clear badge(hide badge) */ - (void)cyl_clearBadge; /** * make bage(if existing) not hiden */ - (void)cyl_resumeBadge; - (BOOL)cyl_isPauseBadge; @end NS_ASSUME_NONNULL_END ================================================ FILE: CYLTabBarController/UIBarButtonItem+CYLBadgeExtention.m ================================================ /* //  CYLTabBarController //  CYLTabBarController // //  Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 03/06/19. //  Copyright © 2019 https://github.com/ChenYilong . All rights reserved. */ #import "UIBarButtonItem+CYLBadgeExtention.h" #import #define kActualView [self cyl_getActualBadgeSuperView] @implementation UIBarButtonItem (CYLBadgeExtention) #pragma mark -- public methods /** * show badge with red dot style and CYLBadgeAnimationTypeNone by default. */ - (void)cyl_showBadge { [kActualView cyl_showBadge]; } - (void)cyl_showBadgeValue:(NSString *)value animationType:(CYLBadgeAnimationType)animationType { [kActualView cyl_showBadgeValue:value animationType:animationType]; } - (void)cyl_clearBadge { [kActualView cyl_clearBadge]; } - (void)cyl_resumeBadge { [kActualView cyl_resumeBadge]; } - (BOOL)cyl_isPauseBadge { return [kActualView cyl_isPauseBadge]; } - (BOOL)cyl_isShowBadge { return [kActualView cyl_isShowBadge]; } #pragma mark -- private method /** * Because UIBarButtonItem is kind of NSObject, it is not able to directly attach badge. This method is used to find actual view (non-nil) inside UIBarButtonItem instance. * * @return view */ - (UIView *)cyl_getActualBadgeSuperView { return [self valueForKeyPath:@"_view"];//use KVC to hack actual view } #pragma mark -- setter/getter - (UILabel *)cyl_badge { return kActualView.cyl_badge; } - (void)cyl_setBadge:(UILabel *)label { [kActualView cyl_setBadge:label]; } - (UIFont *)cyl_badgeFont { return kActualView.cyl_badgeFont; } - (void)cyl_setBadgeFont:(UIFont *)badgeFont { [kActualView cyl_setBadgeFont:badgeFont]; } - (UIColor *)cyl_badgeBackgroundColor { return [kActualView cyl_badgeBackgroundColor]; } - (void)cyl_setBadgeBackgroundColor:(UIColor *)badgeBackgroundColor { [kActualView cyl_setBadgeBackgroundColor:badgeBackgroundColor]; } - (UIColor *)cyl_badgeTextColor { return [kActualView cyl_badgeTextColor]; } - (void)cyl_setBadgeTextColor:(UIColor *)badgeTextColor { [kActualView cyl_setBadgeTextColor:badgeTextColor]; } - (CYLBadgeAnimationType)cyl_badgeAnimationType { return [kActualView cyl_badgeAnimationType]; } - (void)cyl_setBadgeAnimationType:(CYLBadgeAnimationType)animationType { [kActualView cyl_setBadgeAnimationType:animationType]; } - (CGRect)cyl_badgeFrame { return [kActualView cyl_badgeFrame]; } - (void)cyl_setBadgeFrame:(CGRect)badgeFrame { [kActualView cyl_setBadgeFrame:badgeFrame]; } - (CGPoint)cyl_badgeCenterOffset { return [kActualView cyl_badgeCenterOffset]; } - (void)cyl_setBadgeCenterOffset:(CGPoint)badgeCenterOffset { [kActualView cyl_setBadgeCenterOffset:badgeCenterOffset]; } - (NSInteger)cyl_badgeMaximumBadgeNumber { return [kActualView cyl_badgeMaximumBadgeNumber]; } - (void)cyl_setBadgeMaximumBadgeNumber:(NSInteger)badgeMaximumBadgeNumber { [kActualView cyl_setBadgeMaximumBadgeNumber:badgeMaximumBadgeNumber]; } - (CGFloat)cyl_badgeMargin { return [kActualView cyl_badgeMargin]; } - (void)cyl_setBadgeMargin:(CGFloat)badgeMargin { [kActualView cyl_setBadgeMargin:badgeMargin]; } - (CGFloat)cyl_badgeRadius { return [kActualView cyl_badgeRadius]; } - (void)cyl_setBadgeRadius:(CGFloat)badgeRadius { [kActualView cyl_setBadgeRadius:badgeRadius]; } - (CGFloat)cyl_badgeCornerRadius { return [kActualView cyl_badgeCornerRadius]; } - (void)cyl_setBadgeCornerRadius:(CGFloat)cyl_badgeCornerRadius { [kActualView cyl_setBadgeCornerRadius:cyl_badgeCornerRadius]; } @end ================================================ FILE: CYLTabBarController/UIColor+CYLTabBarControllerExtention.h ================================================ // // UIColor+CYLTabBarControllerExtention.h // CYLTabBarController // // v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 16/2/26. // Copyright © 2019年 https://github.com/ChenYilong .All rights reserved. // #import #import "CYLConstants.h" NS_ASSUME_NONNULL_BEGIN @interface UIColor (CYLTabBarControllerExtention) @property (class, nonatomic, readonly) UIColor *cyl_systemRedColor; @property (class, nonatomic, readonly) UIColor *cyl_systemGreenColor; @property (class, nonatomic, readonly) UIColor *cyl_systemBlueColor; @property (class, nonatomic, readonly) UIColor *cyl_systemOrangeColor; @property (class, nonatomic, readonly) UIColor *cyl_systemYellowColor; @property (class, nonatomic, readonly) UIColor *cyl_systemPinkColor; @property (class, nonatomic, readonly) UIColor *cyl_systemPurpleColor; @property (class, nonatomic, readonly) UIColor *cyl_systemTealColor; @property (class, nonatomic, readonly) UIColor *cyl_systemIndigoColor; /* Shades of gray. systemGray is the base gray color. */ @property (class, nonatomic, readonly) UIColor *cyl_systemGrayColor; @property (class, nonatomic, readonly) UIColor *cyl_systemGray2Color; @property (class, nonatomic, readonly) UIColor *cyl_systemGray3Color; @property (class, nonatomic, readonly) UIColor *cyl_systemGray4Color; @property (class, nonatomic, readonly) UIColor *cyl_systemGray5Color; @property (class, nonatomic, readonly) UIColor *cyl_systemGray6Color; #pragma mark Foreground colors /* Foreground colors for static text and related elements. */ @property (class, nonatomic, readonly) UIColor *cyl_labelColor; @property (class, nonatomic, readonly) UIColor *cyl_secondaryLabelColor; @property (class, nonatomic, readonly) UIColor *cyl_tertiaryLabelColor ; @property (class, nonatomic, readonly) UIColor *cyl_quaternaryLabelColor; /* Foreground color for standard system links. */ @property (class, nonatomic, readonly) UIColor *cyl_linkColor; /* Foreground color for placeholder text in controls or text fields or text views. */ @property (class, nonatomic, readonly) UIColor *cyl_placeholderTextColor; /* Foreground colors for separators (thin border or divider lines). * `separatorColor` may be partially transparent, so it can go on top of any content. * `opaqueSeparatorColor` is intended to look similar, but is guaranteed to be opaque, so it will * completely cover anything behind it. Depending on the situation, you may need one or the other. */ @property (class, nonatomic, readonly) UIColor *cyl_separatorColor; @property (class, nonatomic, readonly) UIColor *cyl_opaqueSeparatorColor; #pragma mark Background colors /* We provide two design systems (also known as "stacks") for structuring an iOS app's backgrounds. * * Each stack has three "levels" of background colors. The first color is intended to be the * main background, farthest back. Secondary and tertiary colors are layered on top * of the main background, when appropriate. * * Inside of a discrete piece of UI, choose a stack, then use colors from that stack. * We do not recommend mixing and matching background colors between stacks. * The foreground colors above are designed to work in both stacks. * * 1. systemBackground * Use this stack for views with standard table views, and designs which have a white * primary background in light mode. */ @property (class, nonatomic, readonly) UIColor *cyl_systemBackgroundColor; @property (class, nonatomic, readonly) UIColor *cyl_secondarySystemBackgroundColor; @property (class, nonatomic, readonly) UIColor *cyl_tertiarySystemBackgroundColor; /* 2. systemGroupedBackground * Use this stack for views with grouped content, such as grouped tables and * platter-based designs. These are like grouped table views, but you may use these * colors in places where a table view wouldn't make sense. */ @property (class, nonatomic, readonly) UIColor *cyl_systemGroupedBackgroundColor; @property (class, nonatomic, readonly) UIColor *cyl_secondarySystemGroupedBackgroundColor; @property (class, nonatomic, readonly) UIColor *cyl_tertiarySystemGroupedBackgroundColor; #pragma mark Fill colors /* Fill colors for UI elements. * These are meant to be used over the background colors, since their alpha component is less than 1. * * systemFillColor is appropriate for filling thin and small shapes. * Example: The track of a slider. */ @property (class, nonatomic, readonly) UIColor *cyl_systemFillColor; /* secondarySystemFillColor is appropriate for filling medium-size shapes. * Example: The background of a switch. */ @property (class, nonatomic, readonly) UIColor *cyl_secondarySystemFillColor; /* tertiarySystemFillColor is appropriate for filling large shapes. * Examples: Input fields, search bars, buttons. */ @property (class, nonatomic, readonly) UIColor *cyl_tertiarySystemFillColor; /* quaternarySystemFillColor is appropriate for filling large areas containing complex content. * Example: Expanded table cells. */ @property (class, nonatomic, readonly) UIColor *cyl_quaternarySystemFillColor; #pragma mark Other colors /* lightTextColor is always light, and darkTextColor is always dark, regardless of the current UIUserInterfaceStyle. * When possible, we recommend using `labelColor` and its variants, instead. */ @property(class, nonatomic, readonly) UIColor *cyl_lightTextColor; // for a dark background @property(class, nonatomic, readonly) UIColor *cyl_darkTextColor; // for a light background @end #pragma mark - Deprecated API @interface UIColor (CYLTabBarControllerDeprecated) @property (class, nonatomic, readonly) UIColor *cyl_systemBrownColor CYL_DEPRECATED("Deprecated in 1.27.5."); @end NS_ASSUME_NONNULL_END ================================================ FILE: CYLTabBarController/UIColor+CYLTabBarControllerExtention.m ================================================ // // UIColor+CYLTabBarControllerExtention.h // CYLTabBarController // // v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 16/2/26. // Copyright © 2019年 https://github.com/ChenYilong .All rights reserved. // #import "UIColor+CYLTabBarControllerExtention.h" @implementation UIColor (CYLTabBarControllerExtention) + (UIColor *)cyl_systemRedColor { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 if (@available(iOS 13.0, *)) { #if __has_include() return [UIColor systemRedColor]; #else #endif } #endif return [UIColor colorWithRed:1.0 green:0.23137254901960785 blue:0.18823529411764706 alpha:1.0 ]; } + (UIColor *)cyl_systemGreenColor { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 if (@available(iOS 13.0, *)) { #if __has_include() return [UIColor systemGreenColor]; #else #endif } #endif return [UIColor colorWithRed:0.20392156862745098 green:0.7803921568627451 blue:0.34901960784313724 alpha:1.0 ]; } + (UIColor *)cyl_systemBlueColor { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 if (@available(iOS 13.0, *)) { #if __has_include() return [UIColor systemBlueColor]; #else #endif } #endif return [UIColor colorWithRed:0.0 green:0.47843137254901963 blue:1.0 alpha:1.0 ]; } + (UIColor *)cyl_systemOrangeColor { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 if (@available(iOS 13.0, *)) { #if __has_include() return [UIColor systemOrangeColor]; #else #endif } #endif return [UIColor colorWithRed:1.0 green:0.5843137254901961 blue:0.0 alpha:1.0 ]; } + (UIColor *)cyl_systemYellowColor { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 if (@available(iOS 13.0, *)) { #if __has_include() return [UIColor systemYellowColor]; #else #endif } #endif return [UIColor colorWithRed:1.0 green:0.8 blue:0.0 alpha:1.0 ]; } + (UIColor *)cyl_systemPinkColor { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 if (@available(iOS 13.0, *)) { #if __has_include() return [UIColor systemPinkColor]; #else #endif } #endif return [UIColor colorWithRed:1.0 green:0.17647058823529413 blue:0.3333333333333333 alpha:1.0 ]; } + (UIColor *)cyl_systemPurpleColor { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 if (@available(iOS 13.0, *)) { #if __has_include() return [UIColor systemPurpleColor]; #else #endif } #endif return [UIColor colorWithRed:0.6862745098039216 green:0.3215686274509804 blue:0.8705882352941177 alpha:1.0 ]; } + (UIColor *)cyl_systemTealColor { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 if (@available(iOS 13.0, *)) { #if __has_include() return [UIColor systemTealColor]; #else #endif } #endif return [UIColor colorWithRed:0.35294117647058826 green:0.7843137254901961 blue:0.9803921568627451 alpha:1.0 ]; } + (UIColor *)cyl_systemIndigoColor { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 if (@available(iOS 13.0, *)) { #if __has_include() return [UIColor systemIndigoColor]; #else #endif } #endif return [UIColor colorWithRed:0.34509803921568627 green:0.33725490196078434 blue:0.8392156862745098 alpha:1.0 ]; } + (UIColor *)cyl_systemGrayColor { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 if (@available(iOS 13.0, *)) { #if __has_include() return [UIColor systemGrayColor]; #else #endif } #endif return [UIColor colorWithRed:0.5568627450980392 green:0.5568627450980392 blue:0.5764705882352941 alpha:1.0 ]; } + (UIColor *)cyl_systemGray2Color { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 if (@available(iOS 13.0, *)) { #if __has_include() return [UIColor systemGray2Color]; #else #endif } #endif return [UIColor colorWithRed:0.6823529411764706 green:0.6823529411764706 blue:0.6980392156862745 alpha:1.0 ]; } + (UIColor *)cyl_systemGray3Color { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 if (@available(iOS 13.0, *)) { #if __has_include() return [UIColor systemGray3Color]; #else #endif } #endif return [UIColor colorWithRed:0.7803921568627451 green:0.7803921568627451 blue:0.8 alpha:1.0 ]; } + (UIColor *)cyl_systemGray4Color { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 if (@available(iOS 13.0, *)) { #if __has_include() return [UIColor systemGray4Color]; #else #endif } #endif return [UIColor colorWithRed:0.8196078431372549 green:0.8196078431372549 blue:0.8392156862745098 alpha:1.0 ]; } + (UIColor *)cyl_systemGray5Color { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 if (@available(iOS 13.0, *)) { #if __has_include() return [UIColor systemGray5Color]; #else #endif } #endif return [UIColor colorWithRed:0.8980392156862745 green:0.8980392156862745 blue:0.9176470588235294 alpha:1.0 ]; } + (UIColor *)cyl_systemGray6Color { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 if (@available(iOS 13.0, *)) { #if __has_include() return [UIColor systemGray6Color]; #else #endif } #endif return [UIColor colorWithRed:0.9490196078431372 green:0.9490196078431372 blue:0.9686274509803922 alpha:1.0 ]; } #pragma mark Foreground colors + (UIColor *)cyl_labelColor { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 if (@available(iOS 13.0, *)) { #if __has_include() return [UIColor labelColor]; #else #endif } #endif return [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:1.0 ]; } + (UIColor *)cyl_secondaryLabelColor { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 if (@available(iOS 13.0, *)) { #if __has_include() return [UIColor secondaryLabelColor]; #else #endif } #endif return [UIColor colorWithRed:0.23529411764705882 green:0.23529411764705882 blue:0.2627450980392157 alpha:0.6 ]; } + (UIColor *)cyl_tertiaryLabelColor { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 #endif if (@available(iOS 13.0, *)) { #if __has_include() return [UIColor tertiaryLabelColor]; #else #endif } return [UIColor colorWithRed:0.23529411764705882 green:0.23529411764705882 blue:0.2627450980392157 alpha:0.3 ]; } + (UIColor *)cyl_quaternaryLabelColor { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 if (@available(iOS 13.0, *)) { #if __has_include() return [UIColor quaternaryLabelColor]; #else #endif } #endif return [UIColor colorWithRed:0.23529411764705882 green:0.23529411764705882 blue:0.2627450980392157 alpha:0.18 ]; } /* Foreground color for standard system links. */ + (UIColor *)cyl_linkColor { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 if (@available(iOS 13.0, *)) { #if __has_include() return [UIColor linkColor]; #else #endif } #endif return [UIColor colorWithRed:0.0 green:0.47843137254901963 blue:1.0 alpha:1.0 ]; } + (UIColor *)cyl_placeholderTextColor { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 if (@available(iOS 13.0, *)) { #if __has_include() return [UIColor placeholderTextColor]; #else #endif } #endif return [UIColor colorWithRed:0.23529411764705882 green:0.23529411764705882 blue:0.2627450980392157 alpha:0.3 ]; } + (UIColor *)cyl_separatorColor { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 if (@available(iOS 13.0, *)) { #if __has_include() return [UIColor separatorColor]; #else #endif } #endif return [UIColor colorWithRed:0.23529411764705882 green:0.23529411764705882 blue:0.2627450980392157 alpha:0.29 ]; } + (UIColor *)cyl_opaqueSeparatorColor { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 if (@available(iOS 13.0, *)) { #if __has_include() return [UIColor opaqueSeparatorColor]; #else #endif } #endif return [UIColor colorWithRed:0.7764705882352941 green:0.7764705882352941 blue:0.7843137254901961 alpha:1.0 ]; } #pragma mark Background colors + (UIColor *)cyl_systemBackgroundColor { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 if (@available(iOS 13.0, *)) { #if __has_include() return [UIColor systemBackgroundColor]; #else #endif } #endif return [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0 ]; } + (UIColor *)cyl_secondarySystemBackgroundColor { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 if (@available(iOS 13.0, *)) { #if __has_include() return [UIColor secondarySystemBackgroundColor]; #else #endif } #endif return [UIColor colorWithRed:0.9490196078431372 green:0.9490196078431372 blue:0.9686274509803922 alpha:1.0 ]; } + (UIColor *)cyl_tertiarySystemBackgroundColor { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 if (@available(iOS 13.0, *)) { #if __has_include() return [UIColor tertiarySystemBackgroundColor]; #else #endif } #endif return [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0 ]; } + (UIColor *)cyl_systemGroupedBackgroundColor { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 if (@available(iOS 13.0, *)) { #if __has_include() return [UIColor systemGroupedBackgroundColor]; #else #endif } #endif return [UIColor colorWithRed:0.9490196078431372 green:0.9490196078431372 blue:0.9686274509803922 alpha:1.0 ]; } + (UIColor *)cyl_secondarySystemGroupedBackgroundColor { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 if (@available(iOS 13.0, *)) { #if __has_include() return [UIColor secondarySystemGroupedBackgroundColor]; #else #endif } #endif return [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0 ]; } + (UIColor *)cyl_tertiarySystemGroupedBackgroundColor { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 if (@available(iOS 13.0, *)) { #if __has_include() return [UIColor tertiarySystemGroupedBackgroundColor]; #else #endif } #endif return [UIColor colorWithRed:0.9490196078431372 green:0.9490196078431372 blue:0.9686274509803922 alpha:1.0 ]; } #pragma mark Fill colors + (UIColor *)cyl_systemFillColor { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 if (@available(iOS 13.0, *)) { #if __has_include() return [UIColor systemFillColor]; #else #endif } #endif return [UIColor colorWithRed:0.47058823529411764 green:0.47058823529411764 blue:0.5019607843137255 alpha:0.2 ]; } + (UIColor *)cyl_secondarySystemFillColor { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 if (@available(iOS 13.0, *)) { #if __has_include() return [UIColor secondarySystemFillColor]; #else #endif } #endif return [UIColor colorWithRed:0.47058823529411764 green:0.47058823529411764 blue:0.5019607843137255 alpha:0.16 ]; } + (UIColor *)cyl_tertiarySystemFillColor { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 if (@available(iOS 13.0, *)) { #if __has_include() return [UIColor tertiarySystemFillColor]; #else #endif } #endif return [UIColor colorWithRed:0.4627450980392157 green:0.4627450980392157 blue:0.5019607843137255 alpha:0.12 ]; } + (UIColor *)cyl_quaternarySystemFillColor { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 if (@available(iOS 13.0, *)) { #if __has_include() return [UIColor quaternarySystemFillColor]; #else #endif } #endif return [UIColor colorWithRed:0.4549019607843137 green:0.4549019607843137 blue:0.5019607843137255 alpha:0.08 ]; } #pragma mark Other colors + (UIColor *)cyl_lightTextColor { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 if (@available(iOS 13.0, *)) { #if __has_include() return [UIColor lightTextColor]; #else #endif } #endif return [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:0.6 ]; } + (UIColor *)cyl_darkTextColor { #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 if (@available(iOS 13.0, *)) { #if __has_include() return [UIColor darkTextColor]; #else #endif } #endif return [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:1.0 ]; } #pragma mark - Deprecated API //Apple remove this API in iOS13 beta 2 + (UIColor *)cyl_systemBrownColor { return nil; } @end ================================================ FILE: CYLTabBarController/UIControl+CYLTabBarControllerExtention.h ================================================ // // CYLTabBarController.m // CYLTabBarController // // v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/20/15. // Copyright © 2018 https://github.com/ChenYilong . All rights reserved. // #import NS_ASSUME_NONNULL_BEGIN @class LOTAnimationView; @interface UIControl (CYLTabBarControllerExtention) - (LOTAnimationView *)cyl_lottieAnimationView; - (BOOL)cyl_isChildViewControllerPlusButton; /*! * 调用该方法前已经添加了系统的角标,调用该方法后,系统的角标并未被移除,只是被隐藏,调用 `-cyl_removeTabBadgePoint` 后会重新展示。 */ - (void)cyl_showTabBadgePoint; - (void)cyl_removeTabBadgePoint; - (BOOL)cyl_isShowTabBadgePoint; - (BOOL)cyl_isSelected; @property (nonatomic, strong, setter=cyl_setTabBadgePointView:, getter=cyl_tabBadgePointView) UIView *cyl_tabBadgePointView; @property (nonatomic, assign, setter=cyl_setTabBadgePointViewOffset:, getter=cyl_tabBadgePointViewOffset) UIOffset cyl_tabBadgePointViewOffset; /*! * PlusButton without plusViewController equals NSNotFound */ @property (nonatomic, assign, getter=cyl_tabBarChildViewControllerIndex, setter=cyl_setTabBarChildViewControllerIndex:) NSInteger cyl_tabBarChildViewControllerIndex; /*! * PlusButton has its own visible index, * in this case PlusButton is same as TabBarItem */ @property (nonatomic, assign, getter=cyl_tabBarItemVisibleIndex, setter=cyl_setTabBarItemVisibleIndex:) NSInteger cyl_tabBarItemVisibleIndex; @property (nonatomic, assign, getter=cyl_shouldNotSelect, setter=cyl_setShouldNotSelect:) BOOL cyl_shouldNotSelect; - (void)cyl_addLottieImageWithLottieURL:(NSURL *)lottieURL size:(CGSize)size; - (void)cyl_replaceTabImageViewWithNewView:(UIView *)newView show:(BOOL)show; - (void)cyl_replaceTabImageViewWithNewView:(UIView *)newView offset:(UIOffset)offset show:(BOOL)show completion:(void(^)(BOOL isReplaced, UIControl *tabBarButton, UIView *newView))completion; - (void)cyl_replaceTabButtonWithNewView:(UIView *)newView show:(BOOL)show; - (void)cyl_replaceTabButtonWithNewView:(UIView *)newView offset:(UIOffset)offset show:(BOOL)theShow completion:(void(^)(BOOL isReplaced, UIControl *tabBarButton, UIView *newView))completion; @end NS_ASSUME_NONNULL_END ================================================ FILE: CYLTabBarController/UIControl+CYLTabBarControllerExtention.m ================================================ // // CYLTabBarController.m // CYLTabBarController // // v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/20/15. // Copyright © 2018 https://github.com/ChenYilong . All rights reserved. // #import "UIControl+CYLTabBarControllerExtention.h" #import #import "UIView+CYLTabBarControllerExtention.h" #import "CYLConstants.h" #import "CYLTabBarController.h" #if __has_include() #import #else #endif @implementation UIControl (CYLTabBarControllerExtention) - (BOOL)cyl_isChildViewControllerPlusButton { BOOL isChildViewControllerPlusButton = ([self cyl_isPlusButton] && CYLPlusChildViewController.cyl_plusViewControllerEverAdded); return isChildViewControllerPlusButton; } - (BOOL)cyl_shouldNotSelect { NSNumber *shouldNotSelectObject = objc_getAssociatedObject(self, @selector(cyl_shouldNotSelect)); return [shouldNotSelectObject boolValue]; } - (void)cyl_setShouldNotSelect:(BOOL)shouldNotSelect { NSNumber *shouldNotSelectObject = @(shouldNotSelect); objc_setAssociatedObject(self, @selector(cyl_shouldNotSelect), shouldNotSelectObject, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (NSInteger)cyl_tabBarItemVisibleIndex { if (!self.cyl_isTabButton && !self.cyl_isPlusButton ) { return NSNotFound; } NSNumber *tabBarItemVisibleIndexObject = objc_getAssociatedObject(self, @selector(cyl_tabBarItemVisibleIndex)); return [tabBarItemVisibleIndexObject integerValue]; } - (void)cyl_setTabBarItemVisibleIndex:(NSInteger)tabBarItemVisibleIndex { NSNumber *tabBarItemVisibleIndexObject = [NSNumber numberWithInteger:tabBarItemVisibleIndex]; objc_setAssociatedObject(self, @selector(cyl_tabBarItemVisibleIndex), tabBarItemVisibleIndexObject, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (NSInteger)cyl_tabBarChildViewControllerIndex { if (!self.cyl_isTabButton && !self.cyl_isPlusButton ) { return NSNotFound; } NSNumber *tabBarChildViewControllerIndexObject = objc_getAssociatedObject(self, @selector(cyl_tabBarChildViewControllerIndex)); return [tabBarChildViewControllerIndexObject integerValue]; } - (void)cyl_setTabBarChildViewControllerIndex:(NSInteger)tabBarChildViewControllerIndex { NSNumber *tabBarChildViewControllerIndexObject = [NSNumber numberWithInteger:tabBarChildViewControllerIndex]; objc_setAssociatedObject(self, @selector(cyl_tabBarChildViewControllerIndex), tabBarChildViewControllerIndexObject, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (void)cyl_showTabBadgePoint { [self cyl_setShowTabBadgePointIfNeeded:YES]; } - (void)cyl_removeTabBadgePoint { [self cyl_setShowTabBadgePointIfNeeded:NO]; } - (BOOL)cyl_isShowTabBadgePoint { return !self.cyl_tabBadgePointView.hidden; } - (BOOL)cyl_isSelected { NSUInteger tabBarSelectedIndex = self.cyl_tabBarController.selectedIndex; NSUInteger tabBarChildViewControllerIndex = self.cyl_tabBarChildViewControllerIndex; BOOL isSelected = (tabBarSelectedIndex == tabBarChildViewControllerIndex) && self.selected; if (self.cyl_tabBarController.tabBar.cyl_hasPlusChildViewController) { isSelected = isSelected && CYLPlusChildViewController.cyl_plusViewControllerEverAdded; } return isSelected; } - (void)cyl_setShowTabBadgePointIfNeeded:(BOOL)showTabBadgePoint { @try { [self cyl_setShowTabBadgePoint:showTabBadgePoint]; } @catch (NSException *exception) { NSLog(@"CYLPlusChildViewController do not support set TabBarItem red point"); } } - (void)cyl_setShowTabBadgePoint:(BOOL)showTabBadgePoint { if (showTabBadgePoint && self.cyl_tabBadgePointView.superview == nil) { [self addSubview:self.cyl_tabBadgePointView]; [self bringSubviewToFront:self.cyl_tabBadgePointView]; self.cyl_tabBadgePointView.layer.zPosition = MAXFLOAT; // X constraint [self addConstraint: [NSLayoutConstraint constraintWithItem:self.cyl_tabBadgePointView attribute:NSLayoutAttributeCenterX relatedBy:0 toItem:self.cyl_tabImageView attribute:NSLayoutAttributeRight multiplier:1 constant:self.cyl_tabBadgePointViewOffset.horizontal]]; //Y constraint [self addConstraint: [NSLayoutConstraint constraintWithItem:self.cyl_tabBadgePointView attribute:NSLayoutAttributeCenterY relatedBy:0 toItem:self.cyl_tabImageView attribute:NSLayoutAttributeTop multiplier:1 constant:self.cyl_tabBadgePointViewOffset.vertical]]; } self.cyl_tabBadgePointView.hidden = showTabBadgePoint == NO; self.cyl_tabBadgeView.hidden = showTabBadgePoint == YES; } - (void)cyl_setTabBadgePointView:(UIView *)tabBadgePointView { UIView *tempView = objc_getAssociatedObject(self, @selector(cyl_tabBadgePointView)); if (tempView) { [tempView removeFromSuperview]; } if (tabBadgePointView.superview) { [tabBadgePointView removeFromSuperview]; } tabBadgePointView.hidden = YES; objc_setAssociatedObject(self, @selector(cyl_tabBadgePointView), tabBadgePointView, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (UIView *)cyl_tabBadgePointView { UIView *tabBadgePointView = objc_getAssociatedObject(self, @selector(cyl_tabBadgePointView)); if (tabBadgePointView == nil) { tabBadgePointView = self.cyl_defaultTabBadgePointView; objc_setAssociatedObject(self, @selector(cyl_tabBadgePointView), tabBadgePointView, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } return tabBadgePointView; } - (void)cyl_setTabBadgePointViewOffset:(UIOffset)tabBadgePointViewOffset { objc_setAssociatedObject(self, @selector(cyl_tabBadgePointViewOffset), [NSValue valueWithUIOffset:tabBadgePointViewOffset], OBJC_ASSOCIATION_RETAIN_NONATOMIC); } //offset如果都是正数,则往右下偏移 - (UIOffset)cyl_tabBadgePointViewOffset { id tabBadgePointViewOffsetObject = objc_getAssociatedObject(self, @selector(cyl_tabBadgePointViewOffset)); UIOffset tabBadgePointViewOffset = [tabBadgePointViewOffsetObject UIOffsetValue]; return tabBadgePointViewOffset; } - (LOTAnimationView *)cyl_lottieAnimationView { for (UILabel *subview in self.subviews) { if ([subview cyl_isLottieAnimationView]) { return (LOTAnimationView *)subview; } } return nil; } - (void)cyl_replaceTabImageViewWithNewView:(UIView *)newView show:(BOOL)show { [self cyl_replaceTabImageViewWithNewView:newView offset:UIOffsetZero show:show completion:^(BOOL isReplaced, UIControl *tabBarButton, UIView *newView) { }]; } - (void)cyl_replaceTabImageViewWithNewView:(UIView *)newView offset:(UIOffset)offset show:(BOOL)theShow completion:(void(^)(BOOL isReplaced, UIControl *tabBarButton, UIView *newView))completion { [self cyl_replaceTabImageViewOrTabButton:NO newView:newView offset:offset show:theShow completion:completion]; } - (void)cyl_replaceTabButtonWithNewView:(UIView *)newView offset:(UIOffset)offset show:(BOOL)theShow completion:(void(^)(BOOL isReplaced, UIControl *tabBarButton, UIView *newView))completion { [self cyl_replaceTabImageViewOrTabButton:YES newView:newView offset:offset show:theShow completion:completion]; } - (void)cyl_replaceTabButtonWithNewView:(UIView *)newView show:(BOOL)show { [self cyl_replaceTabButtonWithNewView:newView offset:UIOffsetZero show:show completion:^(BOOL isReplaced, UIControl *tabBarButton, UIView *newView) { }]; } - (void)cyl_replaceTabImageViewOrTabButton:(BOOL)isTabButton newView:(UIView *)newView offset:(UIOffset)offset show:(BOOL)theShow completion:(void(^)(BOOL isReplaced, UIControl *tabBarButton, UIView *newView))completion { UIControl *tabBarButton = self; UIImageView *swappableImageView = tabBarButton.cyl_tabImageView; UIView *replacedView = swappableImageView; if (isTabButton) { replacedView = tabBarButton; } if (!replacedView) { return; } if (newView.frame.size.width == 0 || newView.frame.size.height == 0 || newView.frame.size.width > tabBarButton.frame.size.width || newView.frame.size.height > tabBarButton.frame.size.height) { UIImage *image = swappableImageView.image; newView.frame = ({ CGRect frame = newView.frame; frame.size = CGSizeMake(image.size.width, image.size.height); frame; }); } BOOL newViewCreated = (newView.superview); BOOL newViewAddedToTabButton = [self.subviews containsObject:newView]; BOOL isNewViewAddedToTabButton = newViewCreated && newViewAddedToTabButton; if (newView.superview && !newViewAddedToTabButton) { [newView removeFromSuperview]; } if (isNewViewAddedToTabButton && theShow) { !completion?:completion(YES, self, newView); return; } BOOL show = (newView && theShow); swappableImageView.hidden = (show); if (isTabButton) { tabBarButton.cyl_tabLabel.hidden = show; } BOOL shouldShowNewView = show && !newView.superview; BOOL shouldRemoveNewView = newView.superview; if (shouldShowNewView) { [tabBarButton addSubview:newView]; [tabBarButton bringSubviewToFront:newView]; CGSize newViewSize = newView.frame.size; if (@available(iOS 9.0, *)) { [NSLayoutConstraint activateConstraints:@[ [newView.centerXAnchor constraintEqualToAnchor:swappableImageView.centerXAnchor constant:offset.horizontal], [newView.centerYAnchor constraintEqualToAnchor:replacedView.centerYAnchor constant:offset.vertical], [newView.widthAnchor constraintEqualToConstant:newViewSize.width], [newView.heightAnchor constraintEqualToConstant:newViewSize.height], ] ]; } else { [self addConstraints:@[ [NSLayoutConstraint constraintWithItem:newView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:swappableImageView attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:offset.horizontal], [NSLayoutConstraint constraintWithItem:newView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:replacedView attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:offset.vertical], [NSLayoutConstraint constraintWithItem:newView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:replacedView attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:offset.vertical], [NSLayoutConstraint constraintWithItem:newView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:newViewSize.width], [NSLayoutConstraint constraintWithItem:newView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:newViewSize.height] ]]; } !completion?:completion(YES, self, newView); return; } if (shouldRemoveNewView) { [newView removeFromSuperview]; newView = nil; !completion?:completion(NO, self, nil); return; } } - (void)cyl_addLottieImageWithLottieURL:(NSURL *)lottieURL size:(CGSize)size { #if __has_include() if (self.cyl_lottieAnimationView) { return; } UIControl *tabButton = self; LOTAnimationView *lottieView = [[LOTAnimationView alloc] initWithContentsOfURL:lottieURL]; lottieView.frame = CGRectMake(0, 0, size.width, size.height); lottieView.userInteractionEnabled = NO; lottieView.contentMode = UIViewContentModeScaleAspectFill; lottieView.translatesAutoresizingMaskIntoConstraints = NO; [lottieView setClipsToBounds:NO]; [tabButton cyl_replaceTabImageViewWithNewView:lottieView show:YES]; #else #endif } #pragma mark - private method - (UIView *)cyl_defaultTabBadgePointView { UIView *defaultRedTabBadgePointView = [UIView cyl_tabBadgePointViewWithClolor:[UIColor redColor] radius:4.5]; return defaultRedTabBadgePointView; } @end ================================================ FILE: CYLTabBarController/UIImage+CYLTabBarControllerExtention.h ================================================ // // UIImage+CYLTabBarControllerExtention.h // CYLTabBarController // // Created by chenyilong on 18/4/2019. // Copyright © 2019 微博@iOS程序犭袁. All rights reserved. // #import NS_ASSUME_NONNULL_BEGIN @interface UIImage (CYLTabBarControllerExtention) + (UIImage *)cyl_imageWithColor:(UIColor *)color size:(CGSize)size; @end NS_ASSUME_NONNULL_END ================================================ FILE: CYLTabBarController/UIImage+CYLTabBarControllerExtention.m ================================================ // // UIImage+CYLTabBarControllerExtention.m // CYLTabBarController // // Created by chenyilong on 18/4/2019. // Copyright © 2019 微博@iOS程序犭袁. All rights reserved. // #import "UIImage+CYLTabBarControllerExtention.h" @implementation UIImage (CYLTabBarControllerExtention) + (UIImage *)cyl_imageWithColor:(UIColor *)color size:(CGSize)size { if (!color || size.width <= 0 || size.height <= 0) return nil; CGRect rect = CGRectMake(0.0f, 0.0f, size.width, size.height); UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0); CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetFillColorWithColor(context, color.CGColor); CGContextFillRect(context, rect); UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return [image imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; } + (UIImage *)cyl_assetImageName:(NSString *)assetImageName userInterfaceStyle:(NSInteger)userInterfaceStyle { UIImage *image = [UIImage imageNamed:@"image"]; #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 if (@available(iOS 13.0, *)) { #if __has_include() UITraitCollection *trait; // UIUserInterfaceStyle currentUserInterfaceStyle = [UITraitCollection currentTraitCollection].userInterfaceStyle; // if (currentUserInterfaceStyle == UIUserInterfaceStyleUnspecified) { // currentUserInterfaceStyle == userInterfaceStyle; // } trait = [UITraitCollection traitCollectionWithUserInterfaceStyle:userInterfaceStyle]; image = [image.imageAsset imageWithTraitCollection:trait]; //TODO: return image; #else #endif } #endif return image; } + (UIImage *)cyl_lightOrDarkModeImageWithLightImage:(UIImage *)lightImage darkImage:(UIImage *)darkImage { return [self cyl_lightOrDarkModeImageWithOwner:nil lightImage:lightImage darkImage:darkImage]; } + (UIImage *)cyl_lightOrDarkModeImageWithOwner:(id)owner lightImageName:(NSString *)lightImageName darkImageName:(NSString *)darkImageName { UIImage *lightImage = [UIImage imageNamed:lightImageName]; UIImage *darkImage= [UIImage imageNamed:darkImageName]; UIImage *lightOrDarkImage = [UIImage cyl_lightOrDarkModeImageWithOwner:owner lightImage:lightImage darkImage:darkImage]; return lightOrDarkImage; } + (UIImage *)cyl_lightOrDarkModeImageWithOwner:(id)owner lightImage:(UIImage *)lightImage darkImage:(UIImage *)darkImage { BOOL isDarkImage = NO; #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 if (@available(iOS 13.0, *)) { #if __has_include() //TODO: UITraitCollection *traitCollection = owner.traitCollection ?: [UITraitCollection currentTraitCollection]; UIUserInterfaceStyle userInterfaceStyle = traitCollection.userInterfaceStyle; isDarkImage = (userInterfaceStyle == UIUserInterfaceStyleDark); #else #endif } #endif UIImage *image = (isDarkImage ? darkImage : lightImage); return image; } @end ================================================ FILE: CYLTabBarController/UITabBarItem+CYLBadgeExtention.h ================================================ /* //  CYLTabBarController //  CYLTabBarController // //  Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 03/06/19. //  Copyright © 2019 https://github.com/ChenYilong . All rights reserved. */ #import #import "UIView+CYLBadgeExtention.h" #import "CYLBadgeProtocol.h" NS_ASSUME_NONNULL_BEGIN @interface UITabBarItem (CYLBadgeExtention) - (BOOL)cyl_isShowBadge; /** * show badge with red dot style and CYLBadgeAnimationTypeNone by default. */ - (void)cyl_showBadge; /** * * @param value String value, default is `nil`. if value equal @"" means red dot style. * @param animationType animationType * @attention - 调用该方法前已经添加了系统的角标,调用该方法后,系统的角标并未被移除,只是被隐藏,调用 `-cyl_removeTabBadgePoint` 后会重新展示。 - 不支持 CYLPlusChildViewController 对应的 TabBarItem 角标设置,调用会被忽略。 */ - (void)cyl_showBadgeValue:(NSString *)value animationType:(CYLBadgeAnimationType)animationType; /** * clear badge(hide badge) */ - (void)cyl_clearBadge; /** * make bage(if existing) not hiden */ - (void)cyl_resumeBadge; - (BOOL)cyl_isPauseBadge; @end NS_ASSUME_NONNULL_END ================================================ FILE: CYLTabBarController/UITabBarItem+CYLBadgeExtention.m ================================================ /* //  CYLTabBarController //  CYLTabBarController // //  Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 03/06/19. //  Copyright © 2019 https://github.com/ChenYilong . All rights reserved. */ #import "UITabBarItem+CYLBadgeExtention.h" #import "CYLTabBarController.h" #import #define kActualView [self cyl_getActualBadgeSuperView] @implementation UITabBarItem (CYLBadgeExtention) + (void)load { [self cyl_swizzleSetBadgeValue]; } + (void)cyl_swizzleSetBadgeValue { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ cyl_ClassMethodSwizzle([self class], @selector(setBadgeValue:), @selector(cyl_setBadgeValue:)); }); } - (void)cyl_setBadgeValue:(NSString *)badgeValue { [self.cyl_tabButton cyl_removeTabBadgePoint]; [self cyl_clearBadge]; [self cyl_setBadgeValue:badgeValue]; } #pragma mark -- public methods /** * show badge with red dot style and CYLBadgeAnimationTypeNone by default. */ - (void)cyl_showBadge { [kActualView cyl_showBadgeValue:@"" animationType:CYLBadgeAnimationTypeNone]; } - (void)cyl_showBadgeValue:(NSString *)value animationType:(CYLBadgeAnimationType)animationType { [kActualView cyl_showBadgeValue:value animationType:animationType]; self.cyl_tabButton.cyl_tabBadgeView.hidden = YES; } - (BOOL)cyl_isShowBadge { return [kActualView cyl_isShowBadge]; } - (BOOL)cyl_isPauseBadge { return [kActualView cyl_isPauseBadge]; } /** * clear badge */ - (void)cyl_clearBadge { [kActualView cyl_clearBadge]; self.cyl_tabButton.cyl_tabBadgeView.hidden = NO; } - (void)cyl_resumeBadge { [kActualView cyl_resumeBadge]; self.cyl_tabButton.cyl_tabBadgeView.hidden = YES; } #pragma mark -- private method /** * Because UIBarButtonItem is kind of NSObject, it is not able to directly attach badge. This method is used to find actual view (non-nil) inside UIBarButtonItem instance. * * @return view */ - (UIView *)cyl_getActualBadgeSuperView { UIControl *tabButton = [self cyl_tabButton]; // badge label will be added onto imageView UIImageView *tabImageView = [tabButton cyl_tabImageView]; UIView *lottieAnimationView = (UIView *)tabButton.cyl_lottieAnimationView ; UIView *actualBadgeSuperView = tabImageView; do { if (tabImageView && !tabImageView.cyl_isInvisiable) { actualBadgeSuperView = tabImageView; break; } if (lottieAnimationView && !lottieAnimationView.cyl_isInvisiable) { actualBadgeSuperView = lottieAnimationView; break; } } while (NO); [lottieAnimationView setClipsToBounds:NO]; return actualBadgeSuperView; } #pragma mark -- setter/getter - (UILabel *)cyl_badge { return kActualView.cyl_badge; } - (void)cyl_setBadge:(UILabel *)label { [kActualView cyl_setBadge:label]; } - (UIFont *)cyl_badgeFont { return kActualView.cyl_badgeFont; } - (void)cyl_setBadgeFont:(UIFont *)badgeFont { [kActualView cyl_setBadgeFont:badgeFont]; } - (UIColor *)cyl_badgeBackgroundColor { return [kActualView cyl_badgeBackgroundColor]; } - (void)cyl_setBadgeBackgroundColor:(UIColor *)badgeBackgroundColor { [kActualView cyl_setBadgeBackgroundColor:badgeBackgroundColor]; } - (UIColor *)cyl_badgeTextColor { return [kActualView cyl_badgeTextColor]; } - (void)cyl_setBadgeTextColor:(UIColor *)badgeTextColor { [kActualView cyl_setBadgeTextColor:badgeTextColor]; } - (CYLBadgeAnimationType)cyl_badgeAnimationType { return [kActualView cyl_badgeAnimationType]; } - (void)cyl_setBadgeAnimationType:(CYLBadgeAnimationType)animationType { [kActualView cyl_setBadgeAnimationType:animationType]; } - (CGRect)cyl_badgeFrame { return [kActualView cyl_badgeFrame]; } - (void)cyl_setBadgeFrame:(CGRect)badgeFrame { [kActualView cyl_setBadgeFrame:badgeFrame]; } - (CGPoint)cyl_badgeCenterOffset { return [kActualView cyl_badgeCenterOffset]; } - (void)cyl_setBadgeCenterOffset:(CGPoint)badgeCenterOffset { [kActualView cyl_setBadgeCenterOffset:badgeCenterOffset]; } - (NSInteger)cyl_badgeMaximumBadgeNumber { return [kActualView cyl_badgeMaximumBadgeNumber]; } - (void)cyl_setBadgeMaximumBadgeNumber:(NSInteger)badgeMaximumBadgeNumber { [kActualView cyl_setBadgeMaximumBadgeNumber:badgeMaximumBadgeNumber]; } - (CGFloat)cyl_badgeMargin { return [kActualView cyl_badgeMargin]; } - (void)cyl_setBadgeMargin:(CGFloat)badgeMargin { [kActualView cyl_setBadgeMargin:badgeMargin]; } - (CGFloat)cyl_badgeRadius { return [kActualView cyl_badgeRadius]; } - (void)cyl_setBadgeRadius:(CGFloat)badgeRadius { [kActualView cyl_setBadgeRadius:badgeRadius]; } - (CGFloat)cyl_badgeCornerRadius { return [kActualView cyl_badgeCornerRadius]; } - (void)cyl_setBadgeCornerRadius:(CGFloat)cyl_badgeCornerRadius { [kActualView cyl_setBadgeCornerRadius:cyl_badgeCornerRadius]; } #pragma mark - private method BOOL cyl_ClassMethodSwizzle(Class aClass, SEL originalSelector, SEL swizzleSelector) { Method originalMethod = class_getInstanceMethod(aClass, originalSelector); Method swizzleMethod = class_getInstanceMethod(aClass, swizzleSelector); BOOL didAddMethod = class_addMethod(aClass, originalSelector, method_getImplementation(swizzleMethod), method_getTypeEncoding(swizzleMethod)); if (didAddMethod) { class_replaceMethod(aClass, swizzleSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)); } else { method_exchangeImplementations(originalMethod, swizzleMethod); } return YES; } @end ================================================ FILE: CYLTabBarController/UITabBarItem+CYLTabBarControllerExtention.h ================================================ // // CYLTabBarController.m // CYLTabBarController // // v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/20/15. // Copyright © 2018 https://github.com/ChenYilong . All rights reserved. // #import NS_ASSUME_NONNULL_BEGIN @interface UITabBarItem (CYLTabBarControllerExtention) @property (nonatomic, readonly) UIControl *cyl_tabButton; @end NS_ASSUME_NONNULL_END ================================================ FILE: CYLTabBarController/UITabBarItem+CYLTabBarControllerExtention.m ================================================ // // CYLTabBarController.m // CYLTabBarController // // v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/20/15. // Copyright © 2018 https://github.com/ChenYilong . All rights reserved. // #import "UITabBarItem+CYLTabBarControllerExtention.h" #import "UIControl+CYLTabBarControllerExtention.h" @implementation UITabBarItem (CYLTabBarControllerExtention) - (UIControl *)cyl_tabButton { UIControl *control = [self valueForKeyPath:@"_view"]; return control; } @end ================================================ FILE: CYLTabBarController/UIView+CYLBadgeExtention.h ================================================ /* //  CYLTabBarController //  CYLTabBarController // //  Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 03/06/19. //  Copyright © 2019 https://github.com/ChenYilong . All rights reserved. */ #import #import "CYLBadgeProtocol.h" NS_ASSUME_NONNULL_BEGIN #pragma mark -- badge apis @interface UIView (CYLBadgeExtention) - (BOOL)cyl_isShowBadge; /** * show badge with red dot style and CYLBadgeAnimationTypeNone by default. */ - (void)cyl_showBadge; /** * cyl_showBadge * * @param value String value, default is `nil`. if value equal @"" means red dot style. * @param animationType animationType */ - (void)cyl_showBadgeValue:(NSString *)value animationType:(CYLBadgeAnimationType)animationType; ; // wBadgeStyle default is CYLBadgeStyleNumber ; // CYLBadgeAnimationType defualt is CYLBadgeAnimationTypeNone - (void)cyl_showBadgeValue:(NSString *)value; /** * clear badge(hide badge) */ - (void)cyl_clearBadge; /** * make bage(if existing) not hiden */ - (void)cyl_resumeBadge; - (BOOL)cyl_isPauseBadge; - (BOOL)cyl_isInvisiable; - (BOOL)cyl_canNotResponseEvent; @end NS_ASSUME_NONNULL_END ================================================ FILE: CYLTabBarController/UIView+CYLBadgeExtention.m ================================================ /* //  CYLTabBarController //  CYLTabBarController // //  Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 03/06/19. //  Copyright © 2019 https://github.com/ChenYilong . All rights reserved. */ #import "UIView+CYLBadgeExtention.h" #import #import "CAAnimation+CYLBadgeExtention.h" #define kCYLBadgeDefaultFont ([UIFont boldSystemFontOfSize:9]) #define kCYLBadgeDefaultMaximumBadgeNumber 99 #define kCYLBadgeDefaultMargin (8.0) static const CGFloat kCYLBadgeDefaultRedDotRadius = 4.f; @implementation UIView (CYLBadgeExtention) #pragma mark -- public methods /** * show badge with red dot style and CYLBadgeAnimationTypeNone by default. */ - (void)cyl_showBadge { [self cyl_showBadgeValue:@"" animationType:CYLBadgeAnimationTypeNone]; } - (void)cyl_showBadgeValue:(NSString *)value animationType:(CYLBadgeAnimationType)animationType { [[[self cyl_badge] subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)]; self.cyl_badgeAnimationType = animationType; [self cyl_showBadgeWithValue:value]; if (animationType != CYLBadgeAnimationTypeNone) { [self cyl_beginAnimation]; } } - (void)cyl_showBadgeValue:(NSString *)value { [self cyl_showBadgeValue:value animationType:CYLBadgeAnimationTypeNone]; } #pragma mark -- private methods - (void)cyl_showBadgeWithValue:(NSString *)value { if (!value) { return; } NSCharacterSet *numberSet = [NSCharacterSet decimalDigitCharacterSet]; NSString *trimmedString = [value stringByTrimmingCharactersInSet:numberSet]; BOOL isNumber = NO; if ((trimmedString.length == 0) && (value.length > 0)) { isNumber = YES; } if (isNumber) { [self cyl_showNumberBadgeWithValue:[value integerValue]]; return; } if ([value isEqualToString:@""]) { [self cyl_showRedDotBadge]; return; } if ([value isEqualToString:@"new"] || [value isEqualToString:@"NEW"] ) { [self cyl_showNewBadge:value]; return; } [self cyl_showTextBadge:value]; } /** * clear badge */ - (void)cyl_clearBadge { self.cyl_badge.hidden = YES; } - (BOOL)cyl_isShowBadge { return (self.cyl_badge && !self.cyl_badge.hidden ); } /** * make bage(if existing) not hiden */ - (void)cyl_resumeBadge { if (self.cyl_isPauseBadge) { self.cyl_badge.hidden = NO; } } - (BOOL)cyl_isPauseBadge { return (self.cyl_badge && self.cyl_badge.hidden == YES); } #pragma mark -- private methods - (void)cyl_addMargin { CGRect frame = self.cyl_badge.frame; frame.size.width += self.cyl_badgeMargin; frame.size.height += self.cyl_badgeMargin; if(CGRectGetWidth(frame) < CGRectGetHeight(frame)) { frame.size.width = CGRectGetHeight(frame); } self.cyl_badge.frame = frame; } - (void)cyl_showRedDotBadge { [self cyl_badgeInit]; //if badge has been displayed and, in addition, is was not red dot style, we must update UI. if (self.cyl_badge.tag != CYLBadgeStyleRedDot) { self.cyl_badge.text = @""; self.cyl_badge.tag = CYLBadgeStyleRedDot; [self cyl_resetRedDotBadgeFrame]; self.cyl_badge.layer.cornerRadius = CGRectGetWidth(self.cyl_badge.frame) / 2; } self.cyl_badge.hidden = NO; } - (void)cyl_showNewBadge:(NSString *)value { CGSize size = [value sizeWithAttributes: @{NSFontAttributeName: self.cyl_badgeFont}]; float labelHeight = ceilf(size.height)+ self.cyl_badgeMargin; [self cyl_setBadgeCornerRadius:labelHeight/3]; [self cyl_showTextBadge:value]; } - (void)cyl_showTextBadge:(NSString *)value { if (value == 0 || !value ||value.length == 0) { self.cyl_badge.hidden = YES; return; } [self cyl_badgeInit]; self.cyl_badge.tag = CYLBadgeStyleOther; self.cyl_badge.text = value; self.cyl_badge.font = self.cyl_badgeFont; [self cyl_adjustLabelWidth:self.cyl_badge]; [self cyl_addMargin]; self.cyl_badge.center = CGPointMake(CGRectGetWidth(self.frame) + 2 + self.cyl_badgeCenterOffset.x, self.cyl_badgeCenterOffset.y); //FIXME: to delete self.cyl_badge.layer.cornerRadius = (self.cyl_badgeCornerRadius !=0 ) ? self.cyl_badgeCornerRadius : CGRectGetHeight(self.cyl_badge.frame) / 2; self.cyl_badge.hidden = NO; } - (void)cyl_showNumberBadgeWithValue:(NSInteger)value { if (value <= 0) { self.cyl_badge.hidden = YES; return; } [self cyl_badgeInit]; self.cyl_badge.hidden = (value == 0); self.cyl_badge.tag = CYLBadgeStyleNumber; NSString *text = (value > self.cyl_badgeMaximumBadgeNumber ? [NSString stringWithFormat:@"%@+", @(self.cyl_badgeMaximumBadgeNumber)] : [NSString stringWithFormat:@"%@", @(value)]); [self cyl_showTextBadge:text]; } //lazy loading - (void)cyl_badgeInit { if (self.cyl_badgeBackgroundColor == nil) { self.cyl_badgeBackgroundColor = [UIColor redColor]; } if (self.cyl_badgeTextColor == nil) { self.cyl_badgeTextColor = [UIColor whiteColor]; } if (!self.cyl_badge) { self.cyl_badge = [[UILabel alloc] init]; [self cyl_resetRedDotBadgeFrame]; self.cyl_badge.textAlignment = NSTextAlignmentCenter; self.cyl_badge.backgroundColor = self.cyl_badgeBackgroundColor; self.cyl_badge.textColor = self.cyl_badgeTextColor; self.cyl_badge.text = @""; self.cyl_badge.layer.cornerRadius = CGRectGetWidth(self.cyl_badge.frame) / 2; self.cyl_badge.layer.masksToBounds = YES;//very important self.cyl_badge.hidden = YES; self.cyl_badge.layer.zPosition = MAXFLOAT; [self addSubview:self.cyl_badge]; [self bringSubviewToFront:self.cyl_badge]; } } - (void)cyl_resetRedDotBadgeFrame { CGFloat redotWidth = kCYLBadgeDefaultRedDotRadius *2; if (self.cyl_badgeRadius) { redotWidth = self.cyl_badgeRadius * 2; } CGRect frame = CGRectMake(CGRectGetWidth(self.frame), -redotWidth, redotWidth, redotWidth); self.cyl_badge.frame = frame; self.cyl_badge.center = CGPointMake(CGRectGetWidth(self.frame) + 2 + self.cyl_badgeCenterOffset.x, self.cyl_badgeCenterOffset.y); } #pragma mark -- other private methods - (void)cyl_adjustLabelWidth:(UILabel *)label { CGSize labelsize = [self cyl_getLabelSize:label]; CGRect frame = label.frame; frame.size = CGSizeMake(ceilf(labelsize.width), ceilf(labelsize.height)); [label setFrame:frame]; } - (CGSize)cyl_getLabelSize:(UILabel *)label { [label setNumberOfLines:0]; NSString *s = label.text; UIFont *font = label.font; CGSize size = CGSizeMake(CGRectGetWidth([UIScreen mainScreen].bounds) ,CGFLOAT_MAX); CGSize labelsize; if (![s respondsToSelector:@selector(boundingRectWithSize:options:attributes:context:)]) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" labelsize = [s sizeWithFont:font constrainedToSize:size lineBreakMode:NSLineBreakByWordWrapping]; #pragma clang diagnostic pop } else { NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; [style setLineBreakMode:NSLineBreakByWordWrapping]; labelsize = [s boundingRectWithSize:size options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading) attributes:@{ NSFontAttributeName:font, NSParagraphStyleAttributeName : style} context:nil].size; } return labelsize; } #pragma mark -- animation //if u want to add badge animation type, follow steps bellow: //1. go to definition of CYLBadgeAnimationType and add new type //2. go to category of CAAnimation+CYLBadgeExtention to add new animation interface //3. call that new interface here - (void)cyl_beginAnimation { switch(self.cyl_badgeAnimationType) { case CYLBadgeAnimationTypeBreathe: [self.cyl_badge.layer addAnimation:[CAAnimation cyl_opacityForever_Animation:1.4] forKey:CYLBadgeBreatheAnimationKey]; break; case CYLBadgeAnimationTypeShake: [self.cyl_badge.layer addAnimation:[CAAnimation cyl_shake_AnimationRepeatTimes:CGFLOAT_MAX durTimes:1 forObj:self.cyl_badge.layer] forKey:CYLBadgeShakeAnimationKey]; break; case CYLBadgeAnimationTypeScale: [self.cyl_badge.layer addAnimation:[CAAnimation cyl_scaleFrom:1.4 toScale:0.6 durTimes:1 rep:MAXFLOAT] forKey:CYLBadgeScaleAnimationKey]; break; case CYLBadgeAnimationTypeBounce: [self.cyl_badge.layer addAnimation:[CAAnimation cyl_bounce_AnimationRepeatTimes:CGFLOAT_MAX durTimes:1 forObj:self.cyl_badge.layer] forKey:CYLBadgeBounceAnimationKey]; break; case CYLBadgeAnimationTypeNone: default: break; } } - (void)cyl_removeAnimation { if (self.cyl_badge) { [self.cyl_badge.layer removeAllAnimations]; } } #pragma mark -- setter/getter - (UILabel *)cyl_badge { return objc_getAssociatedObject(self, @selector(cyl_badge)); } - (void)cyl_setBadge:(UILabel *)label { objc_setAssociatedObject(self, @selector(cyl_badge), label, OBJC_ASSOCIATION_RETAIN); } - (UIFont *)cyl_badgeFont { id font = objc_getAssociatedObject(self, @selector(cyl_badgeFont)); return font ?: kCYLBadgeDefaultFont; } - (void)cyl_setBadgeFont:(UIFont *)badgeFont { objc_setAssociatedObject(self, @selector(cyl_badgeFont), badgeFont, OBJC_ASSOCIATION_RETAIN); if (!self.cyl_badge) { [self cyl_badgeInit]; } self.cyl_badge.font = badgeFont; } - (UIColor *)cyl_badgeBackgroundColor { return objc_getAssociatedObject(self, @selector(cyl_badgeBackgroundColor)); } - (void)cyl_setBadgeBackgroundColor:(UIColor *)badgeBackgroundColor { objc_setAssociatedObject(self, @selector(cyl_badgeBackgroundColor), badgeBackgroundColor, OBJC_ASSOCIATION_RETAIN); if (!self.cyl_badge) { [self cyl_badgeInit]; } self.cyl_badge.backgroundColor = badgeBackgroundColor; } - (UIColor *)cyl_badgeTextColor { return objc_getAssociatedObject(self, @selector(cyl_badgeTextColor)); } - (void)cyl_setBadgeTextColor:(UIColor *)badgeTextColor { objc_setAssociatedObject(self, @selector(cyl_badgeTextColor), badgeTextColor, OBJC_ASSOCIATION_RETAIN); if (!self.cyl_badge) { [self cyl_badgeInit]; } self.cyl_badge.textColor = badgeTextColor; } - (CYLBadgeAnimationType)cyl_badgeAnimationType { id obj = objc_getAssociatedObject(self, @selector(cyl_badgeAnimationType)); if(obj != nil && [obj isKindOfClass:[NSNumber class]]) { return [obj integerValue]; } return CYLBadgeAnimationTypeNone; } - (void)cyl_setBadgeAnimationType:(CYLBadgeAnimationType)animationType { NSNumber *numObj = @(animationType); objc_setAssociatedObject(self, @selector(cyl_badgeAnimationType), numObj, OBJC_ASSOCIATION_RETAIN); if (!self.cyl_badge) { [self cyl_badgeInit]; } [self cyl_removeAnimation]; [self cyl_beginAnimation]; } - (CGRect)cyl_badgeFrame { id obj = objc_getAssociatedObject(self, @selector(cyl_badgeFrame)); if (obj != nil && [obj isKindOfClass:[NSDictionary class]] && [obj count] == 4) { CGFloat x = [obj[@"x"] floatValue]; CGFloat y = [obj[@"y"] floatValue]; CGFloat width = [obj[@"width"] floatValue]; CGFloat height = [obj[@"height"] floatValue]; return CGRectMake(x, y, width, height); } return CGRectZero; } - (void)cyl_setBadgeFrame:(CGRect)badgeFrame { NSDictionary *frameInfo = @{@"x" : @(badgeFrame.origin.x), @"y" : @(badgeFrame.origin.y), @"width" : @(badgeFrame.size.width), @"height" : @(badgeFrame.size.height)}; objc_setAssociatedObject(self, @selector(cyl_badgeFrame), frameInfo, OBJC_ASSOCIATION_RETAIN); if (!self.cyl_badge) { [self cyl_badgeInit]; } self.cyl_badge.frame = badgeFrame; } - (CGFloat)cyl_badgeCornerRadius { NSNumber *badgeCornerRadiusObject = objc_getAssociatedObject(self, @selector(cyl_badgeCornerRadius)); return [badgeCornerRadiusObject floatValue]; } - (void)cyl_setBadgeCornerRadius:(CGFloat)badgeCornerRadius { NSNumber *badgeCornerRadiusObject = @(badgeCornerRadius); objc_setAssociatedObject(self, @selector(cyl_badgeCornerRadius), badgeCornerRadiusObject, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (CGPoint)cyl_badgeCenterOffset { id obj = objc_getAssociatedObject(self, @selector(cyl_badgeCenterOffset)); if (obj != nil && [obj isKindOfClass:[NSDictionary class]] && [obj count] == 2) { CGFloat x = [obj[@"x"] floatValue]; CGFloat y = [obj[@"y"] floatValue]; return CGPointMake(x, y); } return CGPointZero; } - (void)cyl_setBadgeCenterOffset:(CGPoint)badgeCenterOff { NSDictionary *cenerInfo = @{@"x" : @(badgeCenterOff.x), @"y" : @(badgeCenterOff.y)}; objc_setAssociatedObject(self, @selector(cyl_badgeCenterOffset), cenerInfo, OBJC_ASSOCIATION_RETAIN); if (!self.cyl_badge) { [self cyl_badgeInit]; } self.cyl_badge.center = CGPointMake(CGRectGetWidth(self.frame) + 2 + badgeCenterOff.x, badgeCenterOff.y); } //badgeRadiusKey - (void)cyl_setBadgeRadius:(CGFloat)badgeRadius { objc_setAssociatedObject(self, @selector(cyl_badgeRadius), [NSNumber numberWithFloat:badgeRadius], OBJC_ASSOCIATION_RETAIN); if (!self.cyl_badge) { [self cyl_badgeInit]; } } - (CGFloat)cyl_badgeRadius { return [objc_getAssociatedObject(self, @selector(cyl_badgeRadius)) floatValue]; } - (void)cyl_setBadgeMargin:(CGFloat)badgeMargin { objc_setAssociatedObject(self, @selector(cyl_badgeMargin), [NSNumber numberWithFloat:badgeMargin], OBJC_ASSOCIATION_RETAIN); if (!self.cyl_badge) { [self cyl_badgeInit]; } } - (CGFloat)cyl_badgeMargin { id margin = objc_getAssociatedObject(self, @selector(cyl_badgeMargin)); return margin == nil ? kCYLBadgeDefaultMargin : [margin floatValue]; } - (NSInteger)cyl_badgeMaximumBadgeNumber { id obj = objc_getAssociatedObject(self, @selector(cyl_badgeMaximumBadgeNumber)); if(obj != nil && [obj isKindOfClass:[NSNumber class]]) { return [obj integerValue]; } return kCYLBadgeDefaultMaximumBadgeNumber; } - (void)cyl_setBadgeMaximumBadgeNumber:(NSInteger)badgeMaximumBadgeNumber { NSNumber *numObj = @(badgeMaximumBadgeNumber); objc_setAssociatedObject(self, @selector(cyl_badgeMaximumBadgeNumber), numObj, OBJC_ASSOCIATION_RETAIN); if (!self.cyl_badge) { [self cyl_badgeInit]; } } - (BOOL)cyl_isInvisiable { UIView *obj = self; CGFloat width = obj.frame.size.width; CGFloat height = obj.frame.size.height; BOOL isSizeZero = (width == 0 || height == 0); BOOL isInvisible = (obj.hidden == YES) || (obj.alpha <= 0.01f) || (!obj.superview) || isSizeZero; return isInvisible; } - (BOOL)cyl_canNotResponseEvent { return self.cyl_isInvisiable || (self.userInteractionEnabled == NO); } @end ================================================ FILE: CYLTabBarController/UIView+CYLTabBarControllerExtention.h ================================================ // // CYLTabBarController.m // CYLTabBarController // // v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/20/15. // Copyright © 2018 https://github.com/ChenYilong . All rights reserved. // #import #import #import "CYLConstants.h" NS_ASSUME_NONNULL_BEGIN @interface UIView (CYLTabBarControllerExtention) - (BOOL)cyl_isPlusButton; - (BOOL)cyl_isTabButton; - (BOOL)cyl_isTabImageView; - (BOOL)cyl_isTabLabel; - (BOOL)cyl_isTabBadgeView; - (BOOL)cyl_isTabBackgroundView; - (UIView *)cyl_tabBadgeView; - (UIImageView *)cyl_tabImageView; - (UILabel *)cyl_tabLabel; - (UIImageView *)cyl_tabShadowImageView; - (UIVisualEffectView *)cyl_tabEffectView; - (BOOL)cyl_isLottieAnimationView; - (UIView *)cyl_tabBackgroundView; + (UIView *)cyl_tabBadgePointViewWithClolor:(UIColor *)color radius:(CGFloat)radius; - (NSArray *)cyl_allSubviews; @end @interface UIView (CYLTabBarControllerExtentionDeprecated) - (UIView *)cyl_tabBadgeBackgroundView CYL_DEPRECATED("Deprecated in 1.6.0. Use `+[CYLPlusButton cyl_tabBackgroundView]` instead."); - (UIView *)cyl_tabBadgeBackgroundSeparator CYL_DEPRECATED("Deprecated in 1.6.0. Use `+[CYLPlusButton cyl_tabShadowImageView]` instead."); @end NS_ASSUME_NONNULL_END ================================================ FILE: CYLTabBarController/UIView+CYLTabBarControllerExtention.m ================================================ // // CYLTabBarController.m // CYLTabBarController // // v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/20/15. // Copyright © 2018 https://github.com/ChenYilong . All rights reserved. // #import #import "UIView+CYLTabBarControllerExtention.h" #import "CYLPlusButton.h" #if __has_include() #import #else #endif @implementation UIView (CYLTabBarControllerExtention) - (BOOL)cyl_isPlusButton { return [self isKindOfClass:[CYLExternPlusButton class]]; } - (BOOL)cyl_isTabButton { BOOL isKindOfButton = [self cyl_isKindOfClass:[UIControl class]]; return isKindOfButton; } - (BOOL)cyl_isTabImageView { BOOL isKindOfImageView = [self cyl_isKindOfClass:[UIImageView class]]; if (!isKindOfImageView) { return NO; } NSString *subString = [NSString stringWithFormat:@"%@cat%@ew", @"Indi" , @"orVi"]; BOOL isBackgroundImage = [self cyl_classStringHasSuffix:subString]; BOOL isTabImageView = !isBackgroundImage; return isTabImageView; } - (BOOL)cyl_isTabLabel { BOOL isKindOfLabel = [self cyl_isKindOfClass:[UILabel class]]; return isKindOfLabel; } - (BOOL)cyl_isTabBadgeView { BOOL isKindOfClass = [self isKindOfClass:[UIView class]]; BOOL isClass = [self isMemberOfClass:[UIView class]]; BOOL isKind = isKindOfClass && !isClass; if (!isKind) { return NO; } NSString *tabBarClassString = [NSString stringWithFormat:@"%@IB%@", @"_U" , @"adg"]; BOOL isTabBadgeView = [self cyl_classStringHasPrefix:tabBarClassString];; return isTabBadgeView; } - (BOOL)cyl_isTabBackgroundView { BOOL isKindOfClass = [self isKindOfClass:[UIView class]]; BOOL isClass = [self isMemberOfClass:[UIView class]]; BOOL isKind = isKindOfClass && !isClass; if (!isKind) { return NO; } NSString *tabBackgroundViewString = [NSString stringWithFormat:@"%@IB%@", @"_U" , @"arBac"]; BOOL isTabBackgroundView = [self cyl_classStringHasPrefix:tabBackgroundViewString] && [self cyl_classStringHasSuffix:@"nd"]; return isTabBackgroundView; } - (UIImageView *)cyl_tabImageView { for (UIImageView *subview in self.cyl_allSubviews) { if ([subview cyl_isTabImageView]) { return (UIImageView *)subview; } } return nil; } - (NSArray *)cyl_allSubviews { __block NSArray* allSubviews = [NSArray arrayWithObject:self]; [self.subviews enumerateObjectsUsingBlock:^(UIView* view, NSUInteger idx, BOOL*stop) { allSubviews = [allSubviews arrayByAddingObjectsFromArray:[view cyl_allSubviews]]; }]; return allSubviews; } - (UIView *)cyl_tabBadgeView { for (UIView *subview in self.cyl_allSubviews) { if ([subview cyl_isTabBadgeView]) { return (UIView *)subview; } } return nil; } - (UILabel *)cyl_tabLabel { for (UILabel *subview in self.cyl_allSubviews) { if ([subview cyl_isTabLabel]) { return (UILabel *)subview; } } return nil; } //UIVisualEffectView - (BOOL)cyl_isTabEffectView { BOOL isClass = [self isMemberOfClass:[UIVisualEffectView class]]; return isClass; } //_UIVisualEffectContentView - (BOOL)cyl_isTabEffectContentView { BOOL isKindOfClass = [self isKindOfClass:[UIView class]]; BOOL isClass = [self isMemberOfClass:[UIView class]]; BOOL isKind = isKindOfClass && !isClass; if (!isKind) { return NO; } NSString *tabBackgroundViewString = [NSString stringWithFormat:@"%@IVisualE%@", @"_U" , @"ffectC"]; BOOL isTabBackgroundView = [self cyl_classStringHasPrefix:tabBackgroundViewString] && [self cyl_classStringHasSuffix:@"entView"]; return isTabBackgroundView; } //UIVisualEffectView - (UIVisualEffectView *)cyl_tabEffectView { for (UIView *subview in self.subviews) { if ([subview cyl_isTabEffectView]) { return (UIVisualEffectView *)subview; } } return nil; } - (UIView *)cyl_tabBadgeBackgroundView { return [self cyl_tabBackgroundView]; } - (UIImageView *)cyl_tabShadowImageView { if (@available(iOS 10.0, *)) { //iOS10及以上这样获取ShadowImageView: UIView *subview = [self cyl_tabBackgroundView]; if (!subview) { return nil; } NSArray<__kindof UIView *> *backgroundSubviews = subview.subviews; //iOS13系统backgroundSubviews.count > 1可行,12及以下就不可行了 if (backgroundSubviews.count >= 1) { for (UIView *subview in backgroundSubviews) { if (CGRectGetHeight(subview.bounds) <= 1.0 ) { return (UIImageView *)subview; } } } } else { //iOS9这样获取ShadowImageView: for (UIView *subview in self.subviews) { if (CGRectGetHeight(subview.bounds) <= 1.0 ) { return (UIImageView *)subview; } } } return nil; } - (UIView *)cyl_tabBackgroundView { for (UIImageView *subview in self.subviews) { if ([subview cyl_isTabBackgroundView]) { return (UIImageView *)subview; } } return nil; } - (BOOL)cyl_isLottieAnimationView { BOOL isKindOfClass = [self isKindOfClass:[UIView class]]; BOOL isClass = [self isMemberOfClass:[UIView class]]; BOOL isKind = isKindOfClass && !isClass; if (!isKind) { return NO; } Class classType = NSClassFromString(@"LOTAnimationView"); BOOL isLottieAnimationView = ([self isKindOfClass:classType] || [self isMemberOfClass:classType]); return isLottieAnimationView; } - (UIView *)cyl_tabBadgeBackgroundSeparator { return [self cyl_tabShadowImageView]; } - (BOOL)cyl_isKindOfClass:(Class)class { BOOL isKindOfClass = [self isKindOfClass:class]; BOOL isClass = [self isMemberOfClass:class]; BOOL isKind = isKindOfClass && !isClass; if (!isKind) { return NO; } BOOL isTabBarClass = [self cyl_isTabBarClass]; return isTabBarClass; } - (BOOL)cyl_isTabBarClass { NSString *tabBarClassString = [NSString stringWithFormat:@"U%@a%@ar", @"IT" , @"bB"]; BOOL isTabBarClass = [self cyl_classStringHasPrefix:tabBarClassString]; return isTabBarClass; } - (BOOL)cyl_classStringHasPrefix:(NSString *)prefix { NSString *classString = NSStringFromClass([self class]); return [classString hasPrefix:prefix]; } - (BOOL)cyl_classStringHasSuffix:(NSString *)suffix { NSString *classString = NSStringFromClass([self class]); return [classString hasSuffix:suffix]; } + (UIView *)cyl_tabBadgePointViewWithClolor:(UIColor *)color radius:(CGFloat)radius { UIView *defaultTabBadgePointView = [[UIView alloc] init]; [defaultTabBadgePointView setTranslatesAutoresizingMaskIntoConstraints:NO]; defaultTabBadgePointView.backgroundColor = color; defaultTabBadgePointView.layer.cornerRadius = radius; defaultTabBadgePointView.layer.masksToBounds = YES; defaultTabBadgePointView.hidden = YES; // Width constraint [defaultTabBadgePointView addConstraint:[NSLayoutConstraint constraintWithItem:defaultTabBadgePointView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute: NSLayoutAttributeNotAnAttribute multiplier:1 constant:radius * 2]]; // Height constraint [defaultTabBadgePointView addConstraint:[NSLayoutConstraint constraintWithItem:defaultTabBadgePointView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute: NSLayoutAttributeNotAnAttribute multiplier:1 constant:radius * 2]]; return defaultTabBadgePointView; } @end ================================================ FILE: CYLTabBarController/UIViewController+CYLNavigationControllerExtention.h ================================================ /* //  CYLTabBarController //  CYLTabBarController // //  Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 03/06/19. //  Copyright © 2019 https://github.com/ChenYilong . All rights reserved. */ #import NS_ASSUME_NONNULL_BEGIN @interface UIViewController (CYLNavigationControllerExtention) @property (nonatomic, assign, getter=cyl_disablePopGestureRecognizer, setter=cyl_setDisablePopGestureRecognizer:) BOOL cyl_disablePopGestureRecognizer; @property (nonatomic, assign, getter=cyl_hideNavigationBarSeparator, setter=cyl_setHideNavigationBarSeparator:) BOOL cyl_hideNavigationBarSeparator; @property (nonatomic, assign, getter=cyl_navigationBarHidden, setter=cyl_setNavigationBarHidden:) BOOL cyl_navigationBarHidden; /*! * 使用方法:用在viewWillDisappear/dealloc * 作用:在左滑动的过渡的时间段内禁用interactivePopGestureRecognizer */ - (void)cyl_disableInteractivePopGestureRecognizer; /*! * use in viewDidDisappear * 作用:在左滑动的结束后启用interactivePopGestureRecognizer */ - (void)cyl_enableInteractivePopGestureRecognizer; /*! * use in viewDidAppear * 当新的视图控制器加载完成后再启用 */ - (void)cyl_resetInteractivePopGestureRecognizer; /*! * use in viewWillAppear */ - (void)cyl_hideNavigationBarSeparatorIfNeeded; - (BOOL)cyl_shouldNavigationBarVisible; //use in viewWillDisappear - (void)cyl_setNavigationBarVisibleIfNeeded:(BOOL)animated; //use in viewWillAppear - (void)cyl_setNavigationBarHiddenIfNeeded:(BOOL)animated; - (void)cyl_viewWillAppearNavigationSetting:(BOOL)animated; - (void)cyl_viewWillDisappearNavigationSetting:(BOOL)animated; - (void)cyl_viewDidDisappearNavigationSetting:(BOOL)animated; - (void)cyl_viewDidAppearNavigationSetting:(BOOL)animated; - (void)cyl_deallocNavigationSetting; @end NS_ASSUME_NONNULL_END ================================================ FILE: CYLTabBarController/UIViewController+CYLNavigationControllerExtention.m ================================================ /* //  CYLTabBarController //  CYLTabBarController // //  Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 03/06/19. //  Copyright © 2019 https://github.com/ChenYilong . All rights reserved. */ #import "UIViewController+CYLNavigationControllerExtention.h" #import @implementation UIViewController (CYLNavigationControllerExtention) - (BOOL)cyl_disablePopGestureRecognizer { NSNumber *disablePopGestureRecognizerObject = objc_getAssociatedObject(self, @selector(cyl_disablePopGestureRecognizer)); return [disablePopGestureRecognizerObject boolValue]; } - (void)cyl_setDisablePopGestureRecognizer:(BOOL)disablePopGestureRecognizer { NSNumber *disablePopGestureRecognizerObject = [NSNumber numberWithBool:disablePopGestureRecognizer]; objc_setAssociatedObject(self, @selector(cyl_disablePopGestureRecognizer), disablePopGestureRecognizerObject, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (BOOL)cyl_hideNavigationBarSeparator { NSNumber *hideNavigationBarSeparatorObject = objc_getAssociatedObject(self, @selector(cyl_hideNavigationBarSeparator)); return [hideNavigationBarSeparatorObject boolValue]; } - (void)cyl_setHideNavigationBarSeparator:(BOOL)hideNavigationBarSeparator { NSNumber *hideNavigationBarSeparatorObject = [NSNumber numberWithBool:hideNavigationBarSeparator]; objc_setAssociatedObject(self, @selector(cyl_hideNavigationBarSeparator), hideNavigationBarSeparatorObject, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (BOOL)cyl_navigationBarHidden { NSNumber *navigationBarHiddenObject = objc_getAssociatedObject(self, @selector(cyl_navigationBarHidden)); return [navigationBarHiddenObject boolValue]; } - (void)cyl_setNavigationBarHidden:(BOOL)navigationBarHidden { NSNumber *navigationBarHiddenObject = [NSNumber numberWithBool:navigationBarHidden]; objc_setAssociatedObject(self, @selector(cyl_navigationBarHidden), navigationBarHiddenObject, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } //viewWillDisappear //dealloc // 在左滑动的过渡的时间段内禁用interactivePopGestureRecognizer - (void)cyl_disableInteractivePopGestureRecognizer { if (![self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) { return; } self.navigationController.interactivePopGestureRecognizer.delegate = nil; } //viewDidDisappear // 在左滑动的结束后启用interactivePopGestureRecognizer - (void)cyl_enableInteractivePopGestureRecognizer { if (![self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) { return; } self.navigationController.interactivePopGestureRecognizer.delegate = (id )self; self.navigationController.interactivePopGestureRecognizer.enabled = YES; } //viewDidAppear // 当新的视图控制器加载完成后再启用 - (void)cyl_resetInteractivePopGestureRecognizer { if (![self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) { return; } BOOL isSingleViewControllerInNavigationController = ([self.navigationController.viewControllers count] == 1); BOOL needDisableInteractivePopGestureRecognizer = (self.cyl_disablePopGestureRecognizer) || isSingleViewControllerInNavigationController; if (needDisableInteractivePopGestureRecognizer) { self.navigationController.interactivePopGestureRecognizer.enabled = NO; } else { self.navigationController.interactivePopGestureRecognizer.enabled = YES; } } //viewWillAppear - (void)cyl_hideNavigationBarSeparatorIfNeeded { if (self.cyl_hideNavigationBarSeparator) { self.navigationController.navigationBar.shadowImage = [UIImage new]; self.navigationController.navigationBar.translucent = NO; } } //在viewwilldisappear使用 - (BOOL)cyl_shouldNavigationBarVisible { BOOL shouldSetNo = YES; BOOL isPop = YES; if (!self.navigationController) { return shouldSetNo; } //push的时候会先将vc添加到viewControllers,再调用viewWillDisappear //pop的时候会先将vc从viewControllers移除,再调用viewWillDisappear NSInteger selfIndex = -1; if (self.navigationController.viewControllers.count > 0) { NSArray *vcList = self.navigationController.viewControllers; for (NSInteger i = 0; i < vcList.count; i++) { UIViewController *vc = vcList[i]; if (vc == self) { selfIndex = i; if (selfIndex == vcList.count - 1) { //这种情况是navigationController push第一个vc或者present,不需要特殊处理,直接return return YES; } isPop = NO; break; } } if (isPop) { UIViewController *preVc = (UIViewController *)self.navigationController.viewControllers.lastObject; if (self.cyl_navigationBarHidden == preVc.cyl_navigationBarHidden) { shouldSetNo = NO; } } else { if (selfIndex + 1 < self.navigationController.viewControllers.count) { UIViewController *nextVc = (UIViewController *)self.navigationController.viewControllers[selfIndex + 1]; if (self.cyl_navigationBarHidden == nextVc.cyl_navigationBarHidden) { shouldSetNo = NO; } } } } return shouldSetNo; } //viewWillDisappear - (void)cyl_setNavigationBarVisibleIfNeeded:(BOOL)animated { if (self.cyl_navigationBarHidden && [self cyl_shouldNavigationBarVisible]) { [self.navigationController setNavigationBarHidden:!self.cyl_navigationBarHidden animated:animated]; } } //viewWillAppear - (void)cyl_setNavigationBarHiddenIfNeeded:(BOOL)animated { if (self.cyl_navigationBarHidden) { [self.navigationController setNavigationBarHidden:self.cyl_navigationBarHidden animated:animated]; } } - (void)cyl_viewWillAppearNavigationSetting:(BOOL)animated { [self cyl_hideNavigationBarSeparatorIfNeeded]; [self cyl_setNavigationBarHiddenIfNeeded:animated]; } - (void)cyl_viewWillDisappearNavigationSetting:(BOOL)animated { [self cyl_disableInteractivePopGestureRecognizer]; [self cyl_setNavigationBarVisibleIfNeeded:animated]; } - (void)cyl_viewDidDisappearNavigationSetting:(BOOL)animated { [self cyl_enableInteractivePopGestureRecognizer]; } - (void)cyl_viewDidAppearNavigationSetting:(BOOL)animated { [self cyl_resetInteractivePopGestureRecognizer]; } - (void)cyl_deallocNavigationSetting { [self cyl_disableInteractivePopGestureRecognizer]; } @end ================================================ FILE: CYLTabBarController/UIViewController+CYLTabBarControllerExtention.h ================================================ // // UIViewController+CYLTabBarControllerExtention.h // CYLTabBarController // // v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 16/2/26. // Copyright © 2018年 https://github.com/ChenYilong .All rights reserved. // #import #import "CYLBadgeProtocol.h" #import "CYLConstants.h" NS_ASSUME_NONNULL_BEGIN typedef void (^CYLPopSelectTabBarChildViewControllerCompletion)(__kindof UIViewController *selectedTabBarChildViewController); typedef void (^CYLPushOrPopCompletionHandler)(BOOL shouldPop, __kindof UIViewController *viewControllerPopTo, BOOL shouldPopSelectTabBarChildViewController, NSUInteger index ); typedef void (^CYLPushOrPopCallback)(NSArray<__kindof UIViewController *> *viewControllers, CYLPushOrPopCompletionHandler completionHandler); @interface UIViewController (CYLTabBarControllerExtention) @property (nonatomic, readonly, getter=cyl_isEmbedInTabBarController) BOOL cyl_embedInTabBarController; @property (nonatomic, readonly, getter=cyl_tabIndex) NSInteger cyl_tabIndex; @property (nonatomic, readonly) UIControl *cyl_tabButton; @property (nonatomic, copy, setter=cyl_setContext:, getter=cyl_context) NSString *cyl_context; @property (nonatomic, assign, setter=cyl_setPlusViewControllerEverAdded:, getter=cyl_plusViewControllerEverAdded) BOOL cyl_plusViewControllerEverAdded; - (BOOL)cyl_isShowBadge; /** * show badge with red dot style and CYLBadgeAnimationTypeNone by default. */ - (void)cyl_showBadge; /** * * @param value String value, default is `nil`. if value equal @"" means red dot style. * @param animationType animationType * @attention - 调用该方法前已经添加了系统的角标,调用该方法后,系统的角标并未被移除,只是被隐藏,调用 `-cyl_removeTabBadgePoint` 后会重新展示。 - 不支持 CYLPlusChildViewController 对应的 TabBarItem 角标设置,调用会被忽略。 */ - (void)cyl_showBadgeValue:(NSString *)value animationType:(CYLBadgeAnimationType)animationType; /** * clear badge(hide badge) */ - (void)cyl_clearBadge; /** * make bage(if existing) not hiden */ - (void)cyl_resumeBadge; - (BOOL)cyl_isPauseBadge; /*! * Pop 到当前 `NavigationController` 的栈底,并改变 `TabBarController` 的 `selectedViewController` 属性,并将被选择的控制器作为返回值返回。 @param index 需要选择的控制器在 `TabBar` 中的 index。 @return 最终被选择的控制器。 @attention 注意:方法中的参数和返回值都是 `UIViewController` 的子类,但并非 `UINavigationController` 的子类,该方法无 pop 动画。 */ - (UIViewController *)cyl_popSelectTabBarChildViewControllerAtIndex:(NSUInteger)index; /*! * Pop 到当前 `NavigationController` 的栈底,并改变 `TabBarController` 的 `selectedViewController` 属性,并将被选择的控制器作为返回值返回。 @param index 需要选择的控制器在 `TabBar` 中的 index。 @param animated 动画 @return 最终被选择的控制器。 @attention 注意:方法中的参数和返回值都是 `UIViewController` 的子类,但并非 `UINavigationController` 的子类。 */ - (UIViewController *)cyl_popSelectTabBarChildViewControllerAtIndex:(NSUInteger)index animated:(BOOL)animated; /*! * Pop 到当前 `NavigationController` 的栈底,并改变 `TabBarController` 的 `selectedViewController` 属性,并将被选择的控制器在 `Block` 回调中返回。 @param index 需要选择的控制器在 `TabBar` 中的 index。 @attention 注意:方法中的参数和返回值都是 `UIViewController` 的子类,但并非 `UINavigationController` 的子类。 */ - (void)cyl_popSelectTabBarChildViewControllerAtIndex:(NSUInteger)index completion:(CYLPopSelectTabBarChildViewControllerCompletion)completion; /*! * Pop 到当前 `NavigationController` 的栈底,并改变 `TabBarController` 的 `selectedViewController` 属性,并将被选择的控制器作为返回值返回。 @param classType 需要选择的控制器所属的类。 @return 最终被选择的控制器。 @attention 注意: - 方法中的参数和返回值都是 `UIViewController` 的子类,但并非 `UINavigationController` 的子类。 - 如果 TabBarViewController 的 viewControllers 中包含多个相同的 `classType` 类型,会返回最左端的一个。 */ - (UIViewController *)cyl_popSelectTabBarChildViewControllerForClassType:(Class)classType; /*! * Pop 到当前 `NavigationController` 的栈底,并改变 `TabBarController` 的 `selectedViewController` 属性,并将被选择的控制器在 `Block` 回调中返回。 @param classType 需要选择的控制器所属的类。 @attention 注意: - 方法中的参数和返回值都是 `UIViewController` 的子类,但并非 `UINavigationController` 的子类。 - 如果 TabBarViewController 的 viewControllers 中包含多个相同的 `classType` 类型,会返回最左端的一个。 */ - (void)cyl_popSelectTabBarChildViewControllerForClassType:(Class)classType completion:(CYLPopSelectTabBarChildViewControllerCompletion)completion; /*! *@brief 如果当前的 `NavigationViewController` 栈中包含有准备 Push 到的目标控制器,可以选择 Pop 而非 Push。 *@param viewController Pop 或 Push 到的“目标控制器”,由 completionHandler 的参数控制 Pop 和 Push 的细节。 *@param animated Pop 或 Push 时是否带动画 *@param callback 回调,如果传 nil,将进行 Push。callback 包含以下几个参数: * param : viewControllers 表示与“目标控制器”相同类型的控制器; * param : completionHandler 包含以下几个参数: * param : shouldPop 是否 Pop * param : viewControllerPopTo Pop 回的控制器 * param : shouldPopSelectTabBarChildViewController 在进行 Push 行为之前,是否 Pop 到当前 `NavigationController` 的栈底。 可能的值如下: NO 如果上一个参数为 NO,下一个参数 index 将被忽略。 YES 会根据 index 参数改变 `TabBarController` 的 `selectedViewController` 属性。 注意:该属性在 Pop 行为时不起作用。 * param : index Pop 改变 `TabBarController` 的 `selectedViewController` 属性。 注意:该属性在 Pop 行为时不起作用。 */ - (void)cyl_pushOrPopToViewController:(UIViewController *)viewController animated:(BOOL)animated callback:(CYLPushOrPopCallback)callback; /*! * 如果正要 Push 的页面与当前栈顶的页面类型相同则取消 Push * 这样做防止主界面卡顿时,导致一个 ViewController 被 Push 多次 */ - (void)cyl_pushViewController:(UIViewController *)viewController animated:(BOOL)animated; - (UIViewController *)cyl_getViewControllerInsteadOfNavigationController; - (void)cyl_handleNavigationBackAction; - (void)cyl_handleNavigationBackActionWithAnimated:(BOOL)animated; @end @interface UIViewController (CYLTabBarControllerExtentionDeprecated) - (void)cyl_showTabBadgePoint CYL_DEPRECATED("Deprecated in 1.19.0. Use `-[UIViewController cyl_showBadgeValue:animationType:]` instead."); - (void)cyl_removeTabBadgePoint CYL_DEPRECATED("Deprecated in 1.19.0. Use `-[UIViewController cyl_clearBadge]` instead."); - (BOOL)cyl_isShowTabBadgePoint CYL_DEPRECATED("Deprecated in 1.19.0. Use `-[UIViewController cyl_isShowBadge]` instead."); @property (nonatomic, strong, setter=cyl_setTabBadgePointView:, getter=cyl_tabBadgePointView) UIView *cyl_tabBadgePointView CYL_DEPRECATED("Deprecated in 1.19.0. Use method in instead."); @property (nonatomic, assign, setter=cyl_setTabBadgePointViewOffset:, getter=cyl_tabBadgePointViewOffset) UIOffset cyl_tabBadgePointViewOffset CYL_DEPRECATED("Deprecated in 1.19.0. Use method in instead."); @end NS_ASSUME_NONNULL_END ================================================ FILE: CYLTabBarController/UIViewController+CYLTabBarControllerExtention.m ================================================ // // UIViewController+CYLTabBarControllerExtention.m // CYLTabBarController // // v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 16/2/26. // Copyright © 2018年 https://github.com/ChenYilong .All rights reserved. // #import "UIViewController+CYLTabBarControllerExtention.h" #import "CYLTabBarController.h" #import #define kActualView [self cyl_getActualBadgeSuperView] @implementation UIViewController (CYLTabBarControllerExtention) #pragma mark - #pragma mark - public Methods - (UIViewController *)cyl_popSelectTabBarChildViewControllerAtIndex:(NSUInteger)index { return [self cyl_popSelectTabBarChildViewControllerAtIndex:index animated:NO]; } - (UIViewController *)cyl_popSelectTabBarChildViewControllerAtIndex:(NSUInteger)index animated:(BOOL)animated { UIViewController *viewController = [self cyl_getViewControllerInsteadOfNavigationController]; [viewController checkTabBarChildControllerValidityAtIndex:index]; CYLTabBarController *tabBarController = [viewController cyl_tabBarController]; tabBarController.selectedIndex = index; [viewController.navigationController popToRootViewControllerAnimated:animated]; UIViewController *selectedTabBarChildViewController = tabBarController.selectedViewController; return [selectedTabBarChildViewController cyl_getViewControllerInsteadOfNavigationController]; } - (void)cyl_popSelectTabBarChildViewControllerAtIndex:(NSUInteger)index completion:(CYLPopSelectTabBarChildViewControllerCompletion)completion { UIViewController *selectedTabBarChildViewController = [self cyl_popSelectTabBarChildViewControllerAtIndex:index]; dispatch_async(dispatch_get_main_queue(), ^{ !completion ?: completion(selectedTabBarChildViewController); }); } - (UIViewController *)cyl_popSelectTabBarChildViewControllerForClassType:(Class)classType { CYLTabBarController *tabBarController = [[self cyl_getViewControllerInsteadOfNavigationController] cyl_tabBarController]; NSArray *viewControllers = tabBarController.viewControllers; NSInteger atIndex = [self cyl_indexForClassType:classType inViewControllers:viewControllers]; return [self cyl_popSelectTabBarChildViewControllerAtIndex:atIndex]; } - (void)cyl_popSelectTabBarChildViewControllerForClassType:(Class)classType completion:(CYLPopSelectTabBarChildViewControllerCompletion)completion { UIViewController *selectedTabBarChildViewController = [self cyl_popSelectTabBarChildViewControllerForClassType:classType]; dispatch_async(dispatch_get_main_queue(), ^{ !completion ?: completion(selectedTabBarChildViewController); }); } - (void)cyl_pushOrPopToViewController:(UIViewController *)viewController animated:(BOOL)animated callback:(CYLPushOrPopCallback)callback { if (!callback) { [self.navigationController pushViewController:viewController animated:animated]; return; } void (^popSelectTabBarChildViewControllerCallback)(BOOL shouldPopSelectTabBarChildViewController, NSUInteger index) = ^(BOOL shouldPopSelectTabBarChildViewController, NSUInteger index) { if (shouldPopSelectTabBarChildViewController) { [self cyl_popSelectTabBarChildViewControllerAtIndex:index completion:^(__kindof UIViewController *selectedTabBarChildViewController) { [selectedTabBarChildViewController.navigationController pushViewController:viewController animated:animated]; }]; } else { [self.navigationController pushViewController:viewController animated:animated]; } }; NSArray<__kindof UIViewController *> *otherSameClassTypeViewControllersInCurrentNavigationControllerStack = [self cyl_getOtherSameClassTypeViewControllersInCurrentNavigationControllerStack:viewController]; CYLPushOrPopCompletionHandler completionHandler = ^(BOOL shouldPop, __kindof UIViewController *viewControllerPopTo, BOOL shouldPopSelectTabBarChildViewController, NSUInteger index ) { if (!otherSameClassTypeViewControllersInCurrentNavigationControllerStack || otherSameClassTypeViewControllersInCurrentNavigationControllerStack.count == 0) { shouldPop = NO; } dispatch_async(dispatch_get_main_queue(),^{ if (shouldPop) { [self.navigationController popToViewController:viewControllerPopTo animated:animated]; return; } popSelectTabBarChildViewControllerCallback(shouldPopSelectTabBarChildViewController, index); }); }; callback(otherSameClassTypeViewControllersInCurrentNavigationControllerStack, completionHandler); } - (void)cyl_pushViewController:(UIViewController *)viewController animated:(BOOL)animated { UIViewController *fromViewController = [self cyl_getViewControllerInsteadOfNavigationController]; NSArray *childViewControllers = fromViewController.navigationController.childViewControllers; if (childViewControllers.count > 0) { if ([[childViewControllers lastObject] isKindOfClass:[viewController class]]) { return; } } [fromViewController.navigationController pushViewController:viewController animated:animated]; } - (UIViewController *)cyl_getViewControllerInsteadOfNavigationController { BOOL isNavigationController = [[self class] isSubclassOfClass:[UINavigationController class]]; if (isNavigationController && ((UINavigationController *)self).viewControllers.count > 0) { return ((UINavigationController *)self).viewControllers[0]; } return self; } #pragma mark - public method - (BOOL)cyl_isPlusChildViewController { if (!CYLPlusChildViewController) { return NO; } return (self == CYLPlusChildViewController); } #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" - (void)cyl_showTabBadgePoint { if (self.cyl_isPlusChildViewController) { return; } [self cyl_showBadge]; } - (void)cyl_removeTabBadgePoint { if (self.cyl_isPlusChildViewController) { return; } [self cyl_clearBadge]; } - (BOOL)cyl_isShowTabBadgePoint { if (self.cyl_isPlusChildViewController) { return NO; } return [self cyl_isShowBadge];; } #pragma clang diagnostic pop - (void)cyl_setTabBadgePointView:(UIView *)tabBadgePointView { if (self.cyl_isPlusChildViewController) { return; } [self.cyl_tabButton cyl_setTabBadgePointView:tabBadgePointView]; } - (UIView *)cyl_tabBadgePointView { if (self.cyl_isPlusChildViewController) { return nil; } return [self.cyl_tabButton cyl_tabBadgePointView];; } - (void)cyl_setTabBadgePointViewOffset:(UIOffset)tabBadgePointViewOffset { if (self.cyl_isPlusChildViewController) { return; } return [self.cyl_tabButton cyl_setTabBadgePointViewOffset:tabBadgePointViewOffset]; } //offset如果都是整数,则往右下偏移 - (UIOffset)cyl_tabBadgePointViewOffset { if (self.cyl_isPlusChildViewController) { return UIOffsetZero; } return [self.cyl_tabButton cyl_tabBadgePointViewOffset]; } - (BOOL)cyl_isEmbedInTabBarController { if (self.cyl_tabBarController == nil) { return NO; } if (self.cyl_isPlusChildViewController) { return NO; } BOOL isEmbedInTabBarController = NO; UIViewController *viewControllerInsteadIOfNavigationController = [self cyl_getViewControllerInsteadOfNavigationController]; for (NSInteger i = 0; i < self.cyl_tabBarController.viewControllers.count; i++) { UIViewController * vc = self.cyl_tabBarController.viewControllers[i]; if ([vc cyl_getViewControllerInsteadOfNavigationController] == viewControllerInsteadIOfNavigationController) { isEmbedInTabBarController = YES; [self cyl_setTabIndex:i]; break; } } return isEmbedInTabBarController; } - (void)cyl_setTabIndex:(NSInteger)tabIndex { objc_setAssociatedObject(self, @selector(cyl_tabIndex), @(tabIndex), OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (NSInteger)cyl_tabIndex { if (!self.cyl_isEmbedInTabBarController) { return NSNotFound; } id tabIndexObject = objc_getAssociatedObject(self, @selector(cyl_tabIndex)); NSInteger tabIndex = [tabIndexObject integerValue]; return tabIndex; } - (UIControl *)cyl_tabButton { if (!self.cyl_isEmbedInTabBarController) { return nil; } UITabBarItem *tabBarItem; UIControl *control; @try { tabBarItem = self.cyl_tabBarController.tabBar.items[self.cyl_tabIndex]; control = [tabBarItem cyl_tabButton]; } @catch (NSException *exception) {} return control; } - (NSString *)cyl_context { return objc_getAssociatedObject(self, @selector(cyl_context)); } - (void)cyl_setContext:(NSString *)cyl_context { objc_setAssociatedObject(self, @selector(cyl_context), cyl_context, OBJC_ASSOCIATION_COPY_NONATOMIC); } - (BOOL)cyl_plusViewControllerEverAdded { NSNumber *cyl_plusViewControllerEverAddedObject = objc_getAssociatedObject(self, @selector(cyl_plusViewControllerEverAdded)); return [cyl_plusViewControllerEverAddedObject boolValue]; } - (void)cyl_setPlusViewControllerEverAdded:(BOOL)cyl_plusViewControllerEverAdded { NSNumber *cyl_plusViewControllerEverAddedObject = [NSNumber numberWithBool:cyl_plusViewControllerEverAdded]; objc_setAssociatedObject(self, @selector(cyl_plusViewControllerEverAdded), cyl_plusViewControllerEverAddedObject, OBJC_ASSOCIATION_ASSIGN); } #pragma mark - #pragma mark - Private Methods - (NSArray<__kindof UIViewController *> *)cyl_getOtherSameClassTypeViewControllersInCurrentNavigationControllerStack:(UIViewController *)viewController { NSArray *currentNavigationControllerStack = [self.navigationController childViewControllers]; if (currentNavigationControllerStack.count < 2) { return nil; } NSMutableArray *mutableArray = [currentNavigationControllerStack mutableCopy]; [mutableArray removeObject:self]; currentNavigationControllerStack = [mutableArray copy]; __block NSMutableArray *mutableOtherViewControllersInNavigationControllerStack = [NSMutableArray arrayWithCapacity:currentNavigationControllerStack.count]; [currentNavigationControllerStack enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { UIViewController *otherViewController = obj; if ([otherViewController isKindOfClass:[viewController class]]) { [mutableOtherViewControllersInNavigationControllerStack addObject:otherViewController]; } }]; return [mutableOtherViewControllersInNavigationControllerStack copy]; } - (void)checkTabBarChildControllerValidityAtIndex:(NSUInteger)index { CYLTabBarController *tabBarController = [[self cyl_getViewControllerInsteadOfNavigationController] cyl_tabBarController]; @try { UIViewController *viewController; viewController = tabBarController.viewControllers[index]; UIButton *plusButton = CYLExternPlusButton; BOOL shouldConfigureSelectionStatus = (CYLPlusChildViewController) && ((index != CYLPlusButtonIndex) && (viewController != CYLPlusChildViewController)); if (shouldConfigureSelectionStatus) { plusButton.selected = NO; } } @catch (NSException *exception) { NSString *formatString = @"\n\n\ ------ BEGIN NSException Log ---------------------------------------------------------------------\n \ class name: %@ \n \ ------line: %@ \n \ ----reason: The Class Type or the index or its NavigationController you pass in method `-cyl_popSelectTabBarChildViewControllerAtIndex` or `-cyl_popSelectTabBarChildViewControllerForClassType` is not the item of CYLTabBarViewController \n \ ------ END ---------------------------------------------------------------------------------------\n\n"; NSString *reason = [NSString stringWithFormat:formatString, @(__PRETTY_FUNCTION__), @(__LINE__)]; NSLog(@"🔴类名与方法名:%@(在第%@行),描述:%@", @(__PRETTY_FUNCTION__), @(__LINE__), reason); } } - (NSInteger)cyl_indexForClassType:(Class)classType inViewControllers:(NSArray *)viewControllers { __block NSInteger atIndex = NSNotFound; [viewControllers enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { UIViewController *obj_ = [obj cyl_getViewControllerInsteadOfNavigationController]; if ([obj_ isKindOfClass:classType]) { atIndex = idx; *stop = YES; return; } }]; return atIndex; } - (void)cyl_handleNavigationBackAction { [self cyl_handleNavigationBackActionWithAnimated:YES]; } - (void)cyl_handleNavigationBackActionWithAnimated:(BOOL)animated { if (!self.presentationController) { [self.navigationController popViewControllerAnimated:animated]; return; } if (self.navigationController.viewControllers.count > 1) { [self.navigationController popViewControllerAnimated:animated]; } else { [self dismissViewControllerAnimated:animated completion:nil]; } } #pragma mark -- public methods /** * show badge with red dot style and CYLBadgeAnimationTypeNone by default. */ - (void)cyl_showBadge { [kActualView cyl_showBadge]; } - (void)cyl_showBadgeValue:(NSString *)value animationType:(CYLBadgeAnimationType)animationType { [kActualView cyl_showBadgeValue:value animationType:animationType]; } - (void)cyl_clearBadge { [kActualView cyl_clearBadge]; } - (void)cyl_resumeBadge { [kActualView cyl_resumeBadge]; } - (BOOL)cyl_isShowBadge { return [kActualView cyl_isShowBadge]; } - (BOOL)cyl_isPauseBadge { return [kActualView cyl_isPauseBadge]; } #pragma mark -- private method /** * Because UIBarButtonItem is kind of NSObject, it is not able to directly attach badge. This method is used to find actual view (non-nil) inside UIBarButtonItem instance. * * @return view */ - (UITabBarItem *)cyl_getActualBadgeSuperView { UIViewController *viewController = self.cyl_getViewControllerInsteadOfNavigationController; UITabBarItem *viewControllerItem = viewController.tabBarItem; UIControl *viewControllerControl = viewControllerItem.cyl_tabButton; UITabBarItem *navigationViewControllerItem = viewController.navigationController.tabBarItem; if (viewControllerControl) { return viewControllerItem; } return navigationViewControllerItem; } #pragma mark -- setter/getter - (UILabel *)cyl_badge { return kActualView.cyl_badge; } - (void)cyl_setBadge:(UILabel *)label { [kActualView cyl_setBadge:label]; } - (UIFont *)cyl_badgeFont { return kActualView.cyl_badgeFont; } - (void)cyl_setBadgeFont:(UIFont *)badgeFont { [kActualView cyl_setBadgeFont:badgeFont]; } - (UIColor *)cyl_badgeBackgroundColor { return [kActualView cyl_badgeBackgroundColor]; } - (void)cyl_setBadgeBackgroundColor:(UIColor *)badgeBackgroundColor { [kActualView cyl_setBadgeBackgroundColor:badgeBackgroundColor]; } - (UIColor *)cyl_badgeTextColor { return [kActualView cyl_badgeTextColor]; } - (void)cyl_setBadgeTextColor:(UIColor *)badgeTextColor { [kActualView cyl_setBadgeTextColor:badgeTextColor]; } - (CYLBadgeAnimationType)cyl_badgeAnimationType { return [kActualView cyl_badgeAnimationType]; } - (void)cyl_setBadgeAnimationType:(CYLBadgeAnimationType)animationType { [kActualView cyl_setBadgeAnimationType:animationType]; } - (CGRect)cyl_badgeFrame { return [kActualView cyl_badgeFrame]; } - (void)cyl_setBadgeFrame:(CGRect)badgeFrame { [kActualView cyl_setBadgeFrame:badgeFrame]; } - (CGPoint)cyl_badgeCenterOffset { return [kActualView cyl_badgeCenterOffset]; } - (void)cyl_setBadgeCenterOffset:(CGPoint)badgeCenterOffset { [kActualView cyl_setBadgeCenterOffset:badgeCenterOffset]; } - (NSInteger)cyl_badgeMaximumBadgeNumber { return [kActualView cyl_badgeMaximumBadgeNumber]; } - (void)cyl_setBadgeMaximumBadgeNumber:(NSInteger)badgeMaximumBadgeNumber { [kActualView cyl_setBadgeMaximumBadgeNumber:badgeMaximumBadgeNumber]; } - (CGFloat)cyl_badgeMargin { return [kActualView cyl_badgeMargin]; } - (void)cyl_setBadgeMargin:(CGFloat)badgeMargin { [kActualView cyl_setBadgeMargin:badgeMargin]; } - (CGFloat)cyl_badgeRadius { return [kActualView cyl_badgeRadius]; } - (void)cyl_setBadgeRadius:(CGFloat)badgeRadius { [kActualView cyl_setBadgeRadius:badgeRadius]; } - (CGFloat)cyl_badgeCornerRadius { return [kActualView cyl_badgeCornerRadius]; } - (void)cyl_setBadgeCornerRadius:(CGFloat)cyl_badgeCornerRadius { [kActualView cyl_setBadgeCornerRadius:cyl_badgeCornerRadius]; } @end ================================================ FILE: CYLTabBarController.podspec ================================================ Pod::Spec.new do |s| s.name = "CYLTabBarController" s.version = "1.29.2" s.summary = "Highly customizable tabBar and tabBarController for iOS" s.description = "[EN]It is an iOS UI module library for adding animation to iOS tabbar items and icons with Lottie. [CN]【中国特色 TabBar】一行代码实现 Lottie 动画TabBar,支持中间带+号的TabBar样式,自带红点角标,支持动态刷新。【iOS12 & iPhone XS MAX supported】" s.homepage = "https://github.com/ChenYilong/CYLTabBarController" s.license = { :type => 'MIT', :file => 'LICENSE' } s.author = { "ChenYilong" => "luohanchenyilong@163.com" } s.social_media_url = 'http://weibo.com/luohanchenyilong/' s.platform = :ios, '8.0' s.source = { :git => "https://github.com/ChenYilong/CYLTabBarController.git", :tag => s.version.to_s } s.requires_arc = true s.default_subspec = 'Core' s.subspec 'Core' do |core| core.source_files = 'CYLTabBarController', 'CYLTabBarController/**/*.{h,m}' core.public_header_files = 'CYLTabBarController/**/*.h' end s.subspec 'Lottie' do |lottie| lottie.dependency 'CYLTabBarController/Core' lottie.dependency "lottie-ios" , '~> 2.5.3' end end ================================================ FILE: CYLTabBarController.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 56676081F69A826056C45ADD /* Pods_CYLTabBarController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7EA6761185EC902A2428DDB4 /* Pods_CYLTabBarController.framework */; }; 9A1559C81CB6D4D300CAB1AF /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A1559C61CB6D4D300CAB1AF /* AppDelegate.m */; }; 9A1559DB1CB6D56500CAB1AF /* CYLHomeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A1559CC1CB6D56500CAB1AF /* CYLHomeViewController.m */; }; 9A1559DC1CB6D56500CAB1AF /* CYLMessageViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A1559CF1CB6D56500CAB1AF /* CYLMessageViewController.m */; }; 9A1559DD1CB6D56500CAB1AF /* CYLMineViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A1559D21CB6D56500CAB1AF /* CYLMineViewController.m */; }; 9A1559DE1CB6D56500CAB1AF /* CYLDetailsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A1559D51CB6D56500CAB1AF /* CYLDetailsViewController.m */; }; 9A1559DF1CB6D56500CAB1AF /* CYLSameCityViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A1559D71CB6D56500CAB1AF /* CYLSameCityViewController.m */; }; 9A1559E41CB6EB1F00CAB1AF /* CYLPlusButtonSubclass.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A1559E31CB6EB1F00CAB1AF /* CYLPlusButtonSubclass.m */; }; 9A3865F62266FA3C008EE46F /* tab_message_animate.json in Resources */ = {isa = PBXBuildFile; fileRef = 9A3865F22266FA3C008EE46F /* tab_message_animate.json */; }; 9A3865F72266FA3C008EE46F /* tab_home_animate.json in Resources */ = {isa = PBXBuildFile; fileRef = 9A3865F32266FA3C008EE46F /* tab_home_animate.json */; }; 9A3865F82266FA3C008EE46F /* tab_search_animate.json in Resources */ = {isa = PBXBuildFile; fileRef = 9A3865F42266FA3C008EE46F /* tab_search_animate.json */; }; 9A3865F92266FA3C008EE46F /* tab_me_animate.json in Resources */ = {isa = PBXBuildFile; fileRef = 9A3865F52266FA3C008EE46F /* tab_me_animate.json */; }; 9A7C59902181C39000EDB266 /* MainTabBarController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A7C598E2181C39000EDB266 /* MainTabBarController.m */; }; 9A98017D2461249F00E65289 /* green_lottie_tab_mine.json in Resources */ = {isa = PBXBuildFile; fileRef = 9A9801792461249F00E65289 /* green_lottie_tab_mine.json */; }; 9A98017E2461249F00E65289 /* green_lottie_tab_discover.json in Resources */ = {isa = PBXBuildFile; fileRef = 9A98017A2461249F00E65289 /* green_lottie_tab_discover.json */; }; 9A98017F2461249F00E65289 /* green_lottie_tab_news.json in Resources */ = {isa = PBXBuildFile; fileRef = 9A98017B2461249F00E65289 /* green_lottie_tab_news.json */; }; 9A9801802461249F00E65289 /* green_lottie_tab_home.json in Resources */ = {isa = PBXBuildFile; fileRef = 9A98017C2461249F00E65289 /* green_lottie_tab_home.json */; }; 9AC0181B1FE90AA1001EC2D6 /* CYLPlusDemoChildViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AC0181A1FE90AA1001EC2D6 /* CYLPlusDemoChildViewController.m */; }; 9AD7F5B022B7D4B6004BF0A0 /* gray_tabbar_me_animation.json in Resources */ = {isa = PBXBuildFile; fileRef = 9AD7F5AD22B7D4B6004BF0A0 /* gray_tabbar_me_animation.json */; }; 9AD7F5B122B7D4B6004BF0A0 /* gray_tabbar_home_animation.json in Resources */ = {isa = PBXBuildFile; fileRef = 9AD7F5AE22B7D4B6004BF0A0 /* gray_tabbar_home_animation.json */; }; 9AD7F5B222B7D4B6004BF0A0 /* gray_tabbar_message_animation.json in Resources */ = {isa = PBXBuildFile; fileRef = 9AD7F5AF22B7D4B6004BF0A0 /* gray_tabbar_message_animation.json */; }; 9AD7F5BA22B7D695004BF0A0 /* img_tab_message_0.png in Resources */ = {isa = PBXBuildFile; fileRef = 9AD7F5B322B7D694004BF0A0 /* img_tab_message_0.png */; }; 9AD7F5BB22B7D695004BF0A0 /* img_tab_me_1.png in Resources */ = {isa = PBXBuildFile; fileRef = 9AD7F5B422B7D694004BF0A0 /* img_tab_me_1.png */; }; 9AD7F5BC22B7D695004BF0A0 /* img_tab_home_1.png in Resources */ = {isa = PBXBuildFile; fileRef = 9AD7F5B522B7D694004BF0A0 /* img_tab_home_1.png */; }; 9AD7F5BD22B7D695004BF0A0 /* img_tab_home_2.png in Resources */ = {isa = PBXBuildFile; fileRef = 9AD7F5B622B7D695004BF0A0 /* img_tab_home_2.png */; }; 9AD7F5BE22B7D695004BF0A0 /* img_tab_home_0.png in Resources */ = {isa = PBXBuildFile; fileRef = 9AD7F5B722B7D695004BF0A0 /* img_tab_home_0.png */; }; 9AD7F5BF22B7D695004BF0A0 /* img_tab_message_1.png in Resources */ = {isa = PBXBuildFile; fileRef = 9AD7F5B822B7D695004BF0A0 /* img_tab_message_1.png */; }; 9AD7F5C022B7D695004BF0A0 /* img_tab_me_0.png in Resources */ = {isa = PBXBuildFile; fileRef = 9AD7F5B922B7D695004BF0A0 /* img_tab_me_0.png */; }; 9AE0BD3122303BA800302A35 /* CYLMainRootViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AE0BD3022303BA800302A35 /* CYLMainRootViewController.m */; }; 9AE942E71BDC933E00354519 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9AE942CB1BDC933E00354519 /* LaunchScreen.xib */; }; 9AE942E81BDC933E00354519 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9AE942CD1BDC933E00354519 /* Main.storyboard */; }; 9AE942EF1BDC933E00354519 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9AE942E31BDC933E00354519 /* Images.xcassets */; }; 9AE942F11BDC933E00354519 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AE942E51BDC933E00354519 /* main.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 7EA6761185EC902A2428DDB4 /* Pods_CYLTabBarController.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_CYLTabBarController.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 89D5086598A9EFD751C286DB /* Pods-CYLTabBarController.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CYLTabBarController.debug.xcconfig"; path = "Target Support Files/Pods-CYLTabBarController/Pods-CYLTabBarController.debug.xcconfig"; sourceTree = ""; }; 8A12E1E008D40054CA1B0110 /* Pods-CYLTabBarController.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CYLTabBarController.release.xcconfig"; path = "Target Support Files/Pods-CYLTabBarController/Pods-CYLTabBarController.release.xcconfig"; sourceTree = ""; }; 9A1559C61CB6D4D300CAB1AF /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 9A1559C71CB6D4D300CAB1AF /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 9A1559CB1CB6D56500CAB1AF /* CYLHomeViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CYLHomeViewController.h; sourceTree = ""; }; 9A1559CC1CB6D56500CAB1AF /* CYLHomeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CYLHomeViewController.m; sourceTree = ""; }; 9A1559CE1CB6D56500CAB1AF /* CYLMessageViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CYLMessageViewController.h; sourceTree = ""; }; 9A1559CF1CB6D56500CAB1AF /* CYLMessageViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CYLMessageViewController.m; sourceTree = ""; }; 9A1559D11CB6D56500CAB1AF /* CYLMineViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CYLMineViewController.h; sourceTree = ""; }; 9A1559D21CB6D56500CAB1AF /* CYLMineViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CYLMineViewController.m; sourceTree = ""; }; 9A1559D41CB6D56500CAB1AF /* CYLDetailsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CYLDetailsViewController.h; sourceTree = ""; }; 9A1559D51CB6D56500CAB1AF /* CYLDetailsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CYLDetailsViewController.m; sourceTree = ""; }; 9A1559D61CB6D56500CAB1AF /* CYLSameCityViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CYLSameCityViewController.h; sourceTree = ""; }; 9A1559D71CB6D56500CAB1AF /* CYLSameCityViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CYLSameCityViewController.m; sourceTree = ""; }; 9A1559E21CB6EB1F00CAB1AF /* CYLPlusButtonSubclass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CYLPlusButtonSubclass.h; sourceTree = ""; }; 9A1559E31CB6EB1F00CAB1AF /* CYLPlusButtonSubclass.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CYLPlusButtonSubclass.m; sourceTree = ""; }; 9A3865F22266FA3C008EE46F /* tab_message_animate.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = tab_message_animate.json; sourceTree = ""; }; 9A3865F32266FA3C008EE46F /* tab_home_animate.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = tab_home_animate.json; sourceTree = ""; }; 9A3865F42266FA3C008EE46F /* tab_search_animate.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = tab_search_animate.json; sourceTree = ""; }; 9A3865F52266FA3C008EE46F /* tab_me_animate.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = tab_me_animate.json; sourceTree = ""; }; 9A579C98225F6E3A00F3C8F0 /* Location.gpx */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = Location.gpx; path = ../../../../../Location.gpx; sourceTree = ""; }; 9A7C598E2181C39000EDB266 /* MainTabBarController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MainTabBarController.m; sourceTree = ""; }; 9A7C598F2181C39000EDB266 /* MainTabBarController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MainTabBarController.h; sourceTree = ""; }; 9A9801792461249F00E65289 /* green_lottie_tab_mine.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = green_lottie_tab_mine.json; sourceTree = ""; }; 9A98017A2461249F00E65289 /* green_lottie_tab_discover.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = green_lottie_tab_discover.json; sourceTree = ""; }; 9A98017B2461249F00E65289 /* green_lottie_tab_news.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = green_lottie_tab_news.json; sourceTree = ""; }; 9A98017C2461249F00E65289 /* green_lottie_tab_home.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = green_lottie_tab_home.json; sourceTree = ""; }; 9AC018191FE90AA1001EC2D6 /* CYLPlusDemoChildViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CYLPlusDemoChildViewController.h; sourceTree = ""; }; 9AC0181A1FE90AA1001EC2D6 /* CYLPlusDemoChildViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CYLPlusDemoChildViewController.m; sourceTree = ""; }; 9AD7F5AD22B7D4B6004BF0A0 /* gray_tabbar_me_animation.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = gray_tabbar_me_animation.json; sourceTree = ""; }; 9AD7F5AE22B7D4B6004BF0A0 /* gray_tabbar_home_animation.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = gray_tabbar_home_animation.json; sourceTree = ""; }; 9AD7F5AF22B7D4B6004BF0A0 /* gray_tabbar_message_animation.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = gray_tabbar_message_animation.json; sourceTree = ""; }; 9AD7F5B322B7D694004BF0A0 /* img_tab_message_0.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = img_tab_message_0.png; sourceTree = ""; }; 9AD7F5B422B7D694004BF0A0 /* img_tab_me_1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = img_tab_me_1.png; sourceTree = ""; }; 9AD7F5B522B7D694004BF0A0 /* img_tab_home_1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = img_tab_home_1.png; sourceTree = ""; }; 9AD7F5B622B7D695004BF0A0 /* img_tab_home_2.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = img_tab_home_2.png; sourceTree = ""; }; 9AD7F5B722B7D695004BF0A0 /* img_tab_home_0.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = img_tab_home_0.png; sourceTree = ""; }; 9AD7F5B822B7D695004BF0A0 /* img_tab_message_1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = img_tab_message_1.png; sourceTree = ""; }; 9AD7F5B922B7D695004BF0A0 /* img_tab_me_0.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = img_tab_me_0.png; sourceTree = ""; }; 9AE0BD2F22303BA800302A35 /* CYLMainRootViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CYLMainRootViewController.h; sourceTree = ""; }; 9AE0BD3022303BA800302A35 /* CYLMainRootViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CYLMainRootViewController.m; sourceTree = ""; }; 9AE942741BDC91B800354519 /* CYLTabBarController.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CYLTabBarController.app; sourceTree = BUILT_PRODUCTS_DIR; }; 9AE942921BDC91B900354519 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 9AE942931BDC91B900354519 /* CYLTabBarControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CYLTabBarControllerTests.m; sourceTree = ""; }; 9AE942CC1BDC933E00354519 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 9AE942CE1BDC933E00354519 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 9AE942E31BDC933E00354519 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 9AE942E41BDC933E00354519 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 9AE942E51BDC933E00354519 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 9AE942711BDC91B800354519 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 56676081F69A826056C45ADD /* Pods_CYLTabBarController.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 36A0A7E83F2E6D2B770F8CDA /* Pods */ = { isa = PBXGroup; children = ( 89D5086598A9EFD751C286DB /* Pods-CYLTabBarController.debug.xcconfig */, 8A12E1E008D40054CA1B0110 /* Pods-CYLTabBarController.release.xcconfig */, ); path = Pods; sourceTree = ""; }; 7D5EF7117AB467CA9F870F71 /* Frameworks */ = { isa = PBXGroup; children = ( 7EA6761185EC902A2428DDB4 /* Pods_CYLTabBarController.framework */, ); name = Frameworks; sourceTree = ""; }; 9A1559C91CB6D56500CAB1AF /* Module */ = { isa = PBXGroup; children = ( 9AC018181FE90A70001EC2D6 /* Other */, 9A1559CA1CB6D56500CAB1AF /* Home */, 9A1559CD1CB6D56500CAB1AF /* Message */, 9A1559D01CB6D56500CAB1AF /* Mine */, 9A1559D31CB6D56500CAB1AF /* SameCity */, ); path = Module; sourceTree = ""; }; 9A1559CA1CB6D56500CAB1AF /* Home */ = { isa = PBXGroup; children = ( 9A1559CB1CB6D56500CAB1AF /* CYLHomeViewController.h */, 9A1559CC1CB6D56500CAB1AF /* CYLHomeViewController.m */, ); path = Home; sourceTree = ""; }; 9A1559CD1CB6D56500CAB1AF /* Message */ = { isa = PBXGroup; children = ( 9A1559CE1CB6D56500CAB1AF /* CYLMessageViewController.h */, 9A1559CF1CB6D56500CAB1AF /* CYLMessageViewController.m */, ); path = Message; sourceTree = ""; }; 9A1559D01CB6D56500CAB1AF /* Mine */ = { isa = PBXGroup; children = ( 9A1559D11CB6D56500CAB1AF /* CYLMineViewController.h */, 9A1559D21CB6D56500CAB1AF /* CYLMineViewController.m */, ); path = Mine; sourceTree = ""; }; 9A1559D31CB6D56500CAB1AF /* SameCity */ = { isa = PBXGroup; children = ( 9A1559D41CB6D56500CAB1AF /* CYLDetailsViewController.h */, 9A1559D51CB6D56500CAB1AF /* CYLDetailsViewController.m */, 9A1559D61CB6D56500CAB1AF /* CYLSameCityViewController.h */, 9A1559D71CB6D56500CAB1AF /* CYLSameCityViewController.m */, 9A579C98225F6E3A00F3C8F0 /* Location.gpx */, ); path = SameCity; sourceTree = ""; }; 9A1559E11CB6EB1F00CAB1AF /* View */ = { isa = PBXGroup; children = ( 9A1559E21CB6EB1F00CAB1AF /* CYLPlusButtonSubclass.h */, 9A1559E31CB6EB1F00CAB1AF /* CYLPlusButtonSubclass.m */, ); path = View; sourceTree = ""; }; 9A3865CF22663549008EE46F /* Other */ = { isa = PBXGroup; children = ( 9A3865D5226635A1008EE46F /* LottieResources */, ); path = Other; sourceTree = ""; }; 9A3865D5226635A1008EE46F /* LottieResources */ = { isa = PBXGroup; children = ( 9AD7F5B722B7D695004BF0A0 /* img_tab_home_0.png */, 9AD7F5B522B7D694004BF0A0 /* img_tab_home_1.png */, 9AD7F5B622B7D695004BF0A0 /* img_tab_home_2.png */, 9AD7F5B922B7D695004BF0A0 /* img_tab_me_0.png */, 9AD7F5B422B7D694004BF0A0 /* img_tab_me_1.png */, 9AD7F5B322B7D694004BF0A0 /* img_tab_message_0.png */, 9AD7F5B822B7D695004BF0A0 /* img_tab_message_1.png */, 9AD7F5AE22B7D4B6004BF0A0 /* gray_tabbar_home_animation.json */, 9AD7F5AD22B7D4B6004BF0A0 /* gray_tabbar_me_animation.json */, 9AD7F5AF22B7D4B6004BF0A0 /* gray_tabbar_message_animation.json */, 9A3865F32266FA3C008EE46F /* tab_home_animate.json */, 9A3865F52266FA3C008EE46F /* tab_me_animate.json */, 9A3865F22266FA3C008EE46F /* tab_message_animate.json */, 9A3865F42266FA3C008EE46F /* tab_search_animate.json */, 9A98017A2461249F00E65289 /* green_lottie_tab_discover.json */, 9A98017C2461249F00E65289 /* green_lottie_tab_home.json */, 9A9801792461249F00E65289 /* green_lottie_tab_mine.json */, 9A98017B2461249F00E65289 /* green_lottie_tab_news.json */, ); path = LottieResources; sourceTree = ""; }; 9AC018181FE90A70001EC2D6 /* Other */ = { isa = PBXGroup; children = ( 9AC018191FE90AA1001EC2D6 /* CYLPlusDemoChildViewController.h */, 9AC0181A1FE90AA1001EC2D6 /* CYLPlusDemoChildViewController.m */, ); path = Other; sourceTree = ""; }; 9AE9426B1BDC91B800354519 = { isa = PBXGroup; children = ( 9AE942C81BDC933E00354519 /* Example */, 9AE942901BDC91B900354519 /* CYLTabBarControllerTests */, 9AE942751BDC91B800354519 /* Products */, 36A0A7E83F2E6D2B770F8CDA /* Pods */, 7D5EF7117AB467CA9F870F71 /* Frameworks */, ); sourceTree = ""; }; 9AE942751BDC91B800354519 /* Products */ = { isa = PBXGroup; children = ( 9AE942741BDC91B800354519 /* CYLTabBarController.app */, ); name = Products; sourceTree = ""; }; 9AE942901BDC91B900354519 /* CYLTabBarControllerTests */ = { isa = PBXGroup; children = ( 9AE942931BDC91B900354519 /* CYLTabBarControllerTests.m */, 9AE942911BDC91B900354519 /* Supporting Files */, ); path = CYLTabBarControllerTests; sourceTree = ""; }; 9AE942911BDC91B900354519 /* Supporting Files */ = { isa = PBXGroup; children = ( 9AE942921BDC91B900354519 /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; }; 9AE942C81BDC933E00354519 /* Example */ = { isa = PBXGroup; children = ( 9A1559C71CB6D4D300CAB1AF /* AppDelegate.h */, 9A1559C61CB6D4D300CAB1AF /* AppDelegate.m */, 9A7C598F2181C39000EDB266 /* MainTabBarController.h */, 9A7C598E2181C39000EDB266 /* MainTabBarController.m */, 9AE0BD2F22303BA800302A35 /* CYLMainRootViewController.h */, 9AE0BD3022303BA800302A35 /* CYLMainRootViewController.m */, 9AE942CF1BDC933E00354519 /* Classes */, 9AE942CB1BDC933E00354519 /* LaunchScreen.xib */, 9AE942CD1BDC933E00354519 /* Main.storyboard */, 9AE942E31BDC933E00354519 /* Images.xcassets */, 9AE942E41BDC933E00354519 /* Info.plist */, 9AE942E51BDC933E00354519 /* main.m */, ); path = Example; sourceTree = ""; }; 9AE942CF1BDC933E00354519 /* Classes */ = { isa = PBXGroup; children = ( 9A3865CF22663549008EE46F /* Other */, 9A1559E11CB6EB1F00CAB1AF /* View */, 9A1559C91CB6D56500CAB1AF /* Module */, ); path = Classes; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 9AE942731BDC91B800354519 /* CYLTabBarController */ = { isa = PBXNativeTarget; buildConfigurationList = 9AE942971BDC91B900354519 /* Build configuration list for PBXNativeTarget "CYLTabBarController" */; buildPhases = ( 5B2F02C6CEFA9E652D86AB7B /* [CP] Check Pods Manifest.lock */, 9AE942701BDC91B800354519 /* Sources */, 9AE942711BDC91B800354519 /* Frameworks */, 9AE942721BDC91B800354519 /* Resources */, 21663BD34D0451A2C1920020 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); dependencies = ( ); name = CYLTabBarController; productName = CYLTabBarController; productReference = 9AE942741BDC91B800354519 /* CYLTabBarController.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 9AE9426C1BDC91B800354519 /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 1100; ORGANIZATIONNAME = "微博@iOS程序犭袁"; TargetAttributes = { 9AE942731BDC91B800354519 = { CreatedOnToolsVersion = 6.3; ProvisioningStyle = Manual; }; }; }; buildConfigurationList = 9AE9426F1BDC91B800354519 /* Build configuration list for PBXProject "CYLTabBarController" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 9AE9426B1BDC91B800354519; productRefGroup = 9AE942751BDC91B800354519 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 9AE942731BDC91B800354519 /* CYLTabBarController */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 9AE942721BDC91B800354519 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 9A9801802461249F00E65289 /* green_lottie_tab_home.json in Resources */, 9AE942EF1BDC933E00354519 /* Images.xcassets in Resources */, 9A98017F2461249F00E65289 /* green_lottie_tab_news.json in Resources */, 9AD7F5BE22B7D695004BF0A0 /* img_tab_home_0.png in Resources */, 9AE942E71BDC933E00354519 /* LaunchScreen.xib in Resources */, 9AD7F5B122B7D4B6004BF0A0 /* gray_tabbar_home_animation.json in Resources */, 9A3865F82266FA3C008EE46F /* tab_search_animate.json in Resources */, 9A98017D2461249F00E65289 /* green_lottie_tab_mine.json in Resources */, 9AD7F5BA22B7D695004BF0A0 /* img_tab_message_0.png in Resources */, 9AD7F5B022B7D4B6004BF0A0 /* gray_tabbar_me_animation.json in Resources */, 9AD7F5B222B7D4B6004BF0A0 /* gray_tabbar_message_animation.json in Resources */, 9A98017E2461249F00E65289 /* green_lottie_tab_discover.json in Resources */, 9AD7F5C022B7D695004BF0A0 /* img_tab_me_0.png in Resources */, 9AE942E81BDC933E00354519 /* Main.storyboard in Resources */, 9A3865F92266FA3C008EE46F /* tab_me_animate.json in Resources */, 9A3865F72266FA3C008EE46F /* tab_home_animate.json in Resources */, 9AD7F5BC22B7D695004BF0A0 /* img_tab_home_1.png in Resources */, 9AD7F5BD22B7D695004BF0A0 /* img_tab_home_2.png in Resources */, 9A3865F62266FA3C008EE46F /* tab_message_animate.json in Resources */, 9AD7F5BB22B7D695004BF0A0 /* img_tab_me_1.png in Resources */, 9AD7F5BF22B7D695004BF0A0 /* img_tab_message_1.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 21663BD34D0451A2C1920020 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-CYLTabBarController/Pods-CYLTabBarController-frameworks.sh", "${BUILT_PRODUCTS_DIR}/CYLTabBarController/CYLTabBarController.framework", "${BUILT_PRODUCTS_DIR}/MJRefresh/MJRefresh.framework", "${BUILT_PRODUCTS_DIR}/lottie-ios/Lottie.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CYLTabBarController.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MJRefresh.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Lottie.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-CYLTabBarController/Pods-CYLTabBarController-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; 5B2F02C6CEFA9E652D86AB7B /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; outputFileListPaths = ( ); outputPaths = ( "$(DERIVED_FILE_DIR)/Pods-CYLTabBarController-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 9AE942701BDC91B800354519 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 9A1559DC1CB6D56500CAB1AF /* CYLMessageViewController.m in Sources */, 9AE0BD3122303BA800302A35 /* CYLMainRootViewController.m in Sources */, 9A1559DE1CB6D56500CAB1AF /* CYLDetailsViewController.m in Sources */, 9A1559E41CB6EB1F00CAB1AF /* CYLPlusButtonSubclass.m in Sources */, 9A1559DF1CB6D56500CAB1AF /* CYLSameCityViewController.m in Sources */, 9A1559DB1CB6D56500CAB1AF /* CYLHomeViewController.m in Sources */, 9A1559C81CB6D4D300CAB1AF /* AppDelegate.m in Sources */, 9A7C59902181C39000EDB266 /* MainTabBarController.m in Sources */, 9A1559DD1CB6D56500CAB1AF /* CYLMineViewController.m in Sources */, 9AE942F11BDC933E00354519 /* main.m in Sources */, 9AC0181B1FE90AA1001EC2D6 /* CYLPlusDemoChildViewController.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ 9AE942CB1BDC933E00354519 /* LaunchScreen.xib */ = { isa = PBXVariantGroup; children = ( 9AE942CC1BDC933E00354519 /* Base */, ); name = LaunchScreen.xib; sourceTree = ""; }; 9AE942CD1BDC933E00354519 /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( 9AE942CE1BDC933E00354519 /* Base */, ); name = Main.storyboard; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 9AE942951BDC91B900354519 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; 9AE942961BDC91B900354519 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; name = Release; }; 9AE942981BDC91B900354519 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 89D5086598A9EFD751C286DB /* Pods-CYLTabBarController.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; CODE_SIGN_ENTITLEMENTS = ""; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Manual; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = "$(SRCROOT)/Example/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "CYL.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; PROVISIONING_PROFILE_SPECIFIER = ""; SUPPORTS_UIKITFORMAC = NO; TARGETED_DEVICE_FAMILY = 1; }; name = Debug; }; 9AE942991BDC91B900354519 /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 8A12E1E008D40054CA1B0110 /* Pods-CYLTabBarController.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; CODE_SIGN_ENTITLEMENTS = ""; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Manual; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = "$(SRCROOT)/Example/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "CYL.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; PROVISIONING_PROFILE_SPECIFIER = ""; SUPPORTS_UIKITFORMAC = NO; TARGETED_DEVICE_FAMILY = 1; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 9AE9426F1BDC91B800354519 /* Build configuration list for PBXProject "CYLTabBarController" */ = { isa = XCConfigurationList; buildConfigurations = ( 9AE942951BDC91B900354519 /* Debug */, 9AE942961BDC91B900354519 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 9AE942971BDC91B900354519 /* Build configuration list for PBXNativeTarget "CYLTabBarController" */ = { isa = XCConfigurationList; buildConfigurations = ( 9AE942981BDC91B900354519 /* Debug */, 9AE942991BDC91B900354519 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 9AE9426C1BDC91B800354519 /* Project object */; } ================================================ FILE: CYLTabBarController.xcodeproj/xcshareddata/xcschemes/CYLTabBarController.xcscheme ================================================ ================================================ FILE: CYLTabBarControllerTests/CYLTabBarControllerTests.m ================================================ // // CYLTabBarControllerTests.m // CYLTabBarControllerTests // // v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 15/10/25. // Copyright (c) 2018年 https://github.com/ChenYilong .All rights reserved. // #import #import @interface CYLTabBarControllerTests : XCTestCase @end @implementation CYLTabBarControllerTests - (void)setUp { [super setUp]; // Put setup code here. This method is called before the invocation of each test method in the class. } - (void)tearDown { // Put teardown code here. This method is called after the invocation of each test method in the class. [super tearDown]; } - (void)testExample { // This is an example of a functional test case. XCTAssert(YES, @"Pass"); } - (void)testPerformanceExample { // This is an example of a performance test case. [self measureBlock:^{ // Put the code you want to measure the time of here. }]; } @end ================================================ FILE: CYLTabBarControllerTests/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 ================================================ FILE: Example/AppDelegate.h ================================================ // // AppDelegate.h // CYLTabBarControllerDemo // // v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/20/15. // Copyright © 2018 https://github.com/ChenYilong . All rights reserved. // #import @interface AppDelegate : UIResponder @property (strong, nonatomic) UIWindow *window; @end ================================================ FILE: Example/AppDelegate.m ================================================ // // AppDelegate.m // CYLTabBarController // // v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/20/15. // Copyright © 2018 https://github.com/ChenYilong . All rights reserved. // #import "AppDelegate.h" #import "CYLPlusButtonSubclass.h" #import "CYLMainRootViewController.h" @interface AppDelegate () @property (nonatomic, strong) NSMutableData *data; @end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [UIApplication sharedApplication].statusBarHidden = NO; // 设置主窗口,并设置根控制器 self.window = [[UIWindow alloc] init]; self.window.frame = [UIScreen mainScreen].bounds; [self.window makeKeyAndVisible]; CYLMainRootViewController *rootViewController = [[CYLMainRootViewController alloc] init]; [self.window setRootViewController:rootViewController]; [self setUpNavigationBarAppearance]; return YES; } #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wmethod-signatures" - (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window { //设置强制旋转屏幕 if (self.cyl_isForceLandscape) { //只支持横屏 return UIInterfaceOrientationMaskLandscape; } else { //只支持竖屏 return UIInterfaceOrientationMaskPortrait; } } #pragma clang diagnostic pop /** * 设置navigationBar样式 */ - (void)setUpNavigationBarAppearance { UINavigationBar *navigationBarAppearance = [UINavigationBar appearance]; UIColor *backgroundColor = [UIColor cyl_systemBackgroundColor]; NSDictionary *textAttributes = nil; UIColor *labelColor = [UIColor cyl_labelColor]; if (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_6_1) { textAttributes = @{ NSFontAttributeName : [UIFont boldSystemFontOfSize:18], NSForegroundColorAttributeName : labelColor, }; } else { #if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0 textAttributes = @{ UITextAttributeFont : [UIFont boldSystemFontOfSize:18], UITextAttributeTextColor : labelColor, UITextAttributeTextShadowColor : [UIColor clearColor], UITextAttributeTextShadowOffset : [NSValue valueWithUIOffset:UIOffsetZero], }; #endif } [navigationBarAppearance setBarTintColor:backgroundColor]; [navigationBarAppearance setTitleTextAttributes:textAttributes]; } @end ================================================ FILE: Example/Base.lproj/LaunchScreen.xib ================================================ ================================================ FILE: Example/Base.lproj/Main.storyboard ================================================ ================================================ FILE: Example/CYLMainRootViewController.h ================================================ // // CYLMainRootViewController.h // CYLTabBarController // // Created by chenyilong on 7/3/2019. // Copyright © 2019 微博@iOS程序犭袁. All rights reserved. // #import #if __has_include() #import #else #import "CYLTabBarController.h" #endif NS_ASSUME_NONNULL_BEGIN @interface CYLMainRootViewController : UINavigationController - (CYLTabBarController *)createNewTabBarWithContext:(NSString *)context; @end NS_ASSUME_NONNULL_END ================================================ FILE: Example/CYLMainRootViewController.m ================================================ // // CYLMainRootViewController.m // CYLTabBarController // // Created by chenyilong on 7/3/2019. // Copyright © 2019 微博@iOS程序犭袁. All rights reserved. // #import "CYLMainRootViewController.h" #import "MainTabBarController.h" #import "CYLPlusButtonSubclass.h" @interface CYLMainRootViewController () @end @implementation CYLMainRootViewController - (void)viewDidLoad { [super viewDidLoad]; self.navigationBarHidden = YES; self.view.backgroundColor = [UIColor whiteColor]; [self createNewTabBar]; } - (CYLTabBarController *)createNewTabBar { [CYLPlusButtonSubclass registerPlusButton]; return [self createNewTabBarWithContext:nil]; } - (CYLTabBarController *)createNewTabBarWithContext:(NSString *)context { MainTabBarController *tabBarController = [[MainTabBarController alloc] initWithContext:context]; self.viewControllers = @[tabBarController]; return tabBarController; } @end ================================================ FILE: Example/Classes/Module/Home/CYLHomeViewController.h ================================================ // // CYLHomeViewController.h // CYLTabBarController // // v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/20/15. // Copyright © 2018 https://github.com/ChenYilong . All rights reserved. // #import #if __has_include() #import #else #import "CYLTabBarController.h" #endif @interface CYLHomeViewController : CYLBaseTableViewController - (void)refresh; @end ================================================ FILE: Example/Classes/Module/Home/CYLHomeViewController.m ================================================ // // CYLHomeViewController.m // CYLTabBarController // // v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/20/15. // Copyright © 2018 https://github.com/ChenYilong . All rights reserved. // #import "CYLHomeViewController.h" //#import "CYLTabBarControllerConfig.h" //#import "CYLPlusButtonSubclass.h" #import "MainTabBarController.h" #import "CYLMainRootViewController.h" #import @implementation CYLHomeViewController #pragma mark - View lifecycle - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor whiteColor]; self.navigationItem.title = @"首页(3)"; //✅sets navigation bar title.The right way to set the title of the navigation self.tabBarItem.title = @"首页"; //❌sets tab bar title. Even the `tabBarItem.title` changed, this will be ignored in tabbar. //self.title = @"首页1"; //❌sets both of these. Do not do this‼️‼️This may cause something strange like this : http://i68.tinypic.com/282l3x4.jpg . // [self.navigationController.tabBarItem setBadgeValue:@"3"]; self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"refresh TabBar" style:UIBarButtonItemStylePlain target:self action:@selector(refreshTabBar:)]; __weak __typeof(self) weakSelf = self; self.tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{ //Call this Block When enter the refresh status automatically NSUInteger delaySeconds = 1; dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delaySeconds * NSEC_PER_SEC)); dispatch_after(when, dispatch_get_main_queue(), ^{ [weakSelf.tableView.mj_header endRefreshing]; }); }]; } - (void)refresh { [self.tableView.mj_header beginRefreshing]; NSUInteger delaySeconds = 1; dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delaySeconds * NSEC_PER_SEC)); dispatch_after(when, dispatch_get_main_queue(), ^{ [self.tableView.mj_header endRefreshing]; }); } - (void)refreshTabBar:(id)sender { [self createNewTabBardynamically]; } - (void)createNewTabBardynamically { id delegate = ((id)[[UIApplication sharedApplication] delegate]); UIWindow *window = delegate.window; CYLMainRootViewController *rootController = (CYLMainRootViewController *)window.rootViewController; [rootController createNewTabBarWithContext:NSStringFromClass([self class])]; } #pragma mark - Methods - (void)configureCell:(UITableViewCell *)cell forIndexPath:(NSIndexPath *)indexPath { [[cell textLabel] setText:[NSString stringWithFormat:@"%@ CYLTabBarController %@", self.tabBarItem.title, @(indexPath.row)]]; } #pragma mark - Table view - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString * CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (!cell) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; } [self configureCell:cell forIndexPath:indexPath]; return cell; } #pragma mark - UINavigationControllerDelegate - (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animate { if ([navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) { if ([navigationController.viewControllers count] == 1) { navigationController.interactivePopGestureRecognizer.enabled = NO; } else { navigationController.interactivePopGestureRecognizer.enabled = YES; } } } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return 30; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView deselectRowAtIndexPath:indexPath animated:YES]; NSNumber *badgeNumber = @(indexPath.row); self.navigationItem.title = [NSString stringWithFormat:@"首页(%@)", badgeNumber]; //sets navigation bar title. // [self.navigationController.tabBarItem setBadgeValue:[NSString stringWithFormat:@"%@", badgeNumber]]; // CYLTabBarControllerConfig *tabBarControllerConfig = [[CYLTabBarControllerConfig alloc] init]; // CYLTabBarController *tabBarController = tabBarControllerConfig.tabBarController; // tabBarController.delegate = self; // [self cyl_showBadgeValue:[NSString stringWithFormat:@"%@", @(indexPath.row)] animationType:CYLBadgeAnimationTypeScale]; [self pushToNewViewController]; } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [self pushToNewViewController]; } - (void)pushToNewViewController { CYLBaseViewController *viewController = [CYLBaseViewController new]; viewController.view.backgroundColor = [UIColor orangeColor]; [viewController cyl_setNavigationBarHidden:YES]; [self.navigationController pushViewController:viewController animated:YES]; } @end ================================================ FILE: Example/Classes/Module/Message/CYLMessageViewController.h ================================================ // // CYLMessageViewController.h // CYLTabBarController // // v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/20/15. // Copyright © 2018 https://github.com/ChenYilong . All rights reserved. // #import #if __has_include() #import #else #import "CYLTabBarController.h" #endif @interface CYLMessageViewController : CYLBaseTableViewController - (void)refresh; @end ================================================ FILE: Example/Classes/Module/Message/CYLMessageViewController.m ================================================ // // CYLMessageViewController.m // CYLTabBarController // // v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/20/15. // Copyright © 2018 https://github.com/ChenYilong . All rights reserved. // #import "CYLMessageViewController.h" #import "CYLMainRootViewController.h" #import @implementation CYLMessageViewController #pragma mark - View lifecycle - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor whiteColor]; self.navigationItem.title = @"消息"; //✅sets navigation bar title.The right way to set the title of the navigation self.tabBarItem.title = @"消息"; //❌sets tab bar title. Even the `tabBarItem.title` changed, this will be ignored in tabbar. //self.title = @"消息1"; //❌sets both of these. Do not do this‼️‼️ This may cause something strange like this : http://i68.tinypic.com/282l3x4.jpg . __weak __typeof(self) weakSelf = self; self.tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{ //Call this Block When enter the refresh status automatically NSUInteger delaySeconds = 1; dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delaySeconds * NSEC_PER_SEC)); dispatch_after(when, dispatch_get_main_queue(), ^{ [weakSelf.tableView.mj_header endRefreshing]; }); }]; } - (void)refresh { [self.tableView.mj_header beginRefreshing]; NSUInteger delaySeconds = 1; dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delaySeconds * NSEC_PER_SEC)); dispatch_after(when, dispatch_get_main_queue(), ^{ [self.tableView.mj_header endRefreshing]; }); } #pragma mark - Methods - (void)viewDidAppear:(BOOL)animated { [self.navigationItem.leftBarButtonItem cyl_showBadge]; } - (void)configureCell:(UITableViewCell *)cell forIndexPath:(NSIndexPath *)indexPath { [[cell textLabel] setText:[NSString stringWithFormat:@"%@ CYLTabBarController %@", self.tabBarItem.title, @(indexPath.row)]]; } #pragma mark - Table view - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString * CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (!cell) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; } [self configureCell:cell forIndexPath:indexPath]; return cell; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView deselectRowAtIndexPath:indexPath animated:YES]; // NSNumber *badgeNumber = @(indexPath.row); // self.navigationItem.title = [NSString stringWithFormat:@"首页(%@)", badgeNumber]; //sets navigation bar title. // [self.navigationController.tabBarItem setBadgeValue:[NSString stringWithFormat:@"%@", badgeNumber]]; // CYLTabBarControllerConfig *tabBarControllerConfig = [[CYLTabBarControllerConfig alloc] init]; // CYLTabBarController *tabBarController = tabBarControllerConfig.tabBarController; // tabBarController.delegate = self; // // [self cyl_showBadgeValue:[NSString stringWithFormat:@"%@", @(indexPath.row)] animationType:CYLBadgeAnimationTypeScale]; // [self pushToNewViewController]; CYLTabBarController *tabBarController = [[CYLMainRootViewController new] createNewTabBarWithContext:NSStringFromClass([self class])]; [self.navigationController pushViewController:tabBarController animated:YES]; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return 15; } @end ================================================ FILE: Example/Classes/Module/Mine/CYLMineViewController.h ================================================ // // CYLMineViewController.h // CYLTabBarController // // v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/20/15. // Copyright © 2018 https://github.com/ChenYilong . All rights reserved. // #import #if __has_include() #import #else #import "CYLTabBarController.h" #endif @interface CYLMineViewController : CYLBaseTableViewController - (void)testPush; - (void)refresh; @end ================================================ FILE: Example/Classes/Module/Mine/CYLMineViewController.m ================================================ // // CYLMineViewController.m // CYLTabBarController // // v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/20/15. // Copyright © 2018 https://github.com/ChenYilong . All rights reserved. // #import "CYLMineViewController.h" #import "CYLDetailsViewController.h" #import @implementation CYLMineViewController #pragma mark - View lifecycle - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor whiteColor]; self.navigationItem.title = @"我的"; //✅sets navigation bar title.The right way to set the title of the navigation self.tabBarItem.title = @"我的"; //❌sets tab bar title. Even the `tabBarItem.title` changed, this will be ignored in tabbar. //self.title = @"我的1"; //❌sets both of these. Do not do this‼️‼️ This may cause something strange like this : http://i68.tinypic.com/282l3x4.jpg . // [self.navigationController.tabBarItem setBadgeValue:@"3"]; __weak __typeof(self) weakSelf = self; self.tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{ //Call this Block When enter the refresh status automatically NSUInteger delaySeconds = 1; dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delaySeconds * NSEC_PER_SEC)); dispatch_after(when, dispatch_get_main_queue(), ^{ [weakSelf.tableView.mj_header endRefreshing]; }); }]; } - (void)refresh { [self.tableView.mj_header beginRefreshing]; NSUInteger delaySeconds = 1; dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delaySeconds * NSEC_PER_SEC)); dispatch_after(when, dispatch_get_main_queue(), ^{ [self.tableView.mj_header endRefreshing]; }); } #pragma mark - Methods - (void)configureCell:(UITableViewCell *)cell forIndexPath:(NSIndexPath *)indexPath { [[cell textLabel] setText:[NSString stringWithFormat:@"%@ CYLTabBarController %@", self.tabBarItem.title, @(indexPath.row)]]; } #pragma mark - Table view - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString * CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (!cell) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; } [self configureCell:cell forIndexPath:indexPath]; return cell; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return 30; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView deselectRowAtIndexPath:indexPath animated:YES]; [self cyl_showBadgeValue:[NSString stringWithFormat:@"%@", @(indexPath.row)] animationType:CYLBadgeAnimationTypeNone]; [self testPush]; } - (void)testPush { UIViewController *viewController = [[UIViewController alloc] init]; viewController.view.backgroundColor = [UIColor redColor]; [self.navigationController pushViewController:viewController animated:YES]; } @end ================================================ FILE: Example/Classes/Module/Other/CYLPlusDemoChildViewController.h ================================================ // // CYLPlusDemoChildViewController.h // CYLTabBarController // // Created by chenyilong on 19/12/2017. // Copyright © 2017 微博@iOS程序犭袁. All rights reserved. // #import @interface CYLPlusDemoChildViewController : UIViewController @end ================================================ FILE: Example/Classes/Module/Other/CYLPlusDemoChildViewController.m ================================================ // // CYLPlusDemoChildViewController.m // CYLTabBarController // // Created by chenyilong on 19/12/2017. // Copyright © 2017 微博@iOS程序犭袁. All rights reserved. // #import "CYLPlusDemoChildViewController.h" @interface CYLPlusDemoChildViewController () @end @implementation CYLPlusDemoChildViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } - (void)dealloc { NSLog(@"🔴类名与方法名:%@(在第%@行),描述:%@", @(__PRETTY_FUNCTION__), @(__LINE__), @""); } /* #pragma mark - Navigation // In a storyboard-based application, you will often want to do a little preparation before navigation - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { // Get the new view controller using [segue destinationViewController]. // Pass the selected object to the new view controller. } */ @end ================================================ FILE: Example/Classes/Module/SameCity/CYLDetailsViewController.h ================================================ // // CYLDetailsViewController.h // CYLTabBarController // // v1.21.x Created by Robert Dimitrov on 11/8/14. // Copyright (c) 2014 Robert Dimitrov. All rights reserved. // #import #if __has_include() #import #else #import "CYLTabBarController.h" #endif @interface CYLDetailsViewController : CYLBaseViewController @end ================================================ FILE: Example/Classes/Module/SameCity/CYLDetailsViewController.m ================================================ // // CYLDetailsViewController.m // CYLTabBarController // // v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/20/15. // Copyright © 2018 https://github.com/ChenYilong . All rights reserved. // #import "CYLDetailsViewController.h" #import "CYLMineViewController.h" #import "CYLSameCityViewController.h" #import "CYLHomeViewController.h" @interface CYLDetailsViewController () @end @implementation CYLDetailsViewController - (void)viewDidLoad { [super viewDidLoad]; self.title = @"详情页"; self.view.backgroundColor = [UIColor orangeColor]; UILabel *label = [[UILabel alloc] init]; label.text = @"点击屏幕可跳转到“我的”,执行testPush"; label.frame = CGRectMake(20, 150, CGRectGetWidth(self.view.frame) - 2 * 20, 20); label.autoresizingMask = UIViewAutoresizingFlexibleWidth; label.textAlignment = NSTextAlignmentCenter; [self.view addSubview:label]; } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; [[self cyl_sharedAppDelegate] cyl_forceUpdateInterfaceOrientation:UIInterfaceOrientationLandscapeLeft]; } - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; [[self cyl_sharedAppDelegate] cyl_forceUpdateInterfaceOrientation:UIInterfaceOrientationPortrait]; } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { // [self cyl_popSelectTabBarChildViewControllerAtIndex:4 completion:^(__kindof UIViewController *selectedTabBarChildViewController) { [self cyl_popSelectTabBarChildViewControllerForClassType:[CYLMineViewController class] completion:^(__kindof UIViewController *selectedTabBarChildViewController) { CYLMineViewController *mineViewController = selectedTabBarChildViewController; @try { [mineViewController testPush]; } @catch (NSException *exception) { NSLog(@"🔴类名与方法名:%@(在第%@行),描述:%@", @(__PRETTY_FUNCTION__), @(__LINE__), exception.reason); } }]; } @end ================================================ FILE: Example/Classes/Module/SameCity/CYLSameCityViewController.h ================================================ // // CYLSameCityViewController.h // CYLTabBarController // // v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/20/15. // Copyright © 2018 https://github.com/ChenYilong . All rights reserved. // #import #if __has_include() #import #else #import "CYLTabBarController.h" #endif @interface CYLSameCityViewController : CYLBaseTableViewController - (void)refresh; @end ================================================ FILE: Example/Classes/Module/SameCity/CYLSameCityViewController.m ================================================ // // CYLSameCityViewController.m // CYLTabBarController // // v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/20/15. // Copyright © 2018 https://github.com/ChenYilong . All rights reserved. // #import "CYLSameCityViewController.h" #import "CYLDetailsViewController.h" #import @implementation CYLSameCityViewController - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor whiteColor]; self.navigationItem.title = @"同城"; //✅sets navigation bar title.The right way to set the title of the navigation self.tabBarItem.title = @"同城"; //❌sets tab bar title. Even the `tabBarItem.title` changed, this will be ignored in tabbar. //self.title = @"同城1"; //❌sets both of these. Do not do this‼️‼️ This may cause something strange like this : http://i68.tinypic.com/282l3x4.jpg . __weak __typeof(self) weakSelf = self; self.tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{ //Call this Block When enter the refresh status automatically NSUInteger delaySeconds = 1; dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delaySeconds * NSEC_PER_SEC)); dispatch_after(when, dispatch_get_main_queue(), ^{ [weakSelf.tableView.mj_header endRefreshing]; }); }]; } - (void)refresh { [self.tableView.mj_header beginRefreshing]; NSUInteger delaySeconds = 1; dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delaySeconds * NSEC_PER_SEC)); dispatch_after(when, dispatch_get_main_queue(), ^{ [self.tableView.mj_header endRefreshing]; }); } #pragma mark - Methods - (void)configureCell:(UITableViewCell *)cell forIndexPath:(NSIndexPath *)indexPath { [[cell textLabel] setText:[NSString stringWithFormat:@"%@ CYLTabBarController %@", self.tabBarItem.title, @(indexPath.row)]]; } #pragma mark - Table view - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString * CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (!cell) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; } [self configureCell:cell forIndexPath:indexPath]; return cell; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return 15; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView deselectRowAtIndexPath:indexPath animated:YES]; UIViewController *viewController = [[CYLDetailsViewController alloc] init]; // viewController.hidesBottomBarWhenPushed = YES; // This property needs to be set before pushing viewController to the navigationController's stack. Meanwhile as it is all base on CYLBaseNavigationController, there is no need to do this. [viewController cyl_setNavigationBarHidden:YES]; [self.navigationController pushViewController:viewController animated:YES]; } @end ================================================ FILE: Example/Classes/Other/LottieResources/gray_tabbar_home_animation.json ================================================ {"v":"5.5.2","fr":25,"ip":0,"op":25,"w":52,"h":52,"nm":"tab1-easy","ddd":0,"assets":[{"id":"image_0","w":188,"h":188,"u":"","p":"img_tab_home_0.png","e":0},{"id":"image_1","w":16,"h":14,"u":"","p":"img_tab_home_1.png","e":0},{"id":"image_2","w":50,"h":48,"u":"","p":"img_tab_home_2.png","e":0}],"layers":[{"ddd":0,"ind":1,"ty":2,"nm":"1黑_1_1.png","cl":"png","refId":"image_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[25.2,26,0],"ix":2},"a":{"a":0,"k":[94,94,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":0,"s":[25,25,100]},{"t":3,"s":[0,0,100]}],"ix":6}},"ao":0,"ip":0,"op":3,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":2,"nm":"Fill 9.png","cl":"png","refId":"image_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":4,"s":[200]},{"t":8,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":4,"s":[25.2,26,0],"to":[0,-0.833,0],"ti":[0,0.833,0]},{"t":8,"s":[25.2,21,0]}],"ix":2},"a":{"a":0,"k":[8,7,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":4,"s":[0,0,100]},{"t":8,"s":[100,100,100]}],"ix":6,"x":"var $bm_rt;\nvar freq, decay, n, n, t, amp, w;\nfreq = 4;\ndecay = 8;\n$bm_rt = n = 0;\nif (numKeys > 0) {\n $bm_rt = n = nearestKey(time).index;\n if (key(n).time > time)\n n--;\n}\nif (n > 0) {\n t = $bm_sub(time, key(n).time);\n amp = velocityAtTime($bm_sub(key(n).time, 0.001));\n w = $bm_mul($bm_mul(freq, Math.PI), 2);\n $bm_rt = $bm_sum(value, $bm_mul(amp, $bm_div($bm_div(Math.sin($bm_mul(t, w)), Math.exp($bm_mul(decay, t))), w)));\n} else\n $bm_rt = value;"}},"ao":0,"ip":4,"op":128,"st":3,"bm":0},{"ddd":0,"ind":3,"ty":2,"nm":"分组 11.png","cl":"png","refId":"image_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[26,26,0],"ix":2},"a":{"a":0,"k":[25,24,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":3,"s":[0,0,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":4,"s":[25,25,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":5,"s":[50,50,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":6,"s":[75,75,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":7,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":8,"s":[116.517,116.517,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":9,"s":[113.923,113.923,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":10,"s":[101.517,101.517,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":11,"s":[92.663,92.663,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":12,"s":[92.877,92.877,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":13,"s":[98.535,98.535,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":14,"s":[103.173,103.173,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":15,"s":[103.581,103.581,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":16,"s":[101.056,101.056,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":17,"s":[98.674,98.674,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":18,"s":[98.229,98.229,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":19,"s":[99.327,99.327,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":20,"s":[100.529,100.529,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":21,"s":[100.862,100.862,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":22,"s":[100.399,100.399,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":23,"s":[99.803,99.803,100]},{"t":24,"s":[99.587,99.587,100]}],"ix":6}},"ao":0,"ip":3,"op":128,"st":3,"bm":0}],"markers":[]} ================================================ FILE: Example/Classes/Other/LottieResources/gray_tabbar_me_animation.json ================================================ {"v":"5.5.2","fr":25,"ip":0,"op":25,"w":52,"h":52,"nm":"tab3-easy","ddd":0,"assets":[{"id":"image_0","w":40,"h":44,"u":"","p":"img_tab_me_0.png","e":0},{"id":"image_1","w":40,"h":44,"u":"","p":"img_tab_me_1.png","e":0},{"id":"comp_0","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"“未标题-4”轮廓","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[26,23.75,0],"ix":2},"a":{"a":0,"k":[400.568,400.679,0],"ix":1},"s":{"a":0,"k":[200,200,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.352,0],[0,0],[0,1.351],[0,0]],"o":[[0,0],[-1.351,0],[0,0],[0,1.351]],"v":[[0,1.223],[0,1.223],[-2.446,-1.223],[2.446,-1.223]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.165000002992,0.165000002992,0.226999993418,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[400.568,400.679],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":4,"op":125,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":2,"nm":"分组 12.png","cl":"png","refId":"image_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[26,26,0],"ix":2},"a":{"a":0,"k":[20,22,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":0,"s":[100,100,100]},{"t":3,"s":[0,0,100]}],"ix":6}},"ao":0,"ip":0,"op":125,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"“未标题-4”轮廓 合成 1","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[26,26,0],"ix":2},"a":{"a":0,"k":[26,26,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":4,"s":[0,0,100]},{"t":9,"s":[100,100,100]}],"ix":6,"x":"var $bm_rt;\nvar freq, decay, n, n, t, amp, w;\nfreq = 4;\ndecay = 8;\n$bm_rt = n = 0;\nif (numKeys > 0) {\n $bm_rt = n = nearestKey(time).index;\n if (key(n).time > time)\n n--;\n}\nif (n > 0) {\n t = $bm_sub(time, key(n).time);\n amp = velocityAtTime($bm_sub(key(n).time, 0.001));\n w = $bm_mul($bm_mul(freq, Math.PI), 2);\n $bm_rt = $bm_sum(value, $bm_mul(amp, $bm_div($bm_div(Math.sin($bm_mul(t, w)), Math.exp($bm_mul(decay, t))), w)));\n} else\n $bm_rt = value;"}},"ao":0,"w":52,"h":52,"ip":0,"op":125,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":2,"nm":"分组 15.png","cl":"png","refId":"image_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[26,26,0],"ix":2},"a":{"a":0,"k":[20,22,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":3,"s":[0,0,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":4,"s":[25,25,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":5,"s":[50,50,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":6,"s":[75,75,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":7,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":8,"s":[116.517,116.517,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":9,"s":[113.923,113.923,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":10,"s":[101.517,101.517,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":11,"s":[92.663,92.663,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":12,"s":[92.877,92.877,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":13,"s":[98.535,98.535,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":14,"s":[103.173,103.173,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":15,"s":[103.581,103.581,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":16,"s":[101.056,101.056,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":17,"s":[98.674,98.674,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":18,"s":[98.229,98.229,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":19,"s":[99.327,99.327,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":20,"s":[100.529,100.529,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":21,"s":[100.862,100.862,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":22,"s":[100.399,100.399,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":23,"s":[99.803,99.803,100]},{"t":24,"s":[99.587,99.587,100]}],"ix":6}},"ao":0,"ip":0,"op":125,"st":0,"bm":0}],"markers":[]} ================================================ FILE: Example/Classes/Other/LottieResources/gray_tabbar_message_animation.json ================================================ {"v":"5.5.2","fr":25,"ip":0,"op":25,"w":52,"h":52,"nm":"tab2-easy","ddd":0,"assets":[{"id":"image_0","w":160,"h":160,"u":"","p":"img_tab_message_0.png","e":0},{"id":"image_1","w":40,"h":40,"u":"","p":"img_tab_message_1.png","e":0}],"layers":[{"ddd":0,"ind":1,"ty":2,"nm":"3黑_5_1.png","cl":"png","refId":"image_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[26,26,0],"ix":2},"a":{"a":0,"k":[80,80,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":0,"s":[25,25,100]},{"t":3,"s":[0,0,100]}],"ix":6}},"ao":0,"ip":0,"op":3,"st":-21,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"“描边”轮廓 - 组 3","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":4,"s":[0]},{"t":7,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[25.75,21.938,0],"ix":2},"a":{"a":0,"k":[313.023,463,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":4,"s":[0,0,100]},{"t":8,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[305.529,463],[320.517,463]],"c":false},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.165000002992,0.165000002992,0.226999993418,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 3","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1,"x":"var $bm_rt;\nvar freq, decay, n, n, t, amp, w;\nfreq = 3;\ndecay = 5;\n$bm_rt = n = 0;\nif (numKeys > 0) {\n $bm_rt = n = nearestKey(time).index;\n if (key(n).time > time)\n n--;\n}\nif (n > 0) {\n t = $bm_sub(time, key(n).time);\n amp = velocityAtTime($bm_sub(key(n).time, 0.001));\n w = $bm_mul($bm_mul(freq, Math.PI), 2);\n $bm_rt = $bm_sum(value, $bm_mul(amp, $bm_div($bm_div(Math.sin($bm_mul(t, w)), Math.exp($bm_mul(decay, t))), w)));\n} else\n $bm_rt = value;"},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":5,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":10,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":14,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[95.304]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":16,"s":[93.827]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":17,"s":[95.826]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":18,"s":[99.033]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":19,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":22,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":23,"s":[99.569]},{"t":24,"s":[99.166]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"修剪路径 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":4,"op":129,"st":4,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"“描边”轮廓 - 组 1","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":4,"s":[0]},{"t":8,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[22.85,30.562,0],"ix":2},"a":{"a":0,"k":[310.124,476.562,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":4,"s":[0,0,100]},{"t":8,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[305.574,476.562],[314.674,476.562]],"c":false},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.165000002992,0.165000002992,0.226999993418,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":5,"s":[0]},{"t":10,"s":[100]}],"ix":2,"x":"var $bm_rt;\nvar freq, decay, n, n, t, amp, w;\nfreq = 3;\ndecay = 6;\n$bm_rt = n = 0;\nif (numKeys > 0) {\n $bm_rt = n = nearestKey(time).index;\n if (key(n).time > time)\n n--;\n}\nif (n > 0) {\n t = $bm_sub(time, key(n).time);\n amp = velocityAtTime($bm_sub(key(n).time, 0.001));\n w = $bm_mul($bm_mul(freq, Math.PI), 2);\n $bm_rt = $bm_sum(value, $bm_mul(amp, $bm_div($bm_div(Math.sin($bm_mul(t, w)), Math.exp($bm_mul(decay, t))), w)));\n} else\n $bm_rt = value;"},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"修剪路径 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":4,"op":129,"st":4,"bm":0},{"ddd":0,"ind":4,"ty":2,"nm":"消息.png","cl":"png","refId":"image_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[26,26,0],"ix":2},"a":{"a":0,"k":[20,20,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":3,"s":[0,0,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":4,"s":[25,25,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":5,"s":[50,50,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":6,"s":[75,75,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":7,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":8,"s":[116.517,116.517,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":9,"s":[113.923,113.923,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":10,"s":[101.517,101.517,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":11,"s":[92.663,92.663,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":12,"s":[92.877,92.877,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":13,"s":[98.535,98.535,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":14,"s":[103.173,103.173,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":15,"s":[103.581,103.581,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":16,"s":[101.056,101.056,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":17,"s":[98.674,98.674,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":18,"s":[98.229,98.229,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":19,"s":[99.327,99.327,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":20,"s":[100.529,100.529,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":21,"s":[100.862,100.862,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":22,"s":[100.399,100.399,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":23,"s":[99.803,99.803,100]},{"t":24,"s":[99.587,99.587,100]}],"ix":6}},"ao":0,"ip":3,"op":128,"st":3,"bm":0}],"markers":[]} ================================================ FILE: Example/Classes/Other/LottieResources/green_lottie_tab_discover.json ================================================ {"v":"5.1.16","fr":30,"ip":0,"op":30,"w":60,"h":60,"nm":"Tab_Discovery_Active","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Icon_Discovery_Active_Line_Circle_Small","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[30,30,0],"ix":2},"a":{"a":0,"k":[30,30,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[4.418,0],[0,4.418],[-4.418,0],[0,-4.418]],"o":[[-4.418,0],[0,-4.418],[4.418,0],[0,4.418]],"v":[[0,8],[-8,0],[0,-8],[8,0]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.325,0.843,0.416,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":2,"lj":2,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[30,30],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"内圈","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.6],"y":[0]},"n":["0p4_1_0p6_0"],"t":0,"s":[0],"e":[99]},{"t":20}],"ix":2},"o":{"a":0,"k":180,"ix":3},"m":1,"ix":2,"nm":"修剪路径 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":30,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Icon_Discovery_Active_Line_Circle_Big","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[30,30,0],"ix":2},"a":{"a":0,"k":[30,30,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,-2.107],[1.432,-2.755],[3.5,-1.907],[3.46,0],[0,11.046],[-11.046,0],[-1.872,-0.58]],"o":[[0.604,1.907],[0,3.321],[-1.839,3.54],[-2.839,1.545],[-11.046,0],[0,-11.045],[2.063,0],[0,0]],"v":[[19.07,-6.044],[20,0],[17.759,9.208],[9.553,17.576],[0,20],[-20,0],[0,-20],[5.924,-19.108]],"c":false},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.325,0.843,0.416,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":2,"lj":2,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[30,30],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"外圈","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.875],"y":[1]},"o":{"x":[0.6],"y":[0]},"n":["0p875_1_0p6_0"],"t":20,"s":[0],"e":[100]},{"t":29}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"修剪路径 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":30,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Icon_Discovery_Active_Triangle","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0.048]},"n":["0p2_1_0p167_0p048"],"t":10,"s":[0],"e":[100]},{"t":14}],"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.4],"y":[0]},"n":["0p2_1_0p4_0"],"t":10,"s":[-45],"e":[0]},{"t":24}],"ix":10},"p":{"a":0,"k":[30,30,0],"ix":2},"a":{"a":0,"k":[30,30,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[7.779,-7.778],[0.708,7.778],[-7.779,-0.707]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.325,0.843,0.416,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[37.778,22.222],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"三角","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Icon_Discovery_Active_Main","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.61],"y":[1]},"o":{"x":[0.24],"y":[0]},"n":["0p61_1_0p24_0"],"t":20,"s":[0],"e":[100]},{"t":26}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[30,30,0],"ix":2},"a":{"a":0,"k":[30,30,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-3.313,0],[0,3.313],[3.313,0],[0,-3.313]],"o":[[3.313,0],[0,-3.313],[-3.313,0],[0,3.313]],"v":[[0,6],[6,0],[0,-6],[-6,0]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.682,0.878,0.69,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[32,32],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"内圆","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Icon_Discovery_Normal","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.8],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"n":["0p8_1_0p167_0p167"],"t":0,"s":[100],"e":[6]},{"t":10}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[30,30,0],"ix":2},"a":{"a":0,"k":[30,30,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.418,0],[0,4.418],[4.418,0],[0,-4.418]],"o":[[4.418,0],[0,-4.418],[-4.418,0],[0,4.418]],"v":[[0,8],[8,0],[0,-8],[-8,0]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.498,0.498,0.498,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":2,"lj":2,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[30,30],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[7.779,-7.778],[0.708,7.778],[-7.779,-0.707]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.498,0.498,0.498,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[37.778,22.222],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 3","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[2.063,0],[0,-11.045],[-11.046,0],[-2.839,1.545],[-1.839,3.54],[0,3.321],[0.604,1.907]],"o":[[-1.872,-0.58],[-11.046,0],[0,11.046],[3.46,0],[3.5,-1.907],[1.432,-2.755],[0,-2.107],[0,0]],"v":[[5.924,-19.108],[0,-20],[-20,0],[0,20],[9.553,17.576],[17.759,9.208],[20,0],[19.07,-6.044]],"c":false},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.498,0.498,0.498,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":2,"lj":2,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[30,30],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 4","np":2,"cix":2,"ix":3,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30,"st":0,"bm":0}],"markers":[]} ================================================ FILE: Example/Classes/Other/LottieResources/green_lottie_tab_home.json ================================================ {"v":"5.1.16","fr":30,"ip":0,"op":30,"w":60,"h":60,"nm":"Tab_Shop_Active","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Icon_Shop_Active_Line_A","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[30,30,0],"ix":2},"a":{"a":0,"k":[30,30,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-3.313,0],[-1.075,1.617],[-2.087,0],[-1.075,1.617],[-2.087,0],[-1.075,1.617],[-2.087,0],[0,3.313],[0,0],[0.845,0],[0,0],[0.284,-0.796]],"o":[[0,3.313],[2.087,0],[1.075,1.617],[2.087,0],[1.075,1.617],[2.087,0],[1.075,1.617],[3.313,0],[0,0],[-0.285,-0.796],[0,0],[-0.846,0],[0,0]],"v":[[-21,-4],[-15,2],[-10,-0.682],[-5,2],[0,-0.682],[5,2],[10,-0.682],[15,2],[21,-4],[16.474,-16.673],[14.591,-18],[-14.59,-18],[-16.474,-16.673]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.325,0.843,0.416,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":2,"lj":2,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.61],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"n":["0p61_1_0p167_0p167"],"t":16,"s":[6],"e":[0]},{"t":18}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.6],"y":[0]},"n":["0p4_1_0p6_0"],"t":0,"s":[6],"e":[100]},{"i":{"x":[0.8],"y":[1]},"o":{"x":[0.6],"y":[0]},"n":["0p8_1_0p6_0"],"t":16,"s":[100],"e":[100]},{"t":35}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":3,"nm":"修剪路径 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"tr","p":{"a":0,"k":[30,30],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"Line","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Icon_Shop_Active_Line_B","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[30,30,0],"ix":2},"a":{"a":0,"k":[30,30,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-1.104,0],[0,0],[0,1.104],[0,0]],"o":[[0,0],[0,1.104],[0,0],[1.104,0],[0,0],[0,0]],"v":[[-16,0],[-16,16],[-14,18],[14,18],[16,16],[16,10]],"c":false},"ix":2},"nm":"路径 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.325,0.843,0.416,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":2,"lj":2,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tm","s":{"a":0,"k":6,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.977],"y":[0.791]},"o":{"x":[0.964],"y":[0]},"n":["0p977_0p791_0p964_0"],"t":16,"s":[6],"e":[100]},{"i":{"x":[0.8],"y":[1]},"o":{"x":[1],"y":[0]},"n":["0p8_1_1_0"],"t":29,"s":[100],"e":[100]},{"t":35}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":3,"nm":"修剪路径 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"tr","p":{"a":0,"k":[30,30],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"Line","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Icon_Shop_Active_Main","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.61],"y":[1]},"o":{"x":[0.24],"y":[0]},"n":["0p61_1_0p24_0"],"t":20,"s":[0],"e":[100]},{"t":26}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[30,30,0],"ix":2},"a":{"a":0,"k":[30,30,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0.145,-0.39],[0,0],[-3.314,0],[-1.075,1.616],[-2.087,0],[-1.075,1.616],[-2.087,0],[0,3.314],[0,0],[0.416,0]],"o":[[-0.416,0],[0,0],[0,3.314],[2.087,0],[1.075,1.616],[2.087,0],[1.075,1.616],[3.314,0],[0,0],[-0.147,-0.39],[0,0]],"v":[[-12.307,-7],[-13.243,-6.351],[-16,1],[-10,7],[-5,4.318],[0,7],[5,4.318],[10,7],[16,1],[13.244,-6.351],[12.307,-7]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.682,0.878,0.69,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[35,25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"Main","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Icon_Shop_Normal","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.8],"y":[1]},"o":{"x":[0.6],"y":[0]},"n":["0p8_1_0p6_0"],"t":0,"s":[100],"e":[6]},{"t":10}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[30,30,0],"ix":2},"a":{"a":0,"k":[30,30,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,3.313],[0,0],[-0.846,0],[0,0],[-0.285,-0.796],[0,0],[3.313,0],[1.075,1.617],[2.087,0],[1.075,1.617],[2.087,0],[1.075,1.617],[2.087,0]],"o":[[0,0],[0.284,-0.796],[0,0],[0.845,0],[0,0],[0,3.313],[-2.087,0],[-1.075,1.617],[-2.087,0],[-1.075,1.617],[-2.087,0],[-1.075,1.617],[-3.313,0]],"v":[[-21,-4],[-16.474,-16.673],[-14.59,-18],[14.591,-18],[16.474,-16.673],[21,-4],[15,2],[10,-0.682],[5,2],[0,-0.682],[-5,2],[-10,-0.682],[-15,2]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[1.104,0],[0,0],[0,1.104],[0,0]],"o":[[0,0],[0,1.104],[0,0],[-1.104,0],[0,0],[0,0]],"v":[[16,10],[16,16],[14,18],[-14,18],[-16,16],[-16,2]],"c":false},"ix":2},"nm":"路径 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"st","c":{"a":0,"k":[0.498,0.498,0.498,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":2,"lj":2,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[30,30],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"Line","np":4,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30,"st":0,"bm":0}],"markers":[]} ================================================ FILE: Example/Classes/Other/LottieResources/green_lottie_tab_mine.json ================================================ {"v":"5.1.16","fr":30,"ip":0,"op":30,"w":60,"h":60,"nm":"Tab_Mine_Active","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Icon_Mine_Active_Line","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[30,30,0],"ix":2},"a":{"a":0,"k":[30,30,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,1.407],[5.523,0],[0,-5.523],[-5.523,0],[0,-9.942],[0,0],[-3.893,3.302]],"o":[[0.524,-1.215],[0,-5.523],[-5.523,0],[0,5.523],[9.942,0],[0,0],[0,-5.505],[0,0]],"v":[[9.185,-5.039],[10,-9],[0,-19],[-10,-9],[0,1],[18,19],[-18,19],[-11.636,5.266]],"c":false},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.325,0.843,0.416,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":2,"lj":2,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[30,29],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.955],"y":[1]},"o":{"x":[1],"y":[0]},"n":["0p955_1_1_0"],"t":0,"s":[0],"e":[38]},{"i":{"x":[0.964],"y":[1]},"o":{"x":[1],"y":[0]},"n":["0p964_1_1_0"],"t":16,"s":[38],"e":[100]},{"t":26}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"修剪路径 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":30,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Icon_Mine_Active_Main","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.76],"y":[1]},"o":{"x":[0.24],"y":[0]},"n":["0p76_1_0p24_0"],"t":20,"s":[0],"e":[100]},{"t":26}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[30,30,0],"ix":2},"a":{"a":0,"k":[30,30,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-8.284],[0,0],[-8.284,0]],"o":[[0,0],[0,-8.284],[8.284,0]],"v":[[15,16.5],[-15,16.5],[0,1.5]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[3.866,0],[0,3.866],[-3.866,0],[0,-3.866]],"o":[[-3.866,0],[0,-3.866],[3.866,0],[0,3.866]],"v":[[0,-2.5],[-7,-9.5],[0,-16.5],[7,-9.5]],"c":true},"ix":2},"nm":"路径 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.682,0.878,0.69,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[33,32.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 2","np":4,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Icon_Mine_Normal","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.8],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"n":["0p8_1_0p167_0p167"],"t":0,"s":[100],"e":[6]},{"t":10}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[30,30,0],"ix":2},"a":{"a":0,"k":[30,30,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,1.407],[5.523,0],[0,-5.523],[-5.523,0],[0,-9.942],[0,0],[-3.893,3.302]],"o":[[0.524,-1.215],[0,-5.523],[-5.523,0],[0,5.523],[9.942,0],[0,0],[0,-5.505],[0,0]],"v":[[9.185,-5.039],[10,-9],[0,-19],[-10,-9],[0,1],[18,19],[-18,19],[-11.636,5.266]],"c":false},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.498,0.498,0.498,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":2,"lj":2,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[30,29],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30,"st":0,"bm":0}],"markers":[]} ================================================ FILE: Example/Classes/Other/LottieResources/green_lottie_tab_news.json ================================================ {"v":"5.1.16","fr":30,"ip":0,"op":30,"w":60,"h":60,"nm":"Tab_Knowledge_Active","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Icon_Knowledge_Active_Line_A","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[30,30,0],"ix":2},"a":{"a":0,"k":[30,30,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,-2.2],[2.019,-1.142]],"o":[[0,0],[0,0],[0,0],[0,0],[1.974,0.669],[0,2.231],[0,0]],"v":[[-1.74,7],[-21.74,-1],[-1.74,-9],[18.26,-1],[18.346,-1],[21.74,3.737],[18.26,9]],"c":false},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.325,0.843,0.416,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":2,"lj":2,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[31.74,21],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 2","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.357],"y":[1]},"o":{"x":[0.644],"y":[0]},"n":["0p357_1_0p644_0"],"t":0,"s":[0],"e":[100]},{"t":16}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"修剪路径 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":30,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Icon_Knowledge_Active_Line_B","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[30,30,0],"ix":2},"a":{"a":0,"k":[30,30,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[20,-4],[0,4],[-20,-4]],"c":false},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.325,0.843,0.416,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":2,"lj":2,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[30,34],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.4],"y":[0]},"n":["0p2_1_0p4_0"],"t":16,"s":[0],"e":[100]},{"t":28}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"修剪路径 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":30,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Icon_Knowledge_Active_Line_C","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[30,30,0],"ix":2},"a":{"a":0,"k":[30,30,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,-2.199],[2.019,-1.142],[0,0],[0,0]],"o":[[1.974,0.669],[0,2.232],[0,0],[0,0],[0,0]],"v":[[18.346,-9],[21.74,-4.264],[18.26,1],[-1.74,9],[-21.74,1]],"c":false},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.325,0.843,0.416,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":2,"lj":2,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[31.74,39],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 3","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.4],"y":[0]},"n":["0p2_1_0p4_0"],"t":20,"s":[0],"e":[100]},{"t":28}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"修剪路径 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":30,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Icon_Knowledge_Active_Main","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.76],"y":[1]},"o":{"x":[0.24],"y":[0]},"n":["0p76_1_0p24_0"],"t":20,"s":[0],"e":[100]},{"t":26}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[30,30,0],"ix":2},"a":{"a":0,"k":[30,30,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-17,-8.001],[-5,-3.501],[-5,16.501],[17,7.501],[17,-10.499],[2.5,-16.501]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.682,0.878,0.69,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[35,31.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 4","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Icon_Knowledge_Normal","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.8],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"n":["0p8_1_0p167_0p167"],"t":0,"s":[100],"e":[6]},{"t":10}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[30,30,0],"ix":2},"a":{"a":0,"k":[30,30,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[20,-4],[0,4],[-20,-4]],"c":false},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.498,0.498,0.498,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":2,"lj":2,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[30,34],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,-2.2],[2.019,-1.142]],"o":[[0,0],[0,0],[0,0],[0,0],[1.974,0.669],[0,2.231],[0,0]],"v":[[-1.74,7],[-21.74,-1],[-1.74,-9],[18.26,-1],[18.346,-1],[21.74,3.737],[18.26,9]],"c":false},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.498,0.498,0.498,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":2,"lj":2,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[31.74,21],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 2","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,2.232],[1.974,0.669]],"o":[[0,0],[0,0],[2.019,-1.142],[0,-2.199],[0,0]],"v":[[-21.74,1],[-1.74,9],[18.26,1],[21.74,-4.264],[18.346,-9]],"c":false},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.498,0.498,0.498,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":2,"lj":2,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[31.74,39],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 3","np":2,"cix":2,"ix":3,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":30,"st":0,"bm":0}],"markers":[]} ================================================ FILE: Example/Classes/Other/LottieResources/tab_home_animate.json ================================================ {"v":"4.7.0","fr":24,"ip":0,"op":19,"w":66,"h":66,"nm":"主页到刷新(66x66)大变 8","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"形状图层 10","ks":{"o":{"a":0,"k":100},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":5,"s":[-180],"e":[-154]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":6,"s":[-154],"e":[-63]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":7,"s":[-63],"e":[15]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":8,"s":[15],"e":[49]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":9,"s":[49],"e":[81]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":10,"s":[81],"e":[116]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":11,"s":[116],"e":[147]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":12,"s":[147],"e":[180]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":13,"s":[180],"e":[215]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":14,"s":[215],"e":[258]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":15,"s":[258],"e":[286]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":16,"s":[286],"e":[321]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":17,"s":[321],"e":[359]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":18,"s":[359],"e":[361]},{"t":19}]},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[33.097,31.625,0],"e":[39.582,25.888,0],"to":[-0.01841666735709,-5.55231285095215,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[39.582,25.888,0],"e":[52,33,0],"to":[0,0,0],"ti":[0,-13.3487205505371,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[52,33,0],"e":[33,52,0],"to":[0,10.4934120178223,0],"ti":[10.493408203125,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[33,52,0],"e":[14,33,0],"to":[-10.4934158325195,0,0],"ti":[0,10.4934158325195,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":13,"s":[14,33,0],"e":[33,14,0],"to":[0,-10.4934196472168,0],"ti":[-10.4934158325195,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15.5,"s":[33,14,0],"e":[33,14,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15.501,"s":[33,14,0],"e":[52,33,0],"to":[10.4934120178223,0,0],"ti":[0,-10.4934196472168,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18,"s":[52,33,0],"e":[52,33,0],"to":[0,0,0],"ti":[0,-8.51000690460205,0]},{"t":19}]},"a":{"a":0,"k":[-0.103,-6.545,0]},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":5,"s":[264,164,100],"e":[196.667,134.095,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":6,"s":[196.667,134.095,100],"e":[101,75.286,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":8,"s":[101,75.286,100],"e":[100,100,100]},{"t":19}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[{"i":[[-0.104,0.151],[0,0],[0.683,0.469],[0.303,0],[0,0],[0,-0.828],[-0.172,-0.25],[0,0],[-0.683,0.469]],"o":[[0,0],[0.469,-0.683],[-0.25,-0.172],[0,0],[-0.829,0],[0,0.303],[0,0],[0.469,0.683],[0.151,-0.104]],"v":[[1.775,5.87],[8.57,-4.016],[8.184,-6.101],[7.334,-6.365],[-6.256,-6.365],[-7.756,-4.865],[-7.492,-4.016],[-0.697,5.87],[1.389,6.256]],"c":true}],"e":[{"i":[[-0.104,0.151],[0,0],[0.683,0.469],[0.303,0],[0,0],[0,-0.828],[-0.172,-0.25],[0,0],[-0.683,0.469]],"o":[[0,0],[0.469,-0.683],[-0.25,-0.172],[0,0],[-0.829,0],[0,0.303],[0,0],[0.469,0.683],[0.151,-0.104]],"v":[[1.775,5.87],[8.57,-4.016],[8.184,-6.101],[7.334,-6.365],[-6.256,-6.365],[-7.756,-4.865],[-7.492,-4.016],[-0.697,5.87],[1.389,6.256]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[-0.104,0.151],[0,0],[0.683,0.469],[0.303,0],[0,0],[0,-0.828],[-0.172,-0.25],[0,0],[-0.683,0.469]],"o":[[0,0],[0.469,-0.683],[-0.25,-0.172],[0,0],[-0.829,0],[0,0.303],[0,0],[0.469,0.683],[0.151,-0.104]],"v":[[1.775,5.87],[8.57,-4.016],[8.184,-6.101],[7.334,-6.365],[-6.256,-6.365],[-7.756,-4.865],[-7.492,-4.016],[-0.697,5.87],[1.389,6.256]],"c":true}],"e":[{"i":[[-0.104,0.151],[0,0],[0.683,0.469],[0.303,0],[0,0],[0,-0.828],[-0.172,-0.25],[0,0],[-0.683,0.469]],"o":[[0,0],[0.469,-0.683],[-0.25,-0.172],[0,0],[-0.829,0],[0,0.303],[0,0],[0.469,0.683],[0.151,-0.104]],"v":[[1.775,5.87],[8.57,-4.016],[8.184,-6.101],[7.334,-6.365],[-6.256,-6.365],[-7.756,-4.865],[-7.492,-4.016],[-0.697,5.87],[1.389,6.256]],"c":true}]},{"t":19}]},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.133,0.133,0.133,1]},"o":{"a":0,"k":100},"r":1,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[-0.642,-0.18],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"矩形 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":6,"op":96,"st":4,"bm":0,"sr":1},{"ddd":0,"ind":2,"ty":4,"nm":"形状图层 7","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[33,33,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":4,"s":[{"i":[[0,0],[0,-13.349],[10.493,0],[0,10.493],[-10.493,0],[0,0],[0,-10.493]],"o":[[-0.097,-29.375],[0,10.493],[-10.493,0],[0,-10.493],[0,0],[10.493,0],[0,0]],"v":[[3.756,22.586],[22.658,3.586],[3.658,22.586],[-15.342,3.586],[3.658,-15.414],[3.658,-15.414],[22.658,3.586]],"c":false}],"e":[{"i":[[0,0],[0,-13.349],[10.493,0],[0,10.493],[-10.493,0],[0,0],[0,-10.493]],"o":[[0,-34.687],[0,10.493],[-10.493,0],[0,-10.493],[0,0],[10.493,0],[0,0]],"v":[[3.756,22.586],[22.658,3.586],[3.658,22.586],[-15.342,3.586],[3.658,-15.414],[3.658,-15.414],[22.658,3.586]],"c":false}]},{"t":19}]},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":4,"s":[0],"e":[6.2]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":6,"s":[6.2],"e":[41]},{"t":19}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":4,"s":[0],"e":[20]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":7,"s":[20],"e":[26.667]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":8,"s":[26.667],"e":[44.836]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":10,"s":[44.836],"e":[64.091]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":13,"s":[64.091],"e":[80.455]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":15,"s":[80.455],"e":[86.97]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":16,"s":[86.97],"e":[100]},{"t":18}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"修剪路径 1","mn":"ADBE Vector Filter - Trim"},{"ty":"st","c":{"a":0,"k":[0.133,0.133,0.133,1]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":4,"s":[38],"e":[37]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":5,"s":[37],"e":[14]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":8,"s":[14],"e":[8]},{"t":19}]},"lc":2,"lj":1,"ml":4,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"tr","p":{"a":0,"k":[-3.658,-3.586],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"矩形 1","np":4,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":6,"op":95,"st":4,"bm":0,"sr":1},{"ddd":0,"ind":3,"ty":4,"nm":"“图层 6”轮廓 3","td":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[32.438,33.875,0]},"a":{"a":0,"k":[42,39,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-2.232,0],[0,0],[0,2.235],[0,0],[0,0]],"o":[[0,0],[0,2.24],[0,0],[2.24,0],[0,0],[0,0],[0,0]],"v":[[-19.231,-14.445],[-19.231,10.398],[-15.188,14.445],[15.187,14.445],[19.231,10.398],[19.231,-14.445],[-0.46,-30.57]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0.062,0.062],[0,0],[0.197,0.099],[0.633,-0.781],[0,0],[0.02,-0.029],[0,0],[-0.78,-0.781],[0,0],[-0.831,0.721],[0,0],[0,0],[-0.692,0.855],[0,0],[0.839,0.713]],"o":[[-0.052,-0.068],[0,0],[-0.16,-0.16],[-0.822,-0.519],[0,0],[-0.022,0.027],[0,0],[-0.836,0.725],[0,0],[0.78,0.779],[0,0],[0,0],[0.836,0.71],[0,0],[0.697,-0.862],[0,0]],"v":[[1.442,-30.764],[1.271,-30.959],[1.303,-30.927],[0.764,-31.315],[-1.784,-30.893],[-1.726,-30.964],[-1.789,-30.881],[-22.231,-13.124],[-22.323,-10.404],[-22.356,-10.437],[-19.437,-10.33],[-0.191,-27.049],[19.222,-10.562],[21.995,-10.818],[21.938,-10.746],[21.671,-13.584]],"c":true}},"nm":"路径 2","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.133,0.133,0.133,1]},"o":{"a":0,"k":100},"r":1,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[42.897,46.78],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":6,"st":-18,"bm":0,"sr":1},{"ddd":0,"ind":4,"ty":4,"nm":"形状图层 9","tt":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":-1,"s":[33,93.013,0],"e":[33,46.763,0],"to":[0,-7.70833349227905,0],"ti":[0,7.70833349227905,0]},{"t":5}]},"a":{"a":0,"k":[0.47,24.873,0]},"s":{"a":0,"k":[186,186,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[37.657,37.657]},"p":{"a":0,"k":[0,0]},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse"},{"ty":"fl","c":{"a":0,"k":[0.133,0.133,0.133,1]},"o":{"a":0,"k":100},"r":1,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[0.47,24.873],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[104.142,104.142],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"椭圆 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":6,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":5,"ty":4,"nm":"“图层 2”轮廓","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[32.438,33.875,0]},"a":{"a":0,"k":[42,39,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0.062,0.062],[0,0],[0.197,0.099],[0.633,-0.781],[0,0],[0.02,-0.029],[0,0],[-0.78,-0.781],[0,0],[-0.831,0.721],[0,0],[0,0],[-0.692,0.855],[0,0],[0.839,0.713]],"o":[[-0.052,-0.068],[0,0],[-0.16,-0.16],[-0.822,-0.519],[0,0],[-0.022,0.027],[0,0],[-0.836,0.725],[0,0],[0.78,0.779],[0,0],[0,0],[0.836,0.71],[0,0],[0.697,-0.862],[0,0]],"v":[[1.676,-10.042],[1.505,-10.238],[1.537,-10.206],[0.998,-10.594],[-1.55,-10.171],[-1.492,-10.242],[-1.555,-10.16],[-21.997,7.598],[-22.089,10.318],[-22.122,10.285],[-19.203,10.391],[0.043,-6.327],[19.456,10.16],[22.229,9.904],[22.172,9.975],[21.905,7.137]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.133,0.133,0.133,1]},"o":{"a":0,"k":100},"r":1,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[42.664,26.059],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":5,"st":-18,"bm":0,"sr":1},{"ddd":0,"ind":6,"ty":4,"nm":"“图层 3_复制”轮廓 3","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[33.125,46.911,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[-1.164,0],[0,-1.167],[0,0],[0,0],[0,0],[3.375,0],[0,-3.378],[0,0]],"o":[[0,0],[0,0],[0,0],[0,-1.167],[1.164,0],[0,0],[0,0],[0,0],[0,-3.39],[-3.368,0],[0,0],[0,0]],"v":[[-40.577,-43.207],[-40.577,-47.299],[-44.805,-47.298],[-44.805,-55.122],[-42.694,-57.239],[-40.583,-55.122],[-40.583,-43.207],[-36.583,-43.207],[-36.583,-55.122],[-42.694,-61.239],[-48.805,-55.122],[-48.805,-43.207]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.133,0.133,0.133,1]},"o":{"a":0,"k":100},"r":1,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[42.694,52.388],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":5,"st":-18,"bm":0,"sr":1},{"ddd":0,"ind":7,"ty":4,"nm":"“图层 6”轮廓","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[32.438,33.875,0]},"a":{"a":0,"k":[42,39,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-2.232,0],[0,0],[0,2.235],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,2.24],[0,0],[2.24,0],[0,0],[0,0]],"v":[[15.311,-14.445],[15.311,10.512],[-15.356,10.512],[-15.356,-14.445],[-19.231,-14.445],[-19.231,10.398],[-15.188,14.445],[15.187,14.445],[19.231,10.398],[19.231,-14.445]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.133,0.133,0.133,1]},"o":{"a":0,"k":100},"r":1,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[42.897,46.78],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":5,"st":-18,"bm":0,"sr":1}]} ================================================ FILE: Example/Classes/Other/LottieResources/tab_me_animate.json ================================================ {"v":"4.6.3","fr":24,"ip":0,"op":10,"w":66,"h":66,"nm":"个人(66x66)","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"空 15","ks":{"o":{"a":0,"k":0},"r":{"a":0,"k":0},"p":{"a":0,"k":[33.625,32.5,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":-1,"s":[100,100,100],"e":[92,92,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":3,"s":[92,92,100],"e":[103,103,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":7,"s":[103,103,100],"e":[100,100,100]},{"t":9}]}},"ao":0,"ip":0,"op":10,"st":-45,"bm":0,"sr":1},{"ddd":0,"ind":2,"ty":4,"nm":"形状图层 2","parent":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":2,"s":[4.365,16.432,0],"e":[-2.135,16.432,0],"to":[-1.08333337306976,0,0],"ti":[0.83333331346512,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[-2.135,16.432,0],"e":[-0.635,16.432,0],"to":[-0.83333331346512,0,0],"ti":[-0.25,0,0]},{"t":9}]},"a":{"a":0,"k":[0.271,16.432,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[4,4]},"p":{"a":0,"k":[0,0]},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse"},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[0.271,16.432],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"椭圆 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":3,"op":10,"st":-45,"bm":0,"sr":1},{"ddd":0,"ind":3,"ty":4,"nm":"“图层 2”轮廓 2","parent":4,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":-23},"p":{"a":0,"k":[42.5,35.5,0]},"a":{"a":0,"k":[42.5,35.5,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":-1,"s":[{"i":[[0,-6.627],[6.627,0],[0,11.188],[0,0]],"o":[[0,6.627],[-0.062,0.062],[0,-10.881],[6.627,0]],"v":[[12,0],[0,12],[9.875,-0.125],[0,-12]],"c":true}],"e":[{"i":[[0,-6.627],[6.627,0],[0,6.627],[-6.627,0]],"o":[[0,6.627],[-6.627,0],[0,-6.627],[6.627,0]],"v":[[12,0],[0,12],[-12,0],[0,-12]],"c":true}]},{"t":6}]},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"tr","p":{"a":0,"k":[42.5,35.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ty":"fl","c":{"a":0,"k":[0.1333333,0.1333333,0.1333333,1]},"o":{"a":0,"k":100},"r":1,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"}],"ip":0,"op":10,"st":-45,"bm":0,"sr":1},{"ddd":0,"ind":4,"ty":4,"nm":"“图层 2”轮廓","parent":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":-1,"s":[-0.5,-9.531,0],"e":[-1.25,-7.031,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":2,"s":[-1.25,-7.031,0],"e":[-1,-9.531,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[-1,-9.531,0],"e":[-0.5,-9.531,0],"to":[0,0,0],"ti":[0,0,0]},{"t":9}]},"a":{"a":0,"k":[42,36,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-6.627],[6.627,0],[0,6.627],[-6.627,0]],"o":[[0,6.627],[-6.627,0],[0,-6.627],[6.627,0]],"v":[[12,0],[0,12],[-12,0],[0,-12]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"st","c":{"a":0,"k":[0.1333333,0.1333333,0.1333333,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":4},"lc":1,"lj":1,"ml":10,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"tr","p":{"a":0,"k":[42,36],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":10,"st":-45,"bm":0,"sr":1},{"ddd":0,"ind":5,"ty":4,"nm":"“图层 2_复制”轮廓 2","parent":1,"td":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[42.5,45.5,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-3.342,0],[-2.607,1.537],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[2.657,1.623],[3.245,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.728,-8.702],[0.395,-6.144],[9.286,-8.562],[16.02,-1.548],[18.062,6.286],[16.938,8.702],[-18.062,8.245],[-17.688,1.494],[-10.938,-7.215]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.1333333,0.1333333,0.1333333,1]},"o":{"a":0,"k":100},"r":1,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[41.604,59.672],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":10,"st":-45,"bm":0,"sr":1},{"ddd":0,"ind":6,"ty":4,"nm":"形状图层 3","parent":1,"tt":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[-0.232,14.395,0]},"a":{"a":0,"k":[-0.982,14.395,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":0,"s":[{"i":[[0,0],[0.706,-6.542],[0,0],[0,0],[0,0]],"o":[[0,0],[1.288,5.372],[0,0],[0,0],[0,0]],"v":[[4.06,-11.103],[8.032,-1.062],[3.935,10.187],[25.345,17.404],[25.345,-7.886]],"c":true}],"e":[{"i":[[0,0],[6.002,-6.583],[0,0],[0,0],[0,0]],"o":[[0,0],[-2.013,4.244],[0,0],[0,0],[0,0]],"v":[[3.476,-11.312],[0.296,2.272],[-12.774,9.728],[24.42,15.708],[24.42,-9.582]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":1.93,"s":[{"i":[[0,0],[6.002,-6.583],[0,0],[0,0],[0,0]],"o":[[0,0],[-2.013,4.244],[0,0],[0,0],[0,0]],"v":[[3.476,-11.312],[0.296,2.272],[-12.774,9.728],[24.42,15.708],[24.42,-9.582]],"c":true}],"e":[{"i":[[0,0],[9.172,-7.75],[0,0],[0,0],[0,0]],"o":[[0,0],[-9.565,8.082],[0,0],[0,0],[0,0]],"v":[[11.143,-12.395],[-7.19,-2.27],[-22.357,30.395],[24.046,16.04],[24.046,-9.25]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":4.071,"s":[{"i":[[0,0],[9.172,-7.75],[0,0],[0,0],[0,0]],"o":[[0,0],[-9.565,8.082],[0,0],[0,0],[0,0]],"v":[[11.143,-12.395],[-7.19,-2.27],[-22.357,30.395],[24.046,16.04],[24.046,-9.25]],"c":true}],"e":[{"i":[[0,0],[9.006,-7.688],[0,0],[0,0],[0,0]],"o":[[0,0],[-9.994,7.312],[0,0],[0,0],[0,0]],"v":[[5.768,-11.958],[-10.649,-2.458],[-27.294,19.52],[26.59,20.341],[26.59,-4.949]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[0,0],[9.006,-7.688],[0,0],[0,0],[0,0]],"o":[[0,0],[-9.994,7.312],[0,0],[0,0],[0,0]],"v":[[5.768,-11.958],[-10.649,-2.458],[-27.294,19.52],[26.59,20.341],[26.59,-4.949]],"c":true}],"e":[{"i":[[0,0],[4.161,-8.25],[0,0],[0,0],[0,0]],"o":[[0,0],[-4.161,8.25],[0,0],[0,0],[0,0]],"v":[[-8.357,-11.27],[-18.357,-1.395],[-18.732,12.145],[29.131,14.109],[29.131,-11.181]],"c":true}]},{"t":8}]},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.1333333,0.1333333,0.1333333,1]},"o":{"a":0,"k":100},"r":1,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[-0.982,14.395],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"矩形 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":10,"st":-45,"bm":0,"sr":1},{"ddd":0,"ind":7,"ty":4,"nm":"“图层 3”轮廓","parent":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[42.5,45.5,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[5.28,3.24],[0,0],[0.391,0],[0,-1.104],[-0.582,-0.349],[0,0],[-0.147,-0.095],[-0.121,-0.084],[-0.131,-0.097],[-0.11,-0.088],[-0.124,-0.104],[-0.104,-0.093],[-0.113,-0.108],[-0.1,-0.1],[-0.103,-0.111],[-0.095,-0.106],[-0.096,-0.119],[-0.085,-0.108],[-0.09,-0.124],[-0.078,-0.111],[-0.081,-0.127],[-0.069,-0.117],[-0.072,-0.132],[-0.06,-0.118],[-0.065,-0.137],[-0.053,-0.121],[-0.055,-0.138],[-0.045,-0.124],[-0.046,-0.145],[-0.035,-0.123],[-0.037,-0.155],[-0.025,-0.12],[-0.028,-0.168],[-0.016,-0.112],[-0.017,-0.197],[-0.006,-0.086],[0,-0.286],[0,0],[-4.411,2.612],[0,0],[0,0.718],[1.105,0],[0.29,-0.164],[0,0],[0.05,-0.031],[0.018,-0.013],[0.135,-0.087],[0.157,-0.107],[0.16,-0.116],[0.15,-0.115],[0.153,-0.125],[0.14,-0.122],[0.146,-0.135],[0.131,-0.128],[0.137,-0.143],[0.121,-0.134],[0.128,-0.151],[0.113,-0.14],[0.117,-0.157],[0.102,-0.147],[0.108,-0.165],[0.093,-0.151],[0.098,-0.174],[0.08,-0.153],[0.087,-0.181],[0.07,-0.158],[0.075,-0.19],[0.059,-0.161],[0.065,-0.199],[0.046,-0.16],[0.051,-0.208],[0.035,-0.16],[0.038,-0.222],[0.023,-0.153],[0.025,-0.254],[0.009,-0.129],[0,-0.391],[0,0],[-1.105,0],[0,0],[-0.174,1.085],[0,1.375]],"o":[[0,0],[-0.309,-0.195],[-1.105,0],[0,0.73],[0,0],[0.151,0.093],[0.123,0.081],[0.135,0.095],[0.115,0.085],[0.128,0.1],[0.108,0.091],[0.119,0.105],[0.104,0.097],[0.108,0.108],[0.099,0.104],[0.102,0.115],[0.089,0.106],[0.095,0.122],[0.08,0.109],[0.084,0.125],[0.073,0.114],[0.078,0.13],[0.065,0.117],[0.069,0.135],[0.056,0.12],[0.058,0.138],[0.048,0.124],[0.051,0.144],[0.039,0.122],[0.043,0.155],[0.029,0.118],[0.036,0.165],[0.019,0.11],[0.027,0.195],[0.008,0.085],[0.019,0.284],[0,0],[0,-4.669],[0,0],[0.567,-0.353],[0,-1.104],[-0.356,0],[0,0],[-0.051,0.029],[-0.017,0.012],[-0.137,0.083],[-0.16,0.102],[-0.164,0.112],[-0.153,0.111],[-0.157,0.121],[-0.144,0.118],[-0.15,0.13],[-0.135,0.125],[-0.142,0.139],[-0.125,0.132],[-0.133,0.147],[-0.116,0.138],[-0.122,0.154],[-0.108,0.145],[-0.114,0.163],[-0.096,0.149],[-0.104,0.172],[-0.085,0.152],[-0.094,0.179],[-0.075,0.157],[-0.082,0.187],[-0.064,0.159],[-0.071,0.196],[-0.051,0.158],[-0.059,0.207],[-0.04,0.159],[-0.046,0.22],[-0.026,0.152],[-0.035,0.251],[-0.012,0.128],[-0.027,0.385],[0,1.375],[0.162,1.079],[0,0],[1.113,0],[0,0],[0,-6.185]],"v":[[11.254,-9.225],[11.253,-9.223],[10.188,-9.531],[8.188,-7.531],[9.165,-5.822],[9.162,-5.816],[9.602,-5.529],[9.972,-5.285],[10.366,-4.993],[10.708,-4.738],[11.08,-4.428],[11.403,-4.156],[11.746,-3.833],[12.055,-3.54],[12.367,-3.21],[12.661,-2.896],[12.954,-2.544],[13.22,-2.225],[13.492,-1.852],[13.733,-1.525],[13.976,-1.145],[14.195,-0.799],[14.415,-0.404],[14.608,-0.053],[14.802,0.357],[14.971,0.715],[15.135,1.132],[15.28,1.503],[15.419,1.939],[15.536,2.305],[15.65,2.773],[15.737,3.127],[15.825,3.628],[15.883,3.958],[15.944,4.548],[15.971,4.803],[16,5.656],[-16,5.656],[-8.939,-5.951],[-8.944,-5.956],[-8,-7.656],[-10,-9.656],[-10.97,-9.378],[-10.977,-9.391],[-11.125,-9.298],[-11.183,-9.268],[-11.586,-9.007],[-12.065,-8.697],[-12.549,-8.35],[-13.006,-8.014],[-13.467,-7.641],[-13.898,-7.283],[-14.337,-6.882],[-14.74,-6.505],[-15.154,-6.078],[-15.529,-5.684],[-15.915,-5.232],[-16.264,-4.818],[-16.617,-4.348],[-16.939,-3.913],[-17.265,-3.419],[-17.555,-2.971],[-17.852,-2.449],[-18.106,-1.994],[-18.37,-1.451],[-18.594,-0.982],[-18.822,-0.417],[-19.013,0.06],[-19.208,0.657],[-19.361,1.13],[-19.518,1.754],[-19.637,2.229],[-19.756,2.894],[-19.837,3.35],[-19.918,4.111],[-19.958,4.493],[-20,5.656],[-19.82,7.691],[-17.503,9.656],[17.503,9.656],[19.821,7.691],[20,5.656]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.1333333,0.1333333,0.1333333,1]},"o":{"a":0,"k":100},"r":1,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[41.833,60.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":10,"st":-45,"bm":0,"sr":1}]} ================================================ FILE: Example/Classes/Other/LottieResources/tab_message_animate.json ================================================ {"v":"4.6.3","fr":24,"ip":0,"op":10,"w":66,"h":66,"nm":"信息(66x66)","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"空 12","ks":{"o":{"a":0,"k":0},"r":{"a":0,"k":0},"p":{"a":0,"k":[34.562,29.5,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":-1,"s":[100,100,100],"e":[92,92,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":2,"s":[92,92,100],"e":[103,103,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":7,"s":[103,103,100],"e":[100,100,100]},{"t":9}]}},"ao":0,"ip":0,"op":10,"st":-2,"bm":0,"sr":1},{"ddd":0,"ind":2,"ty":4,"nm":"“图层 3”轮廓","parent":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[-11,1,0],"e":[-13.5,1,0],"to":[-0.41666665673256,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[-13.5,1,0],"e":[-11,1,0],"to":[0,0,0],"ti":[-0.41666665673256,0,0]},{"t":9}]},"a":{"a":0,"k":[39.5,49.5,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-1.381],[1.381,0],[0,1.381],[-1.381,0]],"o":[[0,1.381],[-1.381,0],[0,-1.381],[1.381,0]],"v":[[2.5,0],[0,2.5],[-2.5,0],[0,-2.5]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":5,"s":[0.1333333,0.1333333,0.1333333,1],"e":[1,1,1,1]},{"t":6}]},"o":{"a":0,"k":100},"r":1,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[39.5,49.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":10,"st":-22,"bm":0,"sr":1},{"ddd":0,"ind":3,"ty":4,"nm":"“图层 4”轮廓","parent":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":4,"s":[-1,1,0],"e":[-3.5,1,0],"to":[-0.41666665673256,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[-3.5,1,0],"e":[-1,1,0],"to":[0,0,0],"ti":[-0.41666665673256,0,0]},{"t":8}]},"a":{"a":0,"k":[49.5,49.5,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-1.381],[1.381,0],[0,1.381],[-1.381,0]],"o":[[0,1.381],[-1.381,0],[0,-1.381],[1.381,0]],"v":[[2.5,0],[0,2.5],[-2.5,0],[0,-2.5]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":4,"s":[0.1333333,0.1333333,0.1333333,1],"e":[1,1,1,1]},{"t":5}]},"o":{"a":0,"k":100},"r":1,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[49.5,49.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":10,"st":-22,"bm":0,"sr":1},{"ddd":0,"ind":4,"ty":4,"nm":"“图层 2”轮廓","parent":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":3,"s":[9,1,0],"e":[6.5,1,0],"to":[-0.41666665673256,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":4,"s":[6.5,1,0],"e":[9,1,0],"to":[0,0,0],"ti":[-0.41666665673256,0,0]},{"t":7}]},"a":{"a":0,"k":[59.5,49.5,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-1.381],[1.381,0],[0,1.381],[-1.381,0]],"o":[[0,1.381],[-1.381,0],[0,-1.381],[1.381,0]],"v":[[2.5,0],[0,2.5],[-2.5,0],[0,-2.5]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":3,"s":[0.1333333,0.1333333,0.1333333,1],"e":[1,1,1,1]},{"t":4}]},"o":{"a":0,"k":100},"r":1,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[59.5,49.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":10,"st":-22,"bm":0,"sr":1},{"ddd":0,"ind":5,"ty":4,"nm":"形状图层 11","parent":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[-0.557,5.651,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[68.493,68.493,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":0,"s":[{"i":[[1.5,0.125],[-0.372,-18.05],[20.636,-0.031],[22.326,18.969],[-0.41,-1.161],[-2.972,-0.113],[-1.927,0],[-1,-0.375],[-3.316,-3.56],[0.372,2.99],[-4.168,-0.022],[0,2.25],[0.25,2.625]],"o":[[2.533,7.509],[0.277,13.408],[-8.721,0.013],[-3.815,-3.242],[0.322,0.912],[3.956,0.151],[3.375,0],[1,0.375],[-0.539,-2.676],[4.358,0.083],[2.528,0.013],[0,-2.25],[-0.625,-1.875]],"v":[[29.821,-28.983],[31.223,-4.158],[10.489,14.531],[-6.669,15.193],[-34.5,13.75],[-28.121,15.509],[-23.577,15.503],[-9.703,15.736],[8.495,29.114],[8.602,15.878],[29.132,15.74],[33.75,10.125],[33.375,-26.375]],"c":true}],"e":[{"i":[[1.5,0.125],[-0.077,-18.053],[9.089,-9.543],[22.326,18.969],[-0.41,-1.161],[-2.972,-0.113],[-1.927,0],[-1,-0.375],[-3.316,-3.56],[0.372,2.99],[-4.168,-0.022],[0,2.25],[0.25,2.625]],"o":[[2.533,7.509],[0.051,11.834],[-6.015,6.315],[-3.815,-3.242],[0.322,0.912],[3.956,0.151],[3.375,0],[1,0.375],[-0.539,-2.676],[4.358,0.083],[2.528,0.013],[0,-2.25],[-0.625,-1.875]],"v":[[29.821,-28.983],[30.598,-3.783],[8.239,14.531],[-6.669,15.193],[-34.5,13.75],[-28.121,15.509],[-23.577,15.503],[-9.703,15.736],[8.495,29.114],[8.602,15.878],[29.132,15.74],[33.75,10.125],[33.375,-26.375]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":1,"s":[{"i":[[1.5,0.125],[-0.077,-18.053],[9.089,-9.543],[22.326,18.969],[-0.41,-1.161],[-2.972,-0.113],[-1.927,0],[-1,-0.375],[-3.316,-3.56],[0.372,2.99],[-4.168,-0.022],[0,2.25],[0.25,2.625]],"o":[[2.533,7.509],[0.051,11.834],[-6.015,6.315],[-3.815,-3.242],[0.322,0.912],[3.956,0.151],[3.375,0],[1,0.375],[-0.539,-2.676],[4.358,0.083],[2.528,0.013],[0,-2.25],[-0.625,-1.875]],"v":[[29.821,-28.983],[30.598,-3.783],[8.239,14.531],[-6.669,15.193],[-34.5,13.75],[-28.121,15.509],[-23.577,15.503],[-9.703,15.736],[8.495,29.114],[8.602,15.878],[29.132,15.74],[33.75,10.125],[33.375,-26.375]],"c":true}],"e":[{"i":[[1.5,0.125],[-0.077,-18.053],[4.786,-8.116],[8.767,8.974],[-0.41,-1.161],[-2.972,-0.113],[-1.927,0],[-1,-0.375],[-3.316,-3.56],[-2.577,2.273],[-4.168,-0.022],[0,2.25],[0.25,2.625]],"o":[[2.533,7.509],[0.051,11.834],[-4.43,7.512],[-3.498,-3.581],[0.322,0.912],[3.956,0.151],[3.375,0],[1,0.375],[-0.539,-2.676],[4.358,0.083],[2.528,0.013],[0,-2.25],[-0.625,-1.875]],"v":[[29.821,-28.983],[31.112,-7.124],[2.969,14.017],[-7.312,15.579],[-34.5,13.75],[-28.121,15.509],[-23.577,15.503],[-15.23,15.993],[7.852,29.242],[8.216,15.878],[29.132,15.74],[33.75,10.125],[33.375,-26.375]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":2,"s":[{"i":[[1.5,0.125],[-0.077,-18.053],[4.786,-8.116],[8.767,8.974],[-0.41,-1.161],[-2.972,-0.113],[-1.927,0],[-1,-0.375],[-3.316,-3.56],[-2.577,2.273],[-4.168,-0.022],[0,2.25],[0.25,2.625]],"o":[[2.533,7.509],[0.051,11.834],[-4.43,7.512],[-3.498,-3.581],[0.322,0.912],[3.956,0.151],[3.375,0],[1,0.375],[-0.539,-2.676],[4.358,0.083],[2.528,0.013],[0,-2.25],[-0.625,-1.875]],"v":[[29.821,-28.983],[31.112,-7.124],[2.969,14.017],[-7.312,15.579],[-34.5,13.75],[-28.121,15.509],[-23.577,15.503],[-15.23,15.993],[7.852,29.242],[8.216,15.878],[29.132,15.74],[33.75,10.125],[33.375,-26.375]],"c":true}],"e":[{"i":[[1.5,0.125],[6.538,-12.759],[6.759,-6.414],[8.767,8.974],[-0.41,-1.161],[-2.972,-0.113],[-1.927,0],[-1,-0.375],[-3.316,-3.56],[-2.577,2.273],[-4.168,-0.022],[0,2.25],[0.25,2.625]],"o":[[-1.304,0.068],[-6.163,12.027],[-6.326,6.003],[-3.498,-3.581],[0.322,0.912],[3.956,0.151],[3.375,0],[1,0.375],[-0.539,-2.676],[4.358,0.083],[2.528,0.013],[0,-2.25],[-0.625,-1.875]],"v":[[29.821,-28.983],[27.145,-6.727],[5.085,9.652],[-9.956,15.711],[-34.5,13.75],[-28.121,15.509],[-23.577,15.503],[-15.23,15.993],[5.075,29.639],[4.91,15.878],[29.132,15.74],[33.75,10.125],[33.375,-26.375]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":3,"s":[{"i":[[1.5,0.125],[6.538,-12.759],[6.759,-6.414],[8.767,8.974],[-0.41,-1.161],[-2.972,-0.113],[-1.927,0],[-1,-0.375],[-3.316,-3.56],[-2.577,2.273],[-4.168,-0.022],[0,2.25],[0.25,2.625]],"o":[[-1.304,0.068],[-6.163,12.027],[-6.326,6.003],[-3.498,-3.581],[0.322,0.912],[3.956,0.151],[3.375,0],[1,0.375],[-0.539,-2.676],[4.358,0.083],[2.528,0.013],[0,-2.25],[-0.625,-1.875]],"v":[[29.821,-28.983],[27.145,-6.727],[5.085,9.652],[-9.956,15.711],[-34.5,13.75],[-28.121,15.509],[-23.577,15.503],[-15.23,15.993],[5.075,29.639],[4.91,15.878],[29.132,15.74],[33.75,10.125],[33.375,-26.375]],"c":true}],"e":[{"i":[[1.5,0.125],[2.789,-3.235],[6.759,-6.414],[5.685,-9.097],[-0.41,-1.161],[-2.972,-0.113],[-1.927,0],[-1,-0.375],[-3.316,-3.56],[-2.577,2.273],[-4.168,-0.022],[0,2.25],[0.25,2.625]],"o":[[-3,0.25],[-2.449,2.84],[-6.326,6.003],[-2.653,4.246],[0.322,0.912],[3.956,0.151],[3.375,0],[1,0.375],[-0.539,-2.676],[4.358,0.083],[2.528,0.013],[0,-2.25],[-0.625,-1.875]],"v":[[27.625,-29.5],[20.3,-25.714],[9.348,-9.205],[-16.673,11.449],[-34.5,13.75],[-28.121,15.509],[-23.577,15.503],[-15.23,15.993],[5.075,29.639],[4.91,15.878],[29.132,15.74],[33.75,10.125],[33.375,-26.375]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":4,"s":[{"i":[[1.5,0.125],[2.789,-3.235],[6.759,-6.414],[5.685,-9.097],[-0.41,-1.161],[-2.972,-0.113],[-1.927,0],[-1,-0.375],[-3.316,-3.56],[-2.577,2.273],[-4.168,-0.022],[0,2.25],[0.25,2.625]],"o":[[-3,0.25],[-2.449,2.84],[-6.326,6.003],[-2.653,4.246],[0.322,0.912],[3.956,0.151],[3.375,0],[1,0.375],[-0.539,-2.676],[4.358,0.083],[2.528,0.013],[0,-2.25],[-0.625,-1.875]],"v":[[27.625,-29.5],[20.3,-25.714],[9.348,-9.205],[-16.673,11.449],[-34.5,13.75],[-28.121,15.509],[-23.577,15.503],[-15.23,15.993],[5.075,29.639],[4.91,15.878],[29.132,15.74],[33.75,10.125],[33.375,-26.375]],"c":true}],"e":[{"i":[[1.5,0.125],[3.75,0],[1.913,-4.424],[6.378,-2.468],[-0.41,-1.161],[-2.972,-0.113],[-1.927,0],[-1,-0.375],[-1.704,-3.936],[-2.577,2.273],[-4.168,-0.022],[0,2.25],[0.25,2.625]],"o":[[-3,0.25],[-3.75,0],[-0.955,2.207],[-4.669,1.807],[0.322,0.912],[3.956,0.151],[3.375,0],[1,0.375],[3.043,-2.078],[4.358,0.083],[2.528,0.013],[0,-2.25],[-0.625,-1.875]],"v":[[27.625,-29.5],[-5.447,-29.5],[-13.749,-11.476],[-30.43,7.915],[-34.5,13.75],[-28.121,15.509],[-23.577,15.503],[-15.23,15.993],[-7.294,28.755],[4.91,15.878],[29.132,15.74],[33.75,10.125],[33.375,-26.375]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[{"i":[[1.5,0.125],[3.75,0],[1.913,-4.424],[6.378,-2.468],[-0.41,-1.161],[-2.972,-0.113],[-1.927,0],[-1,-0.375],[-1.704,-3.936],[-2.577,2.273],[-4.168,-0.022],[0,2.25],[0.25,2.625]],"o":[[-3,0.25],[-3.75,0],[-0.955,2.207],[-4.669,1.807],[0.322,0.912],[3.956,0.151],[3.375,0],[1,0.375],[3.043,-2.078],[4.358,0.083],[2.528,0.013],[0,-2.25],[-0.625,-1.875]],"v":[[27.625,-29.5],[-5.447,-29.5],[-13.749,-11.476],[-30.43,7.915],[-34.5,13.75],[-28.121,15.509],[-23.577,15.503],[-15.23,15.993],[-7.294,28.755],[4.91,15.878],[29.132,15.74],[33.75,10.125],[33.375,-26.375]],"c":true}],"e":[{"i":[[1.5,0.125],[3.75,0],[2.125,-1.125],[0.25,-5],[-0.41,-1.161],[-2.972,-0.113],[-1.927,0],[-1,-0.375],[1.422,-3.689],[-2.577,2.273],[-4.168,-0.022],[0,2.25],[0.25,2.625]],"o":[[-3,0.25],[-3.75,0],[-2.125,1.125],[-0.25,5],[0.322,0.912],[3.956,0.151],[3.375,0],[1,0.375],[3.043,-2.078],[4.358,0.083],[2.528,0.013],[0,-2.25],[-0.625,-1.875]],"v":[[27.625,-29.5],[-11,-29.5],[-32.875,-28.875],[-34.625,-8.25],[-34.5,13.75],[-28.121,15.509],[-23.577,15.503],[-15.23,15.993],[-19.016,28.632],[4.91,15.878],[29.132,15.74],[33.75,10.125],[33.375,-26.375]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[1.5,0.125],[3.75,0],[2.125,-1.125],[0.25,-5],[-0.41,-1.161],[-2.972,-0.113],[-1.927,0],[-1,-0.375],[1.422,-3.689],[-2.577,2.273],[-4.168,-0.022],[0,2.25],[0.25,2.625]],"o":[[-3,0.25],[-3.75,0],[-2.125,1.125],[-0.25,5],[0.322,0.912],[3.956,0.151],[3.375,0],[1,0.375],[3.043,-2.078],[4.358,0.083],[2.528,0.013],[0,-2.25],[-0.625,-1.875]],"v":[[27.625,-29.5],[-11,-29.5],[-32.875,-28.875],[-34.625,-8.25],[-34.5,13.75],[-28.121,15.509],[-23.577,15.503],[-15.23,15.993],[-19.016,28.632],[4.91,15.878],[29.132,15.74],[33.75,10.125],[33.375,-26.375]],"c":true}],"e":[{"i":[[1.5,0.125],[3.75,0],[2.125,-1.125],[0.25,-5],[-0.41,-1.161],[-2.972,-0.113],[-1.927,0],[-1,-0.375],[0.002,-2.808],[-2.577,2.273],[-4.168,-0.022],[0,2.25],[0.25,2.625]],"o":[[-3,0.25],[-3.75,0],[-2.125,1.125],[-0.25,5],[0.322,0.912],[3.956,0.151],[3.375,0],[1,0.375],[3.043,-2.078],[4.358,0.083],[2.528,0.013],[0,-2.25],[-0.625,-1.875]],"v":[[27.625,-29.5],[-11,-29.5],[-32.875,-28.875],[-34.625,-8.25],[-34.5,13.75],[-28.121,15.509],[-23.577,15.503],[-15.23,15.993],[-17.93,28.632],[4.91,15.878],[29.132,15.74],[33.75,10.125],[33.375,-26.375]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[1.5,0.125],[3.75,0],[2.125,-1.125],[0.25,-5],[-0.41,-1.161],[-2.972,-0.113],[-1.927,0],[-1,-0.375],[0.002,-2.808],[-2.577,2.273],[-4.168,-0.022],[0,2.25],[0.25,2.625]],"o":[[-3,0.25],[-3.75,0],[-2.125,1.125],[-0.25,5],[0.322,0.912],[3.956,0.151],[3.375,0],[1,0.375],[3.043,-2.078],[4.358,0.083],[2.528,0.013],[0,-2.25],[-0.625,-1.875]],"v":[[27.625,-29.5],[-11,-29.5],[-32.875,-28.875],[-34.625,-8.25],[-34.5,13.75],[-28.121,15.509],[-23.577,15.503],[-15.23,15.993],[-17.93,28.632],[4.91,15.878],[29.132,15.74],[33.75,10.125],[33.375,-26.375]],"c":true}],"e":[{"i":[[1.5,0.125],[3.75,0],[2.125,-1.125],[0.25,-5],[-0.41,-1.161],[-2.972,-0.113],[-1.927,0],[-1,-0.375],[0.002,-2.808],[-2.577,2.273],[-4.168,-0.022],[0,2.25],[0.25,2.625]],"o":[[-3,0.25],[-3.75,0],[-2.125,1.125],[-0.25,5],[0.322,0.912],[3.956,0.151],[3.375,0],[1,0.375],[3.043,-2.078],[4.358,0.083],[2.528,0.013],[0,-2.25],[-0.625,-1.875]],"v":[[27.625,-29.5],[-11,-29.5],[-32.875,-28.875],[-34.625,-8.25],[-34.5,13.75],[-28.121,15.509],[-23.577,15.503],[-16.057,15.875],[-16.04,28.868],[4.91,15.878],[29.132,15.74],[33.75,10.125],[33.375,-26.375]],"c":true}]},{"t":9}]},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.1333333,0.1333333,0.1333333,1]},"o":{"a":0,"k":100},"r":1,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"形状 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":10,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":6,"ty":4,"nm":"“图层 1”轮廓 2","parent":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[-2,0.5,0]},"a":{"a":0,"k":[48.5,49,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":0,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,-2.758],[0,0],[0,0],[1.229,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[-2.758,0],[0,0],[0,0],[-1.003,-0.711],[0,0],[0,0],[0,0]],"v":[[20.496,-17.098],[20.5,-17.094],[20.491,7.902],[9.502,7.902],[4.5,12.904],[4.5,14.227],[-2.891,8.989],[-6.303,7.902],[-20.5,7.898],[-20.49,-17.098]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,-2.758],[0,0],[0,0],[1.229,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[-2.758,0],[0,0],[0,0],[-1.003,-0.711],[0,0],[0,0],[0,0]],"v":[[20.496,-17.098],[20.5,-17.094],[20.491,7.902],[4.502,7.902],[-0.5,12.904],[-0.5,14.227],[-7.891,8.989],[-11.303,7.902],[-20.5,7.898],[-20.49,-17.098]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":4,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,-2.758],[0,0],[0,0],[1.229,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[-2.758,0],[0,0],[0,0],[-1.003,-0.711],[0,0],[0,0],[0,0]],"v":[[20.496,-17.098],[20.5,-17.094],[20.491,7.902],[4.502,7.902],[-0.5,12.904],[-0.5,14.227],[-7.891,8.989],[-11.303,7.902],[-20.5,7.898],[-20.49,-17.098]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[0,0],[2.188,-1.593],[0,0],[0,0],[1.229,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[-2.758,0],[0,0],[0,0],[-1.003,-0.711],[0,0],[0,0],[0,0]],"v":[[20.496,-17.098],[20.5,-17.094],[20.491,7.902],[4.502,7.902],[-5.312,12.927],[-7.938,14.203],[-7.891,8.989],[-11.303,7.902],[-20.5,7.898],[-20.49,-17.098]],"c":true}]},{"t":6}]},"nm":"路径 2","mn":"ADBE Vector Shape - Group"},{"ty":"mm","mm":1,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge"},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[49.5,54.098],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":10,"st":-22,"bm":0,"sr":1},{"ddd":0,"ind":7,"ty":4,"nm":"“图层 1”轮廓","parent":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[-2,0.5,0]},"a":{"a":0,"k":[48.5,49,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":0,"s":[{"i":[[2.211,0],[0,0],[0,-2.215],[0,0],[-2.212,0],[0,0],[-0.321,-0.228],[0,0],[-0.241,0],[0,0.744],[0,0],[-0.551,0],[0,0],[0,2.215],[0,0]],"o":[[0,0],[-2.214,0],[0,0],[0,2.211],[0,0],[0.394,0],[0,0],[0.3,0.207],[0.499,0],[0,0],[0,-0.551],[0,0],[2.214,0],[0,0],[0,-2.211]],"v":[[20.496,-21.098],[-20.49,-21.098],[-24.5,-17.089],[-24.5,7.898],[-20.495,11.902],[-6.303,11.902],[-5.204,12.251],[6.849,20.795],[7.67,21.098],[8.5,19.935],[8.5,12.904],[9.502,11.902],[20.491,11.902],[24.5,7.892],[24.5,-17.094]],"c":true}],"e":[{"i":[[2.211,0],[0,0],[0,-2.215],[0,0],[-2.212,0],[0,0],[-0.321,-0.228],[0,0],[-0.241,0],[0,0.744],[0,0],[-0.551,0],[0,0],[0,2.215],[0,0]],"o":[[0,0],[-2.214,0],[0,0],[0,2.211],[0,0],[0.394,0],[0,0],[0.3,0.207],[0.499,0],[0,0],[0,-0.551],[0,0],[2.214,0],[0,0],[0,-2.211]],"v":[[20.496,-21.098],[-20.49,-21.098],[-24.5,-17.089],[-24.5,7.898],[-20.495,11.902],[-11.303,11.902],[-10.204,12.251],[3.255,20.795],[4.076,21.098],[4.906,19.935],[3.5,12.904],[4.502,11.902],[20.491,11.902],[24.5,7.892],[24.5,-17.094]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":4,"s":[{"i":[[2.211,0],[0,0],[0,-2.215],[0,0],[-2.212,0],[0,0],[-0.321,-0.228],[0,0],[-0.241,0],[0,0.744],[0,0],[-0.551,0],[0,0],[0,2.215],[0,0]],"o":[[0,0],[-2.214,0],[0,0],[0,2.211],[0,0],[0.394,0],[0,0],[0.3,0.207],[0.499,0],[0,0],[0,-0.551],[0,0],[2.214,0],[0,0],[0,-2.211]],"v":[[20.496,-21.098],[-20.49,-21.098],[-24.5,-17.089],[-24.5,7.898],[-20.495,11.902],[-11.303,11.902],[-10.204,12.251],[3.255,20.795],[4.076,21.098],[4.906,19.935],[3.5,12.904],[4.502,11.902],[20.491,11.902],[24.5,7.892],[24.5,-17.094]],"c":true}],"e":[{"i":[[2.211,0],[0,0],[0,-2.215],[0,0],[-2.212,0],[0,0],[-0.321,-0.228],[0,0],[-0.241,0],[-0.664,0.422],[0,0],[-0.551,0],[0,0],[0,2.215],[0,0]],"o":[[0,0],[-2.214,0],[0,0],[0,2.211],[0,0],[0.394,0],[0,0],[-0.263,0.687],[0.604,0.196],[0,0],[0.563,-0.314],[0,0],[2.214,0],[0,0],[0,-2.211]],"v":[[20.496,-21.098],[-20.49,-21.098],[-24.5,-17.089],[-24.5,7.898],[-20.495,11.902],[-11.303,11.902],[-10.579,12.626],[-13.674,19.589],[-13.541,20.768],[-11.523,20.104],[2.938,12.841],[4.502,11.902],[20.491,11.902],[24.5,7.891],[24.5,-17.094]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[2.211,0],[0,0],[0,-2.215],[0,0],[-2.212,0],[0,0],[-0.321,-0.228],[0,0],[-0.241,0],[-0.664,0.422],[0,0],[-0.551,0],[0,0],[0,2.215],[0,0]],"o":[[0,0],[-2.214,0],[0,0],[0,2.211],[0,0],[0.394,0],[0,0],[-0.263,0.687],[0.604,0.196],[0,0],[0.563,-0.314],[0,0],[2.214,0],[0,0],[0,-2.211]],"v":[[20.496,-21.098],[-20.49,-21.098],[-24.5,-17.089],[-24.5,7.898],[-20.495,11.902],[-11.303,11.902],[-10.579,12.626],[-13.674,19.589],[-13.541,20.768],[-11.523,20.104],[2.938,12.841],[4.502,11.902],[20.491,11.902],[24.5,7.891],[24.5,-17.094]],"c":true}],"e":[{"i":[[2.211,0],[0,0],[0,-2.215],[0,0],[-2.212,0],[0,0],[-0.321,-0.228],[0,0],[-0.241,0],[-0.664,0.422],[0,0],[-0.551,0],[0,0],[0,2.215],[0,0]],"o":[[0,0],[-2.214,0],[0,0],[0,2.211],[0,0],[1.116,-0.027],[0,0],[-0.013,0.646],[0.604,0.196],[0,0],[0.563,-0.314],[0,0],[2.214,0],[0,0],[0,-2.211]],"v":[[20.496,-21.098],[-20.49,-21.098],[-24.5,-17.089],[-24.5,7.898],[-20.495,11.902],[-12.74,11.928],[-11.516,12.631],[-11.424,19.568],[-11.041,20.747],[-9.023,20.083],[2.938,12.841],[5.377,11.928],[20.491,11.902],[24.5,7.891],[24.5,-17.094]],"c":true}]},{"t":9}]},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ind":1,"ty":"sh","ix":2,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":0,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,-2.758],[0,0],[0,0],[1.229,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[-2.758,0],[0,0],[0,0],[-1.003,-0.711],[0,0],[0,0],[0,0]],"v":[[20.496,-17.098],[20.5,-17.094],[20.491,7.902],[9.502,7.902],[4.5,12.904],[4.5,14.227],[-2.891,8.989],[-6.303,7.902],[-20.5,7.898],[-20.49,-17.098]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,-2.758],[0,0],[0,0],[1.229,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[-2.758,0],[0,0],[0,0],[-1.003,-0.711],[0,0],[0,0],[0,0]],"v":[[20.496,-17.098],[20.5,-17.094],[20.491,7.902],[4.502,7.902],[-0.5,12.904],[-0.5,14.227],[-7.891,8.989],[-11.303,7.902],[-20.5,7.898],[-20.49,-17.098]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":4,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,-2.758],[0,0],[0,0],[1.229,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[-2.758,0],[0,0],[0,0],[-1.003,-0.711],[0,0],[0,0],[0,0]],"v":[[20.496,-17.098],[20.5,-17.094],[20.491,7.902],[4.502,7.902],[-0.5,12.904],[-0.5,14.227],[-7.891,8.989],[-11.303,7.902],[-20.5,7.898],[-20.49,-17.098]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[0,0],[2.188,-1.593],[0,0],[0,0],[1.229,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[-2.758,0],[0,0],[0,0],[-1.003,-0.711],[0,0],[0,0],[0,0]],"v":[[20.496,-17.098],[20.5,-17.094],[20.491,7.902],[4.502,7.902],[-5.312,12.927],[-7.938,14.203],[-7.891,8.989],[-11.303,7.902],[-20.5,7.898],[-20.49,-17.098]],"c":true}]},{"t":6}]},"nm":"路径 2","mn":"ADBE Vector Shape - Group"},{"ty":"mm","mm":1,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge"},{"ty":"fl","c":{"a":0,"k":[0.133,0.133,0.133,1]},"o":{"a":0,"k":100},"r":1,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[49.5,54.098],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":4,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":10,"st":-22,"bm":0,"sr":1}]} ================================================ FILE: Example/Classes/Other/LottieResources/tab_search_animate.json ================================================ {"v":"4.6.3","fr":24,"ip":0,"op":10,"w":66,"h":66,"nm":"地球(66x66)","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"空 12","ks":{"o":{"a":0,"k":0},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":3,"s":[0],"e":[-5]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":6,"s":[-5],"e":[0]},{"t":9}]},"p":{"a":0,"k":[32.375,31.5,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":-1,"s":[100,100,100],"e":[92,92,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":3,"s":[92,92,100],"e":[103,103,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":7,"s":[103,103,100],"e":[100,100,100]},{"t":9}]}},"ao":0,"ip":0,"op":10,"st":-1,"bm":0,"sr":1},{"ddd":0,"ind":2,"ty":4,"nm":"形状图层 5","parent":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.999,"y":1},"o":{"x":0.59,"y":0},"n":"0p999_1_0p59_0","t":2,"s":[-8.614,-7.245,0],"e":[6.347,-10.364,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.999,"y":1},"o":{"x":0.001,"y":0},"n":"0p999_1_0p001_0","t":7,"s":[6.347,-10.364,0],"e":[5.09,-10.1,0],"to":[0,0,0],"ti":[0,0,0]},{"t":9}]},"a":{"a":0,"k":[-11.598,-6.663,0]},"s":{"a":0,"k":[88.312,88.312,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[4.278,4.278]},"p":{"a":0,"k":[0,0]},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse"},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[-11.598,-6.663],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"椭圆 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":2,"op":10,"st":-22,"bm":0,"sr":1},{"ddd":0,"ind":3,"ty":4,"nm":"形状图层 4","parent":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.999,"y":1},"o":{"x":0.59,"y":0},"n":"0p999_1_0p59_0","t":2,"s":[-1.892,15.666,0],"e":[13.881,11.86,0],"to":[2.83333325386047,0.03125,0],"ti":[-3.80208325386047,1.21875,0]},{"i":{"x":0.999,"y":1},"o":{"x":0.001,"y":0},"n":"0p999_1_0p001_0","t":7,"s":[13.881,11.86,0],"e":[12.374,12.249,0],"to":[-0.04859279468656,0.04732451215386,0],"ti":[0,0,0]},{"t":9}]},"a":{"a":0,"k":[-14.376,-0.626,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[1.998,1.998]},"p":{"a":0,"k":[0,0]},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse"},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[-14.376,-0.626],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"椭圆 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":2,"op":10,"st":-22,"bm":0,"sr":1},{"ddd":0,"ind":4,"ty":4,"nm":"形状图层 3","parent":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.999,"y":1},"o":{"x":0.59,"y":0},"n":"0p999_1_0p59_0","t":2,"s":[-11.642,-0.709,0],"e":[3.756,-2.89,0],"to":[2.83333325386047,0.03125,0],"ti":[-3.67708325386047,0.59375,0]},{"i":{"x":0.999,"y":1},"o":{"x":0.001,"y":0},"n":"0p999_1_0p001_0","t":7,"s":[3.756,-2.89,0],"e":[2.249,-2.626,0],"to":[0.00749717839062,0.02958649583161,0],"ti":[0,0,0]},{"t":9}]},"a":{"a":0,"k":[-14.376,-0.626,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[1.998,1.998]},"p":{"a":0,"k":[0,0]},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse"},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[-14.376,-0.626],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"椭圆 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":2,"op":10,"st":-22,"bm":0,"sr":1},{"ddd":0,"ind":5,"ty":4,"nm":"“图层 4”轮廓","parent":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.999,"y":1},"o":{"x":0.59,"y":0},"n":"0p999_1_0p59_0","t":0,"s":[6.789,-8.273,0],"e":[17.539,-11.273,0],"to":[1.79166662693024,-0.5,0],"ti":[-1.79166662693024,0.5,0]},{"t":5}]},"a":{"a":0,"k":[57.289,40.227,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-1.002],[1.002,0],[0,1.002],[-1.002,0]],"o":[[0,1.002],[-1.002,0],[0,-1.002],[1.002,0]],"v":[[1.814,0],[0,1.814],[-1.814,0],[0,-1.814]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"st","c":{"a":0,"k":[0.133,0.133,0.133,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":1},"lc":1,"lj":1,"ml":10,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"tr","p":{"a":0,"k":[57.289,40.227],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":4,"st":-4,"bm":0,"sr":1},{"ddd":0,"ind":6,"ty":4,"nm":"“图层 3”轮廓","parent":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.999,"y":1},"o":{"x":0.59,"y":0},"n":"0p999_1_0p59_0","t":0,"s":[2.078,-11.188,0],"e":[12.828,-14.188,0],"to":[1.79166662693024,-0.5,0],"ti":[-1.79166662693024,0.5,0]},{"t":5}]},"a":{"a":0,"k":[52.578,37.312,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.652],[0.653,0],[0,0.652],[-0.652,0]],"o":[[0,0.652],[-0.652,0],[0,-0.652],[0.653,0]],"v":[[1.182,0],[-0.001,1.182],[-1.182,0],[-0.001,-1.182]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"st","c":{"a":0,"k":[0.133,0.133,0.133,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":1},"lc":1,"lj":1,"ml":10,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"tr","p":{"a":0,"k":[52.578,37.312],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":4,"st":-4,"bm":0,"sr":1},{"ddd":0,"ind":7,"ty":4,"nm":"“图层 2”轮廓","parent":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.999,"y":1},"o":{"x":0.59,"y":0},"n":"0p999_1_0p59_0","t":0,"s":[8.992,13.133,0],"e":[19.742,10.133,0],"to":[1.79166662693024,-0.5,0],"ti":[-1.79166662693024,0.5,0]},{"t":5}]},"a":{"a":0,"k":[59.492,61.633,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.764],[0.764,0],[0,0.764],[-0.763,0]],"o":[[0,0.764],[-0.763,0],[0,-0.764],[0.764,0]],"v":[[1.383,0],[0,1.383],[-1.383,0],[0,-1.383]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.133,0.133,0.133,1]},"o":{"a":0,"k":100},"r":1,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[59.492,61.633],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":4,"st":-4,"bm":0,"sr":1},{"ddd":0,"ind":8,"ty":4,"nm":"“图层 12”轮廓 2","parent":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[0.86,1.5,0]},"a":{"a":0,"k":[51.36,50,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-12.151],[0,0],[-1.188,-0.039],[0,0.992],[0,0],[-9.941,0],[-2.039,-7.705],[-1.149,0.688],[0.205,0.564],[9.757,0]],"o":[[0,0.454],[0.076,0.742],[1.188,0.04],[0,0],[0,-9.941],[8.345,0],[0.324,0.797],[1.16,-0.694],[-2.881,-8.795],[-12.151,0]],"v":[[-22.499,0],[-22.458,1.008],[-20.499,2.601],[-18.499,1.008],[-18.499,0],[-0.499,-18],[16.904,-4.617],[19.595,-3.969],[20.413,-6.853],[-0.499,-22]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0.34,-0.373],[0,0],[0,0],[-0.5,-0.308],[-0.792,-0.413],[-2.472,-0.314],[-7.605,1.617],[-4.728,2.867],[-0.892,1.121],[0,0],[0.496,0.292],[0.95,0.337],[0,0.946],[-1.16,0],[-0.187,-0.055],[0,0],[-0.411,-1.933],[16.522,-3.513],[1.225,5.763],[-2.031,1.988],[-0.007,-0.007],[-0.529,0],[0,-1.16]],"o":[[0.005,0.005],[-0.682,0.667],[-0.323,0.484],[0,0],[1.271,0.662],[5.485,0.695],[7.605,-1.617],[2.131,-1.292],[0.556,-0.7],[0.299,-0.497],[0,0],[-0.86,-0.262],[0,-1.16],[0.205,0],[0,0],[2.957,0.994],[1.225,5.763],[-16.522,3.513],[-0.387,-1.82],[0,0],[0.369,-0.323],[1.16,0],[0,0.545]],"v":[[-24.456,3.38],[-24.449,3.388],[-25.304,4.423],[-25.029,5.901],[-24.853,5.995],[-19.154,7.506],[1.242,6.123],[20.436,-0.911],[25.028,-4.609],[25.15,-4.767],[24.795,-6.211],[23.347,-6.917],[21.86,-8.926],[23.96,-11.026],[24.551,-10.941],[24.558,-10.962],[29.818,-6.545],[2.119,10.251],[-30.015,6.176],[-27.4,0.373],[-27.39,0.383],[-26.008,-0.135],[-23.908,1.965]],"c":true}},"nm":"路径 2","mn":"ADBE Vector Shape - Group"},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,0],[-1.605,-0.064],[-6.923,0],[-0.71,9.291],[-1.234,0.731],[0,-0.239],[12.15,0],[3.188,8.221]],"o":[[1.439,0.209],[3.011,5.73],[9.473,0],[1.455,-0.67],[0.007,0.237],[0,12.15],[-9.347,0],[0,0]],"v":[[-21.056,7.994],[-16.48,8.405],[-0.536,18.043],[17.411,1.434],[21.453,-0.67],[21.464,0.043],[-0.536,22.043],[-21.056,7.994]],"c":true}},"nm":"路径 3","mn":"ADBE Vector Shape - Group"},{"ty":"mm","mm":1,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge"},{"ty":"fl","c":{"a":0,"k":[0.1333333,0.1333333,0.1333333,1]},"o":{"a":0,"k":100},"r":1,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[51.499,50],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":5,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":10,"st":-4,"bm":0,"sr":1},{"ddd":0,"ind":10,"ty":4,"nm":"形状图层 1","parent":1,"td":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.999,"y":1},"o":{"x":0.59,"y":0},"n":"0p999_1_0p59_0","t":0,"s":[{"i":[[-0.875,-14.375],[-6.812,-2.25],[3.387,6.235],[0.184,2.986],[0,0.419],[-11.046,0]],"o":[[0.875,14.375],[-7.594,0],[-1.352,-2.49],[-0.025,-0.413],[0,-11.046],[-5,1.75]],"v":[[-17.014,0.88],[-2.077,20.442],[-19.663,9.975],[-22.039,1.69],[-22.077,0.442],[-2.077,-19.558]],"c":true}],"e":[{"i":[[-0.275,-15.238],[11.036,0],[3.718,6.848],[0.202,3.279],[0,0.46],[-12.131,0]],"o":[[0.24,13.315],[-8.34,0],[-1.485,-2.735],[-0.027,-0.454],[0,-12.131],[10.159,0]],"v":[[21.71,0.052],[-0.254,22.016],[-19.568,10.521],[-22.177,1.422],[-22.219,0.052],[-0.254,-21.913]],"c":true}]},{"t":8}]},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[0.494,1.198],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"椭圆 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":10,"st":-4,"bm":0,"sr":1},{"ddd":0,"ind":11,"ty":4,"nm":"“图层 5”轮廓","parent":1,"tt":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[50.5,48.5,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.025,0.646],[-12.143,0.424],[-3.186,-8.688],[1.136,-0.734],[14.314,-2.001],[1.642,0.454],[0.229,0.358]],"o":[[-0.424,-12.143],[9.751,-0.341],[0.225,0.557],[-0.552,0.358],[-10.341,1.242],[-1.641,-0.454],[-0.282,-0.437]],"v":[[-21.462,9.572],[-0.243,-13.182],[21.184,1.225],[20.751,4.729],[-2.356,12.282],[-18.656,12.839],[-21.046,11.275]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.133,0.133,0.133,1]},"o":{"a":0,"k":100},"r":1,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[50.468,41.209],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":10,"st":-4,"bm":0,"sr":1},{"ddd":0,"ind":12,"ty":4,"nm":"形状图层 2","parent":1,"td":1,"ks":{"o":{"a":0,"k":100},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":3,"s":[0],"e":[-3]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":6,"s":[-3],"e":[0]},{"t":9}]},"p":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":0,"s":[100,100,100],"e":[96,96,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":3,"s":[96,96,100],"e":[103,103,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":8,"s":[103,103,100],"e":[100,100,100]},{"t":9}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.999,"y":1},"o":{"x":0.59,"y":0},"n":"0p999_1_0p59_0","t":0,"s":[{"i":[[-0.875,-14.375],[-6.812,-2.25],[3.387,6.235],[0.184,2.986],[0,0.419],[-11.046,0]],"o":[[0.875,14.375],[-7.594,0],[-1.352,-2.49],[-0.025,-0.413],[0,-11.046],[-5,1.75]],"v":[[-14.931,0.489],[0.006,20.052],[-17.58,9.585],[-19.956,1.3],[-19.994,0.052],[0.006,-19.948]],"c":true}],"e":[{"i":[[-0.25,-13.875],[10.049,0],[3.387,6.235],[0.184,2.986],[0,0.419],[-11.046,0]],"o":[[0.218,12.124],[-7.594,0],[-1.352,-2.49],[-0.025,-0.413],[0,-11.046],[9.25,0]],"v":[[19.756,0.052],[-0.244,20.052],[-17.83,9.585],[-20.206,1.3],[-20.244,0.052],[-0.244,-19.948]],"c":true}]},{"t":8}]},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[0.494,1.198],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"椭圆 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":10,"st":-4,"bm":0,"sr":1},{"ddd":0,"ind":13,"ty":4,"nm":"“图层 6”轮廓","parent":1,"tt":1,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[0,0,0]},"a":{"a":0,"k":[50.5,48.5,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[19.341,-1.949],[-6.923,0],[-0.71,9.291]],"o":[[3.011,5.73],[9.473,0],[-7.758,2.355]],"v":[[-16.945,-1.334],[-1.001,8.305],[16.945,-8.305]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.133,0.133,0.133,1]},"o":{"a":0,"k":100},"r":1,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[52.479,61.7],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":10,"st":-4,"bm":0,"sr":1}]} ================================================ FILE: Example/Classes/View/CYLPlusButtonSubclass.h ================================================ // // CYLPlusButtonSubclass.h // CYLTabBarControllerDemo // // v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 15/10/24. // Copyright (c) 2018年 https://github.com/ChenYilong . All rights reserved. // #import "CYLPlusButton.h" @interface CYLPlusButtonSubclass : CYLPlusButton @end ================================================ FILE: Example/Classes/View/CYLPlusButtonSubclass.m ================================================ // // CYLPlusButtonSubclass.m // CYLTabBarControllerDemo // // v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 15/10/24. // Copyright (c) 2018年 https://github.com/ChenYilong . All rights reserved. // #import "CYLPlusButtonSubclass.h" #import "CYLMineViewController.h" @interface CYLPlusButtonSubclass () { CGFloat _buttonImageHeight; } @end @implementation CYLPlusButtonSubclass #pragma mark - #pragma mark - Life Cycle + (void)load { //请在 `-[AppDelegate application:didFinishLaunchingWithOptions:]` 中进行注册,否则iOS10系统下存在Crash风险。 //[super registerPlusButton]; } - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { self.titleLabel.textAlignment = NSTextAlignmentCenter; self.adjustsImageWhenHighlighted = NO; } return self; } //上下结构的 button //- (void)layoutSubviews { // [super layoutSubviews]; // // // 控件大小,间距大小 // // 注意:一定要根据项目中的图片去调整下面的0.7和0.9,Demo之所以这么设置,因为demo中的 plusButton 的 icon 不是正方形。 // CGFloat const imageViewEdgeWidth = self.bounds.size.width * 0.7; // CGFloat const imageViewEdgeHeight = imageViewEdgeWidth * 0.9; // // CGFloat const centerOfView = self.bounds.size.width * 0.5; // CGFloat const labelLineHeight = self.titleLabel.font.lineHeight; // CGFloat const verticalMargin = (self.bounds.size.height - labelLineHeight - imageViewEdgeHeight) * 0.5; // // // imageView 和 titleLabel 中心的 Y 值 // CGFloat const centerOfImageView = verticalMargin + imageViewEdgeHeight * 0.5; // CGFloat const centerOfTitleLabel = imageViewEdgeHeight + verticalMargin * 2 + labelLineHeight * 0.5 + 5; // // //imageView position 位置 // self.imageView.bounds = CGRectMake(0, 0, imageViewEdgeWidth, imageViewEdgeHeight); // self.imageView.center = CGPointMake(centerOfView, centerOfImageView); // // //title position 位置 // self.titleLabel.bounds = CGRectMake(0, 0, self.bounds.size.width, labelLineHeight); // self.titleLabel.center = CGPointMake(centerOfView, centerOfTitleLabel); //} #pragma mark - #pragma mark - CYLPlusButtonSubclassing Methods /* * Create a custom UIButton with title and add it to the center of our tab bar * */ + (id)plusButton { CYLPlusButtonSubclass *button = [[CYLPlusButtonSubclass alloc] init]; UIImage *normalButtonImage = [UIImage imageNamed:@"icon_tabbar_plus"]; UIImage *hlightButtonImage = [UIImage imageNamed:@"icon_tabbar_plus"]; [button setImage:normalButtonImage forState:UIControlStateNormal]; [button setImage:[hlightButtonImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forState:UIControlStateHighlighted]; [button setImage:[hlightButtonImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forState:UIControlStateSelected]; [button setTintColor: [UIColor colorWithRed:0/255.0f green:255/255.0f blue:189/255.0f alpha:1]]; // UIImage *normalButtonBackImage = [UIImage imageNamed:@"videoback"]; // [button setBackgroundImage:normalButtonBackImage forState:UIControlStateNormal]; // [button setBackgroundImage:normalButtonBackImage forState:UIControlStateSelected]; button.imageEdgeInsets = UIEdgeInsetsMake(5, 0, -5, 0); button.titleLabel.font = [UIFont systemFontOfSize:9.5]; [button sizeToFit]; // or set frame in this way `button.frame = CGRectMake(0.0, 0.0, 250, 100);` button.frame = CGRectMake(0.0, 0.0, 55, 59); // if you use `+plusChildViewController` , do not addTarget to plusButton. [button addTarget:button action:@selector(clickPublish) forControlEvents:UIControlEventTouchUpInside]; return button; } /* * Create a custom UIButton without title and add it to the center of our tab bar * */ //+ (id)plusButton //{ // // UIImage *buttonImage = [UIImage imageNamed:@"hood.png"]; // UIImage *highlightImage = [UIImage imageNamed:@"hood-selected.png"]; // // CYLPlusButtonSubclass* button = [CYLPlusButtonSubclass buttonWithType:UIButtonTypeCustom]; // // button.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin; // button.frame = CGRectMake(0.0, 0.0, buttonImage.size.width, buttonImage.size.height); // [button setBackgroundImage:buttonImage forState:UIControlStateNormal]; // [button setBackgroundImage:highlightImage forState:UIControlStateHighlighted]; // [button addTarget:button action:@selector(clickPublish) forControlEvents:UIControlEventTouchUpInside]; // // return button; //} #pragma mark - #pragma mark - Event Response - (void)clickPublish { CYLTabBarController *tabBarController = [self cyl_tabBarController]; UIViewController *viewController = tabBarController.selectedViewController; #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:nil delegate:nil cancelButtonTitle:@"取消" destructiveButtonTitle:nil otherButtonTitles:@"拍照", @"从相册选取", @"淘宝一键转卖", nil]; [actionSheet showInView:viewController.view]; #pragma clang diagnostic pop } #pragma mark - UIActionSheetDelegate #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" - (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex { NSLog(@"buttonIndex = %@", @(buttonIndex)); } #pragma clang diagnostic pop #pragma mark - CYLPlusButtonSubclassing + (UIViewController *)plusChildViewController { UIViewController *plusChildViewController = [[UIViewController alloc] init]; plusChildViewController.view.backgroundColor = [UIColor redColor]; plusChildViewController.navigationItem.title = @"PlusChildViewController"; UIViewController *plusChildNavigationController = [[UINavigationController alloc] initWithRootViewController:plusChildViewController]; return plusChildNavigationController; } + (NSUInteger)indexOfPlusButtonInTabBar { return 2; } + (BOOL)shouldSelectPlusChildViewController { BOOL isSelected = CYLExternPlusButton.selected; if (isSelected) { // HDLLogDebug("🔴类名与方法名:%@(在第%@行),描述:%@", @(__PRETTY_FUNCTION__), @(__LINE__), @"PlusButton is selected"); } else { // HDLLogDebug("🔴类名与方法名:%@(在第%@行),描述:%@", @(__PRETTY_FUNCTION__), @(__LINE__), @"PlusButton is not selected"); } return YES; } + (CGFloat)multiplierOfTabBarHeight:(CGFloat)tabBarHeight { return 0.3; } + (CGFloat)constantOfPlusButtonCenterYOffsetForTabBarHeight:(CGFloat)tabBarHeight { return (CYL_IS_IPHONE_X ? - 6 : 4); } //+ (NSString *)tabBarContext { // return NSStringFromClass([self class]); //} @end ================================================ FILE: Example/Images.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "idiom" : "iphone", "size" : "20x20", "scale" : "2x" }, { "idiom" : "iphone", "size" : "20x20", "scale" : "3x" }, { "size" : "29x29", "idiom" : "iphone", "filename" : "Icon-Small.png", "scale" : "1x" }, { "size" : "29x29", "idiom" : "iphone", "filename" : "Icon-Small@2x.png", "scale" : "2x" }, { "size" : "29x29", "idiom" : "iphone", "filename" : "Icon-Small@3x.png", "scale" : "3x" }, { "size" : "40x40", "idiom" : "iphone", "filename" : "Icon-40@2x.png", "scale" : "2x" }, { "size" : "40x40", "idiom" : "iphone", "filename" : "Icon-40@3x.png", "scale" : "3x" }, { "size" : "57x57", "idiom" : "iphone", "filename" : "Icon.png", "scale" : "1x" }, { "size" : "57x57", "idiom" : "iphone", "filename" : "Icon@2x.png", "scale" : "2x" }, { "size" : "60x60", "idiom" : "iphone", "filename" : "Icon-60@2x.png", "scale" : "2x" }, { "size" : "60x60", "idiom" : "iphone", "filename" : "Icon-60@3x.png", "scale" : "3x" }, { "idiom" : "ipad", "size" : "20x20", "scale" : "1x" }, { "idiom" : "ipad", "size" : "20x20", "scale" : "2x" }, { "size" : "29x29", "idiom" : "ipad", "filename" : "Icon-Small.png", "scale" : "1x" }, { "size" : "29x29", "idiom" : "ipad", "filename" : "Icon-Small@2x.png", "scale" : "2x" }, { "size" : "40x40", "idiom" : "ipad", "filename" : "Icon-40.png", "scale" : "1x" }, { "size" : "40x40", "idiom" : "ipad", "filename" : "Icon-40@2x.png", "scale" : "2x" }, { "size" : "50x50", "idiom" : "ipad", "filename" : "Icon-Small-50.png", "scale" : "1x" }, { "size" : "50x50", "idiom" : "ipad", "filename" : "Icon-Small-50@2x.png", "scale" : "2x" }, { "size" : "72x72", "idiom" : "ipad", "filename" : "Icon-72.png", "scale" : "1x" }, { "size" : "72x72", "idiom" : "ipad", "filename" : "Icon-72@2x.png", "scale" : "2x" }, { "size" : "76x76", "idiom" : "ipad", "filename" : "Icon-76.png", "scale" : "1x" }, { "size" : "76x76", "idiom" : "ipad", "filename" : "Icon-76@2x.png", "scale" : "2x" }, { "size" : "83.5x83.5", "idiom" : "ipad", "filename" : "Icon-83.5@2x.png", "scale" : "2x" }, { "idiom" : "ios-marketing", "size" : "1024x1024", "scale" : "1x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/Images.xcassets/Contents.json ================================================ { "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Example/Images.xcassets/LaunchImage.launchimage/Contents.json ================================================ { "images" : [ { "filename" : "default-portrait-1792h@3x.png", "subtype" : "1792h", "minimum-system-version" : "12.0", "extent" : "full-screen", "orientation" : "portrait", "scale" : "2x", "idiom" : "iphone" }, { "orientation" : "landscape", "minimum-system-version" : "12.0", "subtype" : "1792h", "filename" : "default-landscape-1792h@3x.png", "idiom" : "iphone", "extent" : "full-screen", "scale" : "2x" }, { "scale" : "3x", "idiom" : "iphone", "subtype" : "2688h", "extent" : "full-screen", "filename" : "default-portrait-2688h@3x.png", "minimum-system-version" : "12.0", "orientation" : "portrait" }, { "extent" : "full-screen", "orientation" : "landscape", "filename" : "default-landscape-2688h@3x.png", "scale" : "3x", "subtype" : "2688h", "idiom" : "iphone", "minimum-system-version" : "12.0" }, { "orientation" : "portrait", "idiom" : "iphone", "extent" : "full-screen", "filename" : "default-portrait-2436h@3x.png", "minimum-system-version" : "11.0", "subtype" : "2436h", "scale" : "3x" }, { "scale" : "3x", "subtype" : "2436h", "orientation" : "landscape", "extent" : "full-screen", "idiom" : "iphone", "filename" : "default-landscape-2436h@3x.png", "minimum-system-version" : "11.0" }, { "extent" : "full-screen", "scale" : "1x", "filename" : "default.png", "idiom" : "iphone", "orientation" : "portrait" }, { "orientation" : "portrait", "extent" : "full-screen", "minimum-system-version" : "7.0", "filename" : "default@2x.png", "idiom" : "iphone", "scale" : "2x" }, { "subtype" : "retina4", "idiom" : "iphone", "scale" : "2x", "orientation" : "portrait", "extent" : "full-screen", "filename" : "default-568h@2x.png" }, { "orientation" : "portrait", "scale" : "2x", "subtype" : "retina4", "idiom" : "iphone", "minimum-system-version" : "7.0", "filename" : "default-568h@2x.png", "extent" : "full-screen" }, { "idiom" : "iphone", "filename" : "default@2x.png", "scale" : "2x", "extent" : "full-screen", "orientation" : "portrait" }, { "extent" : "to-status-bar", "idiom" : "ipad", "scale" : "1x", "orientation" : "portrait", "filename" : "default~ipad.png" }, { "filename" : "default~ipad@2x.png", "orientation" : "portrait", "extent" : "to-status-bar", "scale" : "2x", "idiom" : "ipad" }, { "idiom" : "ipad", "orientation" : "landscape", "extent" : "to-status-bar", "filename" : "default~ipad~landscape.png", "scale" : "1x" }, { "scale" : "2x", "extent" : "to-status-bar", "orientation" : "landscape", "filename" : "default~ipad~landscape@2x.png", "idiom" : "ipad" }, { "orientation" : "portrait", "filename" : "default~ipad~nostatusbar.png", "extent" : "full-screen", "minimum-system-version" : "7.0", "scale" : "1x", "idiom" : "ipad" }, { "filename" : "default~ipad~nostatusbar.png", "idiom" : "ipad", "extent" : "full-screen", "scale" : "1x", "orientation" : "portrait" }, { "minimum-system-version" : "7.0", "filename" : "default~ipad~nostatusbar@2x.png", "scale" : "2x", "extent" : "full-screen", "orientation" : "portrait", "idiom" : "ipad" }, { "idiom" : "ipad", "extent" : "full-screen", "scale" : "2x", "orientation" : "portrait", "filename" : "default~ipad~nostatusbar@2x.png" }, { "extent" : "full-screen", "minimum-system-version" : "7.0", "filename" : "default~ipad~landscape~nostatusbar.png", "scale" : "1x", "orientation" : "landscape", "idiom" : "ipad" }, { "idiom" : "ipad", "orientation" : "landscape", "extent" : "full-screen", "filename" : "default~ipad~landscape~nostatusbar.png", "scale" : "1x" }, { "extent" : "full-screen", "orientation" : "landscape", "idiom" : "ipad", "filename" : "default~ipad~landscape~nostatusbar@2x.png", "minimum-system-version" : "7.0", "scale" : "2x" }, { "filename" : "default~ipad~landscape~nostatusbar@2x.png", "idiom" : "ipad", "scale" : "2x", "extent" : "full-screen", "orientation" : "landscape" }, { "subtype" : "736h", "filename" : "default-portrait-736h@3x.png", "orientation" : "portrait", "idiom" : "iphone", "scale" : "3x", "minimum-system-version" : "8.0", "extent" : "full-screen" }, { "extent" : "full-screen", "scale" : "3x", "idiom" : "iphone", "subtype" : "736h", "minimum-system-version" : "8.0", "orientation" : "landscape", "filename" : "default-landscape-736h@3x.png" }, { "orientation" : "portrait", "scale" : "2x", "minimum-system-version" : "8.0", "extent" : "full-screen", "filename" : "default-667h@2x.png", "subtype" : "667h", "idiom" : "iphone" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Example/Images.xcassets/NavBar/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/Images.xcassets/NavBar/home_bar_scan.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "home_bar_scan@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x", "filename" : "home_bar_scan@3x.png" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/Images.xcassets/NavBar/home_title_slogan.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "home_title_slogan@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x", "filename" : "home_title_slogan@3x.png" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/Images.xcassets/NavBar/icon_search.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "icon_search@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x", "filename" : "icon_search@3x.png" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/Images.xcassets/TabBarIcon/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/Images.xcassets/TabBarIcon/TabBar_Bg_Shadow.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "TabBar_Bg_Shadow@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/Images.xcassets/TabBarIcon/account/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/Images.xcassets/TabBarIcon/account/account_highlight.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "account_highlight.png", "scale" : "1x" }, { "idiom" : "universal", "filename" : "account_highlight@2x.png", "scale" : "2x" }, { "idiom" : "universal", "filename" : "account_highlight@3x.png", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/Images.xcassets/TabBarIcon/account/account_normal.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "account_normal.png", "scale" : "1x" }, { "idiom" : "universal", "filename" : "account_normal@2x.png", "scale" : "2x" }, { "idiom" : "universal", "filename" : "account_normal@3x.png", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/Images.xcassets/TabBarIcon/fishpond/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/Images.xcassets/TabBarIcon/fishpond/fishpond_highlight.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "fishpond_highlight.png", "scale" : "1x" }, { "idiom" : "universal", "filename" : "fishpond_highlight@2x.png", "scale" : "2x" }, { "idiom" : "universal", "filename" : "fishpond_highlight@3x.png", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/Images.xcassets/TabBarIcon/fishpond/fishpond_normal.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "fishpond_normal.png", "scale" : "1x" }, { "idiom" : "universal", "filename" : "fishpond_normal@2x.png", "scale" : "2x" }, { "idiom" : "universal", "filename" : "fishpond_normal@3x.png", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/Images.xcassets/TabBarIcon/home/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/Images.xcassets/TabBarIcon/home/home_highlight.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "home_highlight.png", "scale" : "1x" }, { "idiom" : "universal", "filename" : "home_highlight@2x.png", "scale" : "2x" }, { "idiom" : "universal", "filename" : "home_highlight@3x.png", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/Images.xcassets/TabBarIcon/home/home_normal.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "home_normal.png", "scale" : "1x" }, { "idiom" : "universal", "filename" : "home_normal@2x.png", "scale" : "2x" }, { "idiom" : "universal", "filename" : "home_normal@3x.png", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/Images.xcassets/TabBarIcon/home_select_cover.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "home_select_cover@2x.png", "scale" : "2x" }, { "idiom" : "universal", "filename" : "home_select_cover@3x.png", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/Images.xcassets/TabBarIcon/lottie_placeholder/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/Images.xcassets/TabBarIcon/lottie_placeholder/gray_tabbar_home_animation_lottie_placeholder.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "gray_tabbar_home_animation_lottie_placeholder@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/Images.xcassets/TabBarIcon/lottie_placeholder/gray_tabbar_me_animation_lottie_placeholder.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "gray_tabbar_me_animation_lottie_placeholder@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/Images.xcassets/TabBarIcon/lottie_placeholder/gray_tabbar_message_animation_lottie_placeholder.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "gray_tabbar_message_animation_lottie_placeholder@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/Images.xcassets/TabBarIcon/message/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/Images.xcassets/TabBarIcon/message/message_highlight.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "message_highlight.png", "scale" : "1x" }, { "idiom" : "universal", "filename" : "message_highlight@2x.png", "scale" : "2x" }, { "idiom" : "universal", "filename" : "message_highlight@3x.png", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/Images.xcassets/TabBarIcon/message/message_normal.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "message_normal.png", "scale" : "1x" }, { "idiom" : "universal", "filename" : "message_normal@2x.png", "scale" : "2x" }, { "idiom" : "universal", "filename" : "message_normal@3x.png", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/Images.xcassets/TabBarIcon/post/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/Images.xcassets/TabBarIcon/post/post_highlight.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "post_highlight@2x.png", "scale" : "2x" }, { "idiom" : "universal", "filename" : "post_highlight@3x.png", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/Images.xcassets/TabBarIcon/post/post_normal.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "post_normal@2x.png", "scale" : "2x" }, { "idiom" : "universal", "filename" : "post_normal@3x.png", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/Images.xcassets/TabBarIcon/tabbarBg.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "tabbarBg@2x.png", "scale" : "2x" }, { "idiom" : "universal", "filename" : "tabbarBg@3x.png", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/Images.xcassets/TabBarIcon/tabbar_background.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "tabbar_background@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/Images.xcassets/TabBarIcon/tapbar_top_line.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "tapbar_top_line@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" }, "properties" : { "template-rendering-intent" : "original" } } ================================================ FILE: Example/Images.xcassets/TabBarIcon/videoback.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "videoback@2x.png", "scale" : "2x" }, { "idiom" : "universal", "filename" : "videoback@3x.png", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/Images.xcassets/home-float-icon.imageset/Contents.json ================================================ { "images" : [ { "filename" : "home-float-icon.jpg", "idiom" : "universal", "scale" : "1x" }, { "filename" : "home-float-icon@2x.jpg", "idiom" : "universal", "scale" : "2x" }, { "filename" : "home-float-icon@3x.jpg", "idiom" : "universal", "scale" : "3x" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Example/Images.xcassets/icon_tabbar_plus.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "filename" : "icon_tabbar_plus@2x.png", "idiom" : "universal", "scale" : "2x" }, { "filename" : "icon_tabbar_plus@3x.png", "idiom" : "universal", "scale" : "3x" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Example/Images.xcassets/navigationbar_background_tall.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x", "filename" : "navigationbar_background_tall@2x.png" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 LSRequiresIPhoneOS UIRequiredDeviceCapabilities armv7 UIRequiresFullScreen UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight ================================================ FILE: Example/MainTabBarController.h ================================================ // // MainTabBarController.h // CYLTabBarController // // v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 15/11/3. // Copyright © 2015年 https://github.com/ChenYilong .All rights reserved. // #import #if __has_include() #import #else #import "CYLTabBarController.h" #endif @interface MainTabBarController : CYLTabBarController - (instancetype)initWithContext:(NSString *)context; @end ================================================ FILE: Example/MainTabBarController.m ================================================ // // MainTabBarController.m // CYLTabBarController // // v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/20/15. // Copyright © 2015 https://github.com/ChenYilong . All rights reserved. // #import "MainTabBarController.h" #import static CGFloat const CYLTabBarControllerHeight = 40.f; //View Controllers #import "CYLHomeViewController.h" #import "CYLMessageViewController.h" #import "CYLMineViewController.h" #import "CYLSameCityViewController.h" #define RANDOM_COLOR [UIColor colorWithHue: (arc4random() % 256 / 256.0) saturation:((arc4random()% 128 / 256.0 ) + 0.5) brightness:(( arc4random() % 128 / 256.0 ) + 0.5) alpha:1] @interface MainTabBarController () @property (nonatomic, weak) UIButton *selectedCover; @end @implementation MainTabBarController - (instancetype)initWithContext:(NSString *)context { /** * 以下两行代码目的在于手动设置让TabBarItem只显示图标,不显示文字,并让图标垂直居中。 * 等 效于在 `-tabBarItemsAttributesForController` 方法中不传 `CYLTabBarItemTitle` 字段。 * 更推荐后一种做法。 */ UIEdgeInsets imageInsets = UIEdgeInsetsZero;//UIEdgeInsetsMake(4.5, 0, -4.5, 0); UIOffset titlePositionAdjustment = UIOffsetMake(0, -3.5); if (self = [super initWithViewControllers:[self viewControllersForTabBar] tabBarItemsAttributes:[self tabBarItemsAttributesForTabBar] imageInsets:imageInsets titlePositionAdjustment:titlePositionAdjustment context:context ]) { [self customizeTabBarAppearanceWithTitlePositionAdjustment:titlePositionAdjustment]; self.delegate = self; self.navigationController.navigationBar.hidden = YES; } return self; } - (void)viewDidLoad { [super viewDidLoad]; [[UIApplication sharedApplication] setApplicationSupportsShakeToEdit:YES]; [self becomeFirstResponder]; [self customizeInterface]; } - (NSArray *)viewControllersForTabBar { CYLHomeViewController *firstViewController = [[CYLHomeViewController alloc] init]; UIViewController *firstNavigationController = [[CYLBaseNavigationController alloc] initWithRootViewController:firstViewController]; [firstViewController cyl_setHideNavigationBarSeparator:YES]; // [firstViewController cyl_setNavigationBarHidden:YES]; CYLSameCityViewController *secondViewController = [[CYLSameCityViewController alloc] init]; UIViewController *secondNavigationController = [[CYLBaseNavigationController alloc] initWithRootViewController:secondViewController]; [secondViewController cyl_setHideNavigationBarSeparator:YES]; // [secondViewController cyl_setNavigationBarHidden:YES]; CYLMessageViewController *thirdViewController = [[CYLMessageViewController alloc] init]; UIViewController *thirdNavigationController = [[CYLBaseNavigationController alloc] initWithRootViewController:thirdViewController]; [thirdViewController cyl_setHideNavigationBarSeparator:YES]; CYLMineViewController *fourthViewController = [[CYLMineViewController alloc] init]; UIViewController *fourthNavigationController = [[CYLBaseNavigationController alloc] initWithRootViewController:fourthViewController]; [fourthNavigationController cyl_setHideNavigationBarSeparator:YES]; NSArray *viewControllers = @[ firstNavigationController, secondNavigationController, thirdNavigationController, fourthNavigationController ]; return viewControllers; } - (NSArray *)tabBarItemsAttributesForTabBar { // lottie动画的json文件来自于NorthSea, respect! CGFloat firstXOffset = -12/2; NSDictionary *firstTabBarItemsAttributes = @{ CYLTabBarItemTitle : @"首页", CYLTabBarItemImage : [[UIImage imageNamed:@"home_normal"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal], /* NSString and UIImage are supported*/ CYLTabBarItemSelectedImage : @"home_highlight", /* NSString and UIImage are supported*/ CYLTabBarItemTitlePositionAdjustment: [NSValue valueWithUIOffset:UIOffsetMake(firstXOffset, -3.5)], //第一位 右大,下大 CYLTabBarLottieURL : [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"green_lottie_tab_home" ofType:@"json"]], // CYLTabBarLottieSize: [NSValue valueWithCGSize:CGSizeMake(22, 22)] }; CGFloat secondXOffset = (-25+2)/2; NSDictionary *secondTabBarItemsAttributes = @{ CYLTabBarItemTitle : @"鱼塘", CYLTabBarItemImage : [[UIImage imageNamed:@"fishpond_normal"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal], CYLTabBarItemSelectedImage : @"fishpond_highlight", CYLTabBarItemTitlePositionAdjustment: [NSValue valueWithUIOffset:UIOffsetMake(secondXOffset, -3.5)], CYLTabBarLottieURL : [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"green_lottie_tab_discover" ofType:@"json"]], // CYLTabBarLottieSize: [NSValue valueWithCGSize:CGSizeMake(33, 33)] }; NSDictionary *thirdTabBarItemsAttributes = @{ CYLTabBarItemTitle : @"消息", CYLTabBarItemImage : [[UIImage imageNamed:@"message_normal"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal], CYLTabBarItemSelectedImage : @"message_highlight", CYLTabBarItemTitlePositionAdjustment: [NSValue valueWithUIOffset:UIOffsetMake(-secondXOffset, -3.5)], CYLTabBarLottieURL : [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"green_lottie_tab_news" ofType:@"json"]], // CYLTabBarLottieSize: [NSValue valueWithCGSize:CGSizeMake(44, 44)] }; NSDictionary *fourthTabBarItemsAttributes = @{ CYLTabBarItemTitle : @"我的", CYLTabBarItemImage : [[UIImage imageNamed:@"account_normal"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal], CYLTabBarItemSelectedImage : @"account_highlight", CYLTabBarItemTitlePositionAdjustment: [NSValue valueWithUIOffset:UIOffsetMake(-firstXOffset, -3.5)], CYLTabBarLottieURL : [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"green_lottie_tab_mine" ofType:@"json"]], // CYLTabBarLottieSize: [NSValue valueWithCGSize:CGSizeMake(22, 22)] }; NSArray *tabBarItemsAttributes = @[ firstTabBarItemsAttributes, secondTabBarItemsAttributes, thirdTabBarItemsAttributes, fourthTabBarItemsAttributes ]; return tabBarItemsAttributes; } /** * 更多TabBar自定义设置:比如:tabBarItem 的选中和不选中文字和背景图片属性、tabbar 背景图片属性等等 */ - (void)customizeTabBarAppearanceWithTitlePositionAdjustment:(UIOffset)titlePositionAdjustment { // Customize UITabBar height // 自定义 TabBar 高度 // tabBarController.tabBarHeight = CYL_IS_IPHONE_X ? 65 : 40; [self rootWindow].backgroundColor = [UIColor cyl_systemBackgroundColor]; // set the text color for unselected state // 普通状态下的文字属性 NSMutableDictionary *normalAttrs = [NSMutableDictionary dictionary]; normalAttrs[NSForegroundColorAttributeName] = [UIColor cyl_systemGrayColor]; //normalAttrs[NSFontAttributeName] = [UIFont systemFontOfSize:10]; // set the text color for selected state // 选中状态下的文字属性 NSMutableDictionary *selectedAttrs = [NSMutableDictionary dictionary]; selectedAttrs[NSForegroundColorAttributeName] = [UIColor cyl_labelColor]; //selectedAttrs[NSFontAttributeName] = [UIFont systemFontOfSize:10]; // Set the dark color to selected tab (the dimmed background) // TabBarItem选中后的背景颜色 // [self customizeTabBarSelectionIndicatorImage]; // update TabBar when TabBarItem width did update // If your app need support UIDeviceOrientationLandscapeLeft or UIDeviceOrientationLandscapeRight, // remove the comment '//' // 如果你的App需要支持横竖屏,请使用该方法移除注释 '//' // [self updateTabBarCustomizationWhenTabBarItemWidthDidUpdate]; // set background color // 设置 TabBar 背景 // 半透明 // [UITabBar appearance].translucent = YES; // [UITabBar appearance].barTintColor = [UIColor cyl_systemBackgroundColor]; // [[UITabBar appearance] setBackgroundColor:[UIColor cyl_systemBackgroundColor]]; // [[UITabBar appearance] setBackgroundImage:[[self class] imageWithColor:[UIColor whiteColor] size:CGSizeMake([UIScreen mainScreen].bounds.size.width, tabBarController.tabBarHeight ?: (CYL_IS_IPHONE_X ? 65 : 40))]]; // [[UITabBar appearance] setUnselectedItemTintColor:[UIColor systemGrayColor]]; //Three way to deal with shadow 三种阴影处理方式: // NO.3, without shadow : use -[[CYLTabBarController hideTabBarShadowImageView] in CYLMainRootViewController.m // NO.2,using layer to add shadow. // CYLTabBarController *tabBarController = [self cyl_tabBarController]; // tabBarController.tabBar.layer.shadowColor = [UIColor blackColor].CGColor; // tabBarController.tabBar.layer.shadowRadius = 15.0; // tabBarController.tabBar.layer.shadowOpacity = 1; // tabBarController.tabBar.layer.shadowOffset = CGSizeMake(0, 3); // tabBarController.tabBar.layer.masksToBounds = NO; // tabBarController.tabBar.clipsToBounds = NO; // NO.1,using Image note:recommended.推荐方式 // set the bar shadow image // without shadow : use -[[CYLTabBarController hideTabBarShadowImageView] in CYLMainRootViewController.m if (@available(iOS 13.0, *)) { UITabBarItemAppearance *inlineLayoutAppearance = [[UITabBarItemAppearance alloc] init]; // fix https://github.com/ChenYilong/CYLTabBarController/issues/456 inlineLayoutAppearance.normal.titlePositionAdjustment = titlePositionAdjustment; // set the text Attributes // 设置文字属性 [inlineLayoutAppearance.normal setTitleTextAttributes:normalAttrs]; [inlineLayoutAppearance.selected setTitleTextAttributes:selectedAttrs]; UITabBarAppearance *standardAppearance = [[UITabBarAppearance alloc] init]; standardAppearance.stackedLayoutAppearance = inlineLayoutAppearance; standardAppearance.backgroundColor = [UIColor cyl_systemBackgroundColor]; //shadowColor和shadowImage均可以自定义颜色, shadowColor默认高度为1, shadowImage可以自定义高度. standardAppearance.shadowColor = [UIColor cyl_systemGreenColor]; // standardAppearance.shadowImage = [[self class] imageWithColor:[UIColor cyl_systemGreenColor] size:CGSizeMake([UIScreen mainScreen].bounds.size.width, 1)]; self.tabBar.standardAppearance = standardAppearance; } else { // Override point for customization after application launch. // set the text Attributes // 设置文字属性 UITabBarItem *tabBar = [UITabBarItem appearance]; [tabBar setTitleTextAttributes:normalAttrs forState:UIControlStateNormal]; [tabBar setTitleTextAttributes:selectedAttrs forState:UIControlStateSelected]; // This shadow image attribute is ignored if the tab bar does not also have a custom background image.So at least set somthing. [[UITabBar appearance] setBackgroundImage:[[UIImage alloc] init]]; [[UITabBar appearance] setShadowImage:[[self class] imageWithColor:[UIColor cyl_systemGreenColor] size:CGSizeMake([UIScreen mainScreen].bounds.size.width, 1)]]; } } - (void)updateTabBarCustomizationWhenTabBarItemWidthDidUpdate { void (^deviceOrientationDidChangeBlock)(NSNotification *) = ^(NSNotification *notification) { UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation]; if ((orientation == UIDeviceOrientationLandscapeLeft) || (orientation == UIDeviceOrientationLandscapeRight)) { NSLog(@"Landscape Left or Right !"); } else if (orientation == UIDeviceOrientationPortrait) { NSLog(@"Landscape portrait!"); } [self customizeTabBarSelectionIndicatorImage]; }; [[NSNotificationCenter defaultCenter] addObserverForName:CYLTabBarItemWidthDidChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:deviceOrientationDidChangeBlock]; } - (void)customizeTabBarSelectionIndicatorImage { ///Get initialized TabBar Height if exists, otherwise get Default TabBar Height. CGFloat tabBarHeight = CYLTabBarControllerHeight; CGSize selectionIndicatorImageSize = CGSizeMake(CYLTabBarItemWidth, tabBarHeight); //Get initialized TabBar if exists. UITabBar *tabBar = self.tabBar ?: [UITabBar appearance]; [tabBar setSelectionIndicatorImage: [[self class] imageWithColor:[UIColor whiteColor] size:selectionIndicatorImageSize]]; } + (UIImage *)scaleImage:(UIImage *)image { CGFloat halfWidth = image.size.width/2; CGFloat halfHeight = image.size.height/2; UIImage *secondStrechImage = [image resizableImageWithCapInsets:UIEdgeInsetsMake(halfHeight, halfWidth, halfHeight, halfWidth) resizingMode:UIImageResizingModeStretch]; return secondStrechImage; } + (UIImage *)imageWithColor:(UIColor *)color size:(CGSize)size { if (!color || size.width <= 0 || size.height <= 0) return nil; CGRect rect = CGRectMake(0.0f, 0.0f, size.width + 1, size.height); UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0); CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetFillColorWithColor(context, color.CGColor); CGContextFillRect(context, rect); UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return image; } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; NSLog(@"🔴类名与方法名:%@(在第%@行),描述:%@", @(__PRETTY_FUNCTION__), @(__LINE__), @""); } - (UIButton *)selectedCover { if (_selectedCover) { return _selectedCover; } UIButton *selectedCover = [UIButton buttonWithType:UIButtonTypeCustom]; UIImage *image = [UIImage imageNamed:@"home_select_cover"]; [selectedCover setImage:image forState:UIControlStateNormal]; selectedCover.frame = ({ CGRect frame = selectedCover.frame; frame.size = CGSizeMake(image.size.width, image.size.height); frame; }); selectedCover.translatesAutoresizingMaskIntoConstraints = NO; // selectedCover.userInteractionEnabled = false; _selectedCover = selectedCover; return _selectedCover; } - (void)setSelectedCoverShow:(BOOL)show { UIControl *selectedTabButton = [self.viewControllers[0].tabBarItem cyl_tabButton]; [selectedTabButton cyl_replaceTabButtonWithNewView:self.selectedCover show:show]; //fix: #480 //selectedTabButton.cyl_tabImageView.hidden = YES; if (show) { [self addOnceScaleAnimationOnView:self.selectedCover]; } } //缩放动画 - (void)addOnceScaleAnimationOnView:(UIView *)animationView { //需要实现的帧动画,这里根据需求自定义 CAKeyframeAnimation *animation = [CAKeyframeAnimation animation]; animation.keyPath = @"transform.scale"; animation.values = @[@0.5, @1.0]; animation.duration = 0.1; // animation.repeatCount = repeatCount; animation.calculationMode = kCAAnimationCubic; [animationView.layer addAnimation:animation forKey:nil]; } - (void)traitCollectionDidChange:(nullable UITraitCollection *)previousTraitCollection { [super traitCollectionDidChange:previousTraitCollection]; #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 if (@available(iOS 13.0, *)) { #if __has_include() UIUserInterfaceStyle currentUserInterfaceStyle = [UITraitCollection currentTraitCollection].userInterfaceStyle; if (currentUserInterfaceStyle == previousTraitCollection.userInterfaceStyle) { return; } #else #endif //TODO: [[UIViewController cyl_topmostViewController].navigationController.navigationBar setBarTintColor:[UIColor cyl_systemBackgroundColor]]; } #endif } - (void)customizeInterface { //设置导航栏 // [self setUpNavigationBarAppearance]; // [self hideTabBarShadowImageView]; //#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 // if (@available(iOS 13.0, *)) { // tabBarController.overrideUserInterfaceStyle = UIUserInterfaceStyleLight; // } //#endif //添加小红点 //添加提示动画,引导用户点击 [self setViewDidLayoutSubViewsBlockInvokeOnce:YES block:^(CYLTabBarController *tabBarController) { NSUInteger delaySeconds = 1.5; dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delaySeconds * NSEC_PER_SEC)); dispatch_after(when, dispatch_get_main_queue(), ^{ @try { UIViewController *viewController0 = tabBarController.viewControllers[0]; // UIControl *tab0 = viewController0.cyl_tabButton; // [tab0 cyl_showBadge]; [viewController0 cyl_setBadgeBackgroundColor:RANDOM_COLOR]; [viewController0 cyl_setBadgeCenterOffset:CGPointMake(-5, 3)]; // [viewController0 cyl_setBadgeRadius:11/2]; //以上对Badge的参数设置,需要在 cyl_showBadgeValue 调用之前执行。 [viewController0 cyl_showBadge]; // [tabBarController.viewControllers[1] cyl_setBadgeMargin:5]; // [tabBarController.viewControllers[2] cyl_setBadgeMargin:5]; // [tabBarController.viewControllers[3] cyl_setBadgeMargin:5]; // [tabBarController.viewControllers[4] cyl_setBadgeMargin:5]; [tabBarController.viewControllers[1] cyl_setBadgeBackgroundColor:RANDOM_COLOR]; [tabBarController.viewControllers[1] cyl_showBadgeValue:@"" animationType:CYLBadgeAnimationTypeScale]; [tabBarController.viewControllers[2] cyl_showBadgeValue:@"" animationType:CYLBadgeAnimationTypeShake]; NSString *testBadgeString = @"100"; // [tabBarController.viewControllers[3] cyl_setBadgeMargin:-5]; // CGSize size = [testBadgeString sizeWithAttributes: // @{NSFontAttributeName: // tabBarController.viewControllers[3].cyl_badgeFont}]; // float labelHeight = ceilf(size.height); // [tabBarController.viewControllers[3] cyl_setBadgeCornerRadius:(labelHeight+ tabBarController.viewControllers[3].cyl_badgeMargin)/2]; [tabBarController.viewControllers[3] cyl_showBadgeValue:testBadgeString animationType:CYLBadgeAnimationTypeBounce]; [tabBarController.viewControllers[4] cyl_showBadgeValue:@"NEW" animationType:CYLBadgeAnimationTypeBreathe]; } @catch (NSException *exception) {} //添加仿淘宝tabbar,第一个tab选中后有图标覆盖 if (self.selectedIndex != 0) { return; } // tabBarController.selectedIndex = 1; }); }]; } #pragma mark - delegate - (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController { BOOL should = YES; [self updateSelectionStatusIfNeededForTabBarController:tabBarController shouldSelectViewController:viewController shouldSelect:should]; UIControl *selectedTabButton = [viewController.tabBarItem cyl_tabButton]; if (selectedTabButton.selected) { @try { [[[self class] cyl_topmostViewController] performSelector:@selector(refresh)]; } @catch (NSException *exception) { NSLog(@"🔴类名与方法名:%@(在第%@行),描述:%@", @(__PRETTY_FUNCTION__), @(__LINE__), exception.reason); } } return should; } - (void)tabBarController:(UITabBarController *)tabBarController didSelectControl:(UIControl *)control { UIView *animationView; // NSLog(@"🔴类名与方法名:%@(在第%@行),描述:control : %@ ,tabBarChildViewControllerIndex: %@, tabBarItemVisibleIndex : %@", @(__PRETTY_FUNCTION__), @(__LINE__), control, @(control.cyl_tabBarChildViewControllerIndex), @(control.cyl_tabBarItemVisibleIndex)); if ([control cyl_isTabButton]) { //更改红标状态 if ([self.selectedViewController cyl_isShowBadge]) { [self.selectedViewController cyl_clearBadge]; } else { [self.selectedViewController cyl_showBadge]; } animationView = [control cyl_tabImageView]; } UIButton *button = CYLExternPlusButton; BOOL isPlusButton = [control cyl_isPlusButton]; // 即使 PlusButton 也添加了点击事件,点击 PlusButton 后也会触发该代理方法。 if (isPlusButton) { animationView = button.imageView; } [self addScaleAnimationOnView:animationView repeatCount:1]; // [self addRotateAnimationOnView:animationView];//暂时不推荐用旋转方式,badge也会旋转。 //添加仿淘宝tabbar,第一个tab选中后有图标覆盖 if ([control cyl_isTabButton]|| [control cyl_isPlusButton]) { // BOOL shouldSelectedCoverShow = (self.selectedIndex == 0); // [self setSelectedCoverShow:shouldSelectedCoverShow]; } } //缩放动画 - (void)addScaleAnimationOnView:(UIView *)animationView repeatCount:(float)repeatCount { //需要实现的帧动画,这里根据需求自定义 CAKeyframeAnimation *animation = [CAKeyframeAnimation animation]; animation.keyPath = @"transform.scale"; animation.values = @[@1.0,@1.3,@0.9,@1.15,@0.95,@1.02,@1.0]; animation.duration = 1; animation.repeatCount = repeatCount; animation.calculationMode = kCAAnimationCubic; [animationView.layer addAnimation:animation forKey:nil]; } //旋转动画 - (void)addRotateAnimationOnView:(UIView *)animationView { // 针对旋转动画,需要将旋转轴向屏幕外侧平移,最大图片宽度的一半 // 否则背景与按钮图片处于同一层次,当按钮图片旋转时,转轴就在背景图上,动画时会有一部分在背景图之下。 // 动画结束后复位 animationView.layer.zPosition = 65.f / 2; [UIView animateWithDuration:0.32 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{ animationView.layer.transform = CATransform3DMakeRotation(M_PI, 0, 1, 0); } completion:nil]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [UIView animateWithDuration:0.70 delay:0 usingSpringWithDamping:1 initialSpringVelocity:0.2 options:UIViewAnimationOptionCurveEaseOut animations:^{ animationView.layer.transform = CATransform3DMakeRotation(2 * M_PI, 0, 1, 0); } completion:nil]; }); } @end ================================================ FILE: Example/main.m ================================================ // // main.m // CYLTabBarController // // v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 15/10/25. // Copyright (c) 2018年 https://github.com/ChenYilong .All rights reserved. // #import #import "AppDelegate.h" int main(int argc, char * argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } } ================================================ FILE: Example-Swift/AppDelegate.swift ================================================ // // AppDelegate.swift // // v1.16.0 Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/20/15. // Copyright © 2018 https://github.com/ChenYilong . All rights reserved. // import CYLTabBarController import UIKit @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate, UITabBarControllerDelegate { var window: UIWindow? func application(_: UIApplication, didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { CYLPlusButtonSubclass.register() let mainTabBarVc = MainTabBarController(viewControllers: viewControllers(), tabBarItemsAttributes: tabBarItemsAttributesForController()) window = UIWindow() window?.frame = UIScreen.main.bounds window?.rootViewController = mainTabBarVc mainTabBarVc?.hideTabBadgeBackgroundSeparator() mainTabBarVc.hideTabBarShadowImageView(); window?.makeKeyAndVisible() UITabBar.appearance().backgroundColor = UIColor.white return true } func viewControllers() -> [UINavigationController] { let home = UINavigationController(rootViewController: HomeViewController()) let connection = UINavigationController(rootViewController: ConnectionViewController()) let message = UINavigationController(rootViewController: MessageViewController()) let personal = UINavigationController(rootViewController: PersonalViewController()) let viewControllers = [home, connection, message, personal] return viewControllers } func tabBarItemsAttributesForController() -> [[String: String]] { let tabBarItemOne = [CYLTabBarItemTitle: "首页", CYLTabBarItemImage: "home_normal", CYLTabBarItemSelectedImage: "home_highlight"] let tabBarItemTwo = [CYLTabBarItemTitle: "同城", CYLTabBarItemImage: "mycity_normal", CYLTabBarItemSelectedImage: "mycity_highlight"] let tabBarItemThree = [CYLTabBarItemTitle: "消息", CYLTabBarItemImage: "message_normal", CYLTabBarItemSelectedImage: "message_highlight"] let tabBarItemFour = [CYLTabBarItemTitle: "我的", CYLTabBarItemImage: "account_normal", CYLTabBarItemSelectedImage: "account_highlight"] let tabBarItemsAttributes = [tabBarItemOne, tabBarItemTwo, tabBarItemThree, tabBarItemFour] return tabBarItemsAttributes } } ================================================ FILE: Example-Swift/CYLTabbarController-Swift.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 48; objects = { /* Begin PBXBuildFile section */ 9AF595E221C8E63C00C6AF2B /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AF595DF21C8E63C00C6AF2B /* AppDelegate.swift */; }; 9AF595E321C8E63C00C6AF2B /* MainTabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AF595E021C8E63C00C6AF2B /* MainTabBarController.swift */; }; 9AF5960E21C8E7B100C6AF2B /* CYLPlusButtonSubclass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AF595E721C8E7B000C6AF2B /* CYLPlusButtonSubclass.swift */; }; 9AF5960F21C8E7B100C6AF2B /* PersonalViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AF595EC21C8E7B000C6AF2B /* PersonalViewController.swift */; }; 9AF5961021C8E7B100C6AF2B /* HomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AF595F221C8E7B000C6AF2B /* HomeViewController.swift */; }; 9AF5961121C8E7B100C6AF2B /* ConnectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AF595F821C8E7B000C6AF2B /* ConnectionViewController.swift */; }; 9AF5961221C8E7B100C6AF2B /* MessageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AF595FE21C8E7B000C6AF2B /* MessageViewController.swift */; }; 9AF5961321C8E7B100C6AF2B /* PublishViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AF5960421C8E7B000C6AF2B /* PublishViewController.swift */; }; 9AF5961421C8E7B100C6AF2B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9AF5960821C8E7B100C6AF2B /* Assets.xcassets */; }; 9AF5961521C8E7B100C6AF2B /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9AF5960921C8E7B100C6AF2B /* LaunchScreen.storyboard */; }; 9AF5961621C8E7B100C6AF2B /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9AF5960B21C8E7B100C6AF2B /* Main.storyboard */; }; C0196AB673A3C11A8689ED66 /* Pods_CYLTabBarController_Swift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9DEC604443F0BED5845C1590 /* Pods_CYLTabBarController_Swift.framework */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 2CDA77BCC28E878CAB5EFD15 /* Pods-CYLTabBarController-Swift.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CYLTabBarController-Swift.release.xcconfig"; path = "Pods/Target Support Files/Pods-CYLTabBarController-Swift/Pods-CYLTabBarController-Swift.release.xcconfig"; sourceTree = ""; }; 922DCEDD1FF63399005C89BE /* CYLTabBarController-Swift.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "CYLTabBarController-Swift.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 9AF595DF21C8E63C00C6AF2B /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 9AF595E021C8E63C00C6AF2B /* MainTabBarController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainTabBarController.swift; sourceTree = ""; }; 9AF595E721C8E7B000C6AF2B /* CYLPlusButtonSubclass.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CYLPlusButtonSubclass.swift; sourceTree = ""; }; 9AF595EC21C8E7B000C6AF2B /* PersonalViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PersonalViewController.swift; sourceTree = ""; }; 9AF595F221C8E7B000C6AF2B /* HomeViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomeViewController.swift; sourceTree = ""; }; 9AF595F821C8E7B000C6AF2B /* ConnectionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConnectionViewController.swift; sourceTree = ""; }; 9AF595FE21C8E7B000C6AF2B /* MessageViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageViewController.swift; sourceTree = ""; }; 9AF5960421C8E7B000C6AF2B /* PublishViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PublishViewController.swift; sourceTree = ""; }; 9AF5960821C8E7B100C6AF2B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 9AF5960A21C8E7B100C6AF2B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 9AF5960C21C8E7B100C6AF2B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 9AF5960D21C8E7B100C6AF2B /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 9DEC604443F0BED5845C1590 /* Pods_CYLTabBarController_Swift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_CYLTabBarController_Swift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; C7C15F27AFB129417A291CF9 /* Pods-CYLTabBarController-Swift.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CYLTabBarController-Swift.debug.xcconfig"; path = "Pods/Target Support Files/Pods-CYLTabBarController-Swift/Pods-CYLTabBarController-Swift.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 922DCEDA1FF63399005C89BE /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( C0196AB673A3C11A8689ED66 /* Pods_CYLTabBarController_Swift.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 6961000247EFFCCDCECEE099 /* Frameworks */ = { isa = PBXGroup; children = ( 9DEC604443F0BED5845C1590 /* Pods_CYLTabBarController_Swift.framework */, ); name = Frameworks; sourceTree = ""; }; 922DCED41FF63399005C89BE = { isa = PBXGroup; children = ( 9AF595DF21C8E63C00C6AF2B /* AppDelegate.swift */, 9AF595E021C8E63C00C6AF2B /* MainTabBarController.swift */, 9AF595E821C8E7B000C6AF2B /* Module */, 9AF595E521C8E7B000C6AF2B /* Model */, 9AF595E621C8E7B000C6AF2B /* View */, 9AF5961821C8E8B700C6AF2B /* Controller */, 9AF5960721C8E7B100C6AF2B /* Other */, 922DCEDE1FF63399005C89BE /* Products */, 9E8F1952DFE997BA5D0E1F59 /* Pods */, 6961000247EFFCCDCECEE099 /* Frameworks */, ); sourceTree = ""; }; 922DCEDE1FF63399005C89BE /* Products */ = { isa = PBXGroup; children = ( 922DCEDD1FF63399005C89BE /* CYLTabBarController-Swift.app */, ); name = Products; sourceTree = ""; }; 9AF595E521C8E7B000C6AF2B /* Model */ = { isa = PBXGroup; children = ( ); path = Model; sourceTree = ""; }; 9AF595E621C8E7B000C6AF2B /* View */ = { isa = PBXGroup; children = ( 9AF595E721C8E7B000C6AF2B /* CYLPlusButtonSubclass.swift */, ); path = View; sourceTree = ""; }; 9AF595E821C8E7B000C6AF2B /* Module */ = { isa = PBXGroup; children = ( 9AF595E921C8E7B000C6AF2B /* Personal */, 9AF595EF21C8E7B000C6AF2B /* Home */, 9AF595F521C8E7B000C6AF2B /* Connection */, 9AF595FB21C8E7B000C6AF2B /* Message */, 9AF5960121C8E7B000C6AF2B /* Publish */, 9AF5961921C8E8D600C6AF2B /* Other */, ); path = Module; sourceTree = ""; }; 9AF595E921C8E7B000C6AF2B /* Personal */ = { isa = PBXGroup; children = ( 9AF595EA21C8E7B000C6AF2B /* Other */, 9AF595EB21C8E7B000C6AF2B /* Controller */, 9AF595ED21C8E7B000C6AF2B /* Model */, 9AF595EE21C8E7B000C6AF2B /* View */, ); path = Personal; sourceTree = ""; }; 9AF595EA21C8E7B000C6AF2B /* Other */ = { isa = PBXGroup; children = ( ); path = Other; sourceTree = ""; }; 9AF595EB21C8E7B000C6AF2B /* Controller */ = { isa = PBXGroup; children = ( 9AF595EC21C8E7B000C6AF2B /* PersonalViewController.swift */, ); path = Controller; sourceTree = ""; }; 9AF595ED21C8E7B000C6AF2B /* Model */ = { isa = PBXGroup; children = ( ); path = Model; sourceTree = ""; }; 9AF595EE21C8E7B000C6AF2B /* View */ = { isa = PBXGroup; children = ( ); path = View; sourceTree = ""; }; 9AF595EF21C8E7B000C6AF2B /* Home */ = { isa = PBXGroup; children = ( 9AF595F021C8E7B000C6AF2B /* Other */, 9AF595F121C8E7B000C6AF2B /* Controller */, 9AF595F321C8E7B000C6AF2B /* Model */, 9AF595F421C8E7B000C6AF2B /* View */, ); path = Home; sourceTree = ""; }; 9AF595F021C8E7B000C6AF2B /* Other */ = { isa = PBXGroup; children = ( ); path = Other; sourceTree = ""; }; 9AF595F121C8E7B000C6AF2B /* Controller */ = { isa = PBXGroup; children = ( 9AF595F221C8E7B000C6AF2B /* HomeViewController.swift */, ); path = Controller; sourceTree = ""; }; 9AF595F321C8E7B000C6AF2B /* Model */ = { isa = PBXGroup; children = ( ); path = Model; sourceTree = ""; }; 9AF595F421C8E7B000C6AF2B /* View */ = { isa = PBXGroup; children = ( ); path = View; sourceTree = ""; }; 9AF595F521C8E7B000C6AF2B /* Connection */ = { isa = PBXGroup; children = ( 9AF595F621C8E7B000C6AF2B /* Other */, 9AF595F721C8E7B000C6AF2B /* Controller */, 9AF595F921C8E7B000C6AF2B /* Model */, 9AF595FA21C8E7B000C6AF2B /* View */, ); path = Connection; sourceTree = ""; }; 9AF595F621C8E7B000C6AF2B /* Other */ = { isa = PBXGroup; children = ( ); path = Other; sourceTree = ""; }; 9AF595F721C8E7B000C6AF2B /* Controller */ = { isa = PBXGroup; children = ( 9AF595F821C8E7B000C6AF2B /* ConnectionViewController.swift */, ); path = Controller; sourceTree = ""; }; 9AF595F921C8E7B000C6AF2B /* Model */ = { isa = PBXGroup; children = ( ); path = Model; sourceTree = ""; }; 9AF595FA21C8E7B000C6AF2B /* View */ = { isa = PBXGroup; children = ( ); path = View; sourceTree = ""; }; 9AF595FB21C8E7B000C6AF2B /* Message */ = { isa = PBXGroup; children = ( 9AF595FC21C8E7B000C6AF2B /* Other */, 9AF595FD21C8E7B000C6AF2B /* Controller */, 9AF595FF21C8E7B000C6AF2B /* Model */, 9AF5960021C8E7B000C6AF2B /* View */, ); path = Message; sourceTree = ""; }; 9AF595FC21C8E7B000C6AF2B /* Other */ = { isa = PBXGroup; children = ( ); path = Other; sourceTree = ""; }; 9AF595FD21C8E7B000C6AF2B /* Controller */ = { isa = PBXGroup; children = ( 9AF595FE21C8E7B000C6AF2B /* MessageViewController.swift */, ); path = Controller; sourceTree = ""; }; 9AF595FF21C8E7B000C6AF2B /* Model */ = { isa = PBXGroup; children = ( ); path = Model; sourceTree = ""; }; 9AF5960021C8E7B000C6AF2B /* View */ = { isa = PBXGroup; children = ( ); path = View; sourceTree = ""; }; 9AF5960121C8E7B000C6AF2B /* Publish */ = { isa = PBXGroup; children = ( 9AF5960221C8E7B000C6AF2B /* Other */, 9AF5960321C8E7B000C6AF2B /* Controller */, 9AF5960521C8E7B000C6AF2B /* Model */, 9AF5960621C8E7B000C6AF2B /* View */, ); path = Publish; sourceTree = ""; }; 9AF5960221C8E7B000C6AF2B /* Other */ = { isa = PBXGroup; children = ( ); path = Other; sourceTree = ""; }; 9AF5960321C8E7B000C6AF2B /* Controller */ = { isa = PBXGroup; children = ( 9AF5960421C8E7B000C6AF2B /* PublishViewController.swift */, ); path = Controller; sourceTree = ""; }; 9AF5960521C8E7B000C6AF2B /* Model */ = { isa = PBXGroup; children = ( ); path = Model; sourceTree = ""; }; 9AF5960621C8E7B000C6AF2B /* View */ = { isa = PBXGroup; children = ( ); path = View; sourceTree = ""; }; 9AF5960721C8E7B100C6AF2B /* Other */ = { isa = PBXGroup; children = ( 9AF5960821C8E7B100C6AF2B /* Assets.xcassets */, 9AF5960921C8E7B100C6AF2B /* LaunchScreen.storyboard */, 9AF5960B21C8E7B100C6AF2B /* Main.storyboard */, 9AF5960D21C8E7B100C6AF2B /* Info.plist */, ); path = Other; sourceTree = ""; }; 9AF5961821C8E8B700C6AF2B /* Controller */ = { isa = PBXGroup; children = ( ); path = Controller; sourceTree = ""; }; 9AF5961921C8E8D600C6AF2B /* Other */ = { isa = PBXGroup; children = ( ); path = Other; sourceTree = ""; }; 9E8F1952DFE997BA5D0E1F59 /* Pods */ = { isa = PBXGroup; children = ( C7C15F27AFB129417A291CF9 /* Pods-CYLTabBarController-Swift.debug.xcconfig */, 2CDA77BCC28E878CAB5EFD15 /* Pods-CYLTabBarController-Swift.release.xcconfig */, ); name = Pods; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 922DCEDC1FF63399005C89BE /* CYLTabBarController-Swift */ = { isa = PBXNativeTarget; buildConfigurationList = 922DCEEF1FF63399005C89BE /* Build configuration list for PBXNativeTarget "CYLTabBarController-Swift" */; buildPhases = ( CDF94486ED41F7591F19980E /* [CP] Check Pods Manifest.lock */, 922DCED91FF63399005C89BE /* Sources */, 922DCEDA1FF63399005C89BE /* Frameworks */, 922DCEDB1FF63399005C89BE /* Resources */, 66B8CB3D934CEEA7F1A6E40D /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); dependencies = ( ); name = "CYLTabBarController-Swift"; productName = "CYLTabBarController-Swift"; productReference = 922DCEDD1FF63399005C89BE /* CYLTabBarController-Swift.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 922DCED51FF63399005C89BE /* Project object */ = { isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0920; LastUpgradeCheck = 1010; ORGANIZATIONNAME = Anthony; TargetAttributes = { 922DCEDC1FF63399005C89BE = { CreatedOnToolsVersion = 9.2; LastSwiftMigration = 1000; ProvisioningStyle = Automatic; }; }; }; buildConfigurationList = 922DCED81FF63399005C89BE /* Build configuration list for PBXProject "CYLTabBarController-Swift" */; compatibilityVersion = "Xcode 8.0"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 922DCED41FF63399005C89BE; productRefGroup = 922DCEDE1FF63399005C89BE /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 922DCEDC1FF63399005C89BE /* CYLTabBarController-Swift */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 922DCEDB1FF63399005C89BE /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 9AF5961521C8E7B100C6AF2B /* LaunchScreen.storyboard in Resources */, 9AF5961421C8E7B100C6AF2B /* Assets.xcassets in Resources */, 9AF5961621C8E7B100C6AF2B /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 66B8CB3D934CEEA7F1A6E40D /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( "${SRCROOT}/Pods/Target Support Files/Pods-CYLTabBarController-Swift/Pods-CYLTabBarController-Swift-frameworks.sh", "${BUILT_PRODUCTS_DIR}/CYLTabBarController/CYLTabBarController.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CYLTabBarController.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-CYLTabBarController-Swift/Pods-CYLTabBarController-Swift-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; CDF94486ED41F7591F19980E /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; outputPaths = ( "$(DERIVED_FILE_DIR)/Pods-CYLTabBarController-Swift-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 922DCED91FF63399005C89BE /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 9AF5961021C8E7B100C6AF2B /* HomeViewController.swift in Sources */, 9AF595E221C8E63C00C6AF2B /* AppDelegate.swift in Sources */, 9AF5961121C8E7B100C6AF2B /* ConnectionViewController.swift in Sources */, 9AF5960E21C8E7B100C6AF2B /* CYLPlusButtonSubclass.swift in Sources */, 9AF5961321C8E7B100C6AF2B /* PublishViewController.swift in Sources */, 9AF5960F21C8E7B100C6AF2B /* PersonalViewController.swift in Sources */, 9AF595E321C8E63C00C6AF2B /* MainTabBarController.swift in Sources */, 9AF5961221C8E7B100C6AF2B /* MessageViewController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ 9AF5960921C8E7B100C6AF2B /* LaunchScreen.storyboard */ = { isa = PBXVariantGroup; children = ( 9AF5960A21C8E7B100C6AF2B /* Base */, ); name = LaunchScreen.storyboard; sourceTree = ""; }; 9AF5960B21C8E7B100C6AF2B /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( 9AF5960C21C8E7B100C6AF2B /* Base */, ); name = Main.storyboard; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 922DCEED1FF63399005C89BE /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; 922DCEEE1FF63399005C89BE /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; VALIDATE_PRODUCT = YES; }; name = Release; }; 922DCEF01FF63399005C89BE /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = C7C15F27AFB129417A291CF9 /* Pods-CYLTabBarController-Swift.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = "$(SRCROOT)/Other/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "WeMadeCode.CYLTabBarController-Swift"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; 922DCEF11FF63399005C89BE /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 2CDA77BCC28E878CAB5EFD15 /* Pods-CYLTabBarController-Swift.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = "$(SRCROOT)/Other/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "WeMadeCode.CYLTabBarController-Swift"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 922DCED81FF63399005C89BE /* Build configuration list for PBXProject "CYLTabBarController-Swift" */ = { isa = XCConfigurationList; buildConfigurations = ( 922DCEED1FF63399005C89BE /* Debug */, 922DCEEE1FF63399005C89BE /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 922DCEEF1FF63399005C89BE /* Build configuration list for PBXNativeTarget "CYLTabBarController-Swift" */ = { isa = XCConfigurationList; buildConfigurations = ( 922DCEF01FF63399005C89BE /* Debug */, 922DCEF11FF63399005C89BE /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 922DCED51FF63399005C89BE /* Project object */; } ================================================ FILE: Example-Swift/MainTabBarController.swift ================================================ // // MainTabBarController.swift // // v1.16.0 Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/20/15. // Copyright © 2018 https://github.com/ChenYilong . All rights reserved. // import CYLTabBarController import UIKit class MainTabBarController: CYLTabBarController { override func viewDidLoad() { super.viewDidLoad() } } ================================================ FILE: Example-Swift/Module/Connection/Controller/ConnectionViewController.swift ================================================ // // ConnectionViewController.swift // // v1.16.0 Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/20/15. // Copyright © 2018 https://github.com/ChenYilong . All rights reserved. // import UIKit class ConnectionViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = UIColor.blue } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } /* // MARK: - Navigation // In a storyboard-based application, you will often want to do a little preparation before navigation override func prepare(for segue: UIStoryboardSegue, sender: Any?) { // Get the new view controller using segue.destinationViewController. // Pass the selected object to the new view controller. } */ } ================================================ FILE: Example-Swift/Module/Home/Controller/HomeViewController.swift ================================================ // // HomeViewController.swift // // v1.16.0 Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/20/15. // Copyright © 2018 https://github.com/ChenYilong . All rights reserved. // import UIKit class HomeViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = UIColor.orange } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } /* // MARK: - Navigation // In a storyboard-based application, you will often want to do a little preparation before navigation override func prepare(for segue: UIStoryboardSegue, sender: Any?) { // Get the new view controller using segue.destinationViewController. // Pass the selected object to the new view controller. } */ } ================================================ FILE: Example-Swift/Module/Message/Controller/MessageViewController.swift ================================================ // // MessageViewController.swift // SwiftDemo // // Created by Anthony on 2017/12/29. // Copyright © 2017年 Anthony. All rights reserved. // import UIKit class MessageViewController: UIViewController { // private weak var myLabel1:UILabel! // private weak var myLabel2:UILabel! // private weak var myLabel3:UILabel! // private weak var myLabel4:UILabel! // private weak var myLabel5:UILabel! // private weak var myLabel6:UILabel! // // var buttonColor: UIColor { // return UIColor(named: "buttonColor")! // } // // var labelColor: UIColor { // return UIColor(named: "labelColor")! // } // // var textFieldColor: UIColor { // return UIColor(named: "textFieldColor")! // } override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = UIColor.gray } } ================================================ FILE: Example-Swift/Module/Personal/Controller/PersonalViewController.swift ================================================ // // PersonalViewController.swift // // v1.16.0 Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/20/15. // Copyright © 2018 https://github.com/ChenYilong . All rights reserved. // import UIKit class PersonalViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = UIColor.green } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } /* // MARK: - Navigation // In a storyboard-based application, you will often want to do a little preparation before navigation override func prepare(for segue: UIStoryboardSegue, sender: Any?) { // Get the new view controller using segue.destinationViewController. // Pass the selected object to the new view controller. } */ } ================================================ FILE: Example-Swift/Module/Publish/Controller/PublishViewController.swift ================================================ // // PublishViewController.swift // CYLTabbarController-Swift // v1.16.0 Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/20/15. // Copyright © 2018 https://github.com/ChenYilong . All rights reserved. // import UIKit class PublishViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = UIColor.red // Do any additional setup after loading the view. } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } /* // MARK: - Navigation // In a storyboard-based application, you will often want to do a little preparation before navigation override func prepare(for segue: UIStoryboardSegue, sender: Any?) { // Get the new view controller using segue.destinationViewController. // Pass the selected object to the new view controller. } */ } ================================================ FILE: Example-Swift/Other/Assets.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "idiom" : "iphone", "size" : "20x20", "scale" : "2x" }, { "idiom" : "iphone", "size" : "20x20", "scale" : "3x" }, { "size" : "29x29", "idiom" : "iphone", "filename" : "Icon-Small.png", "scale" : "1x" }, { "size" : "29x29", "idiom" : "iphone", "filename" : "Icon-Small@2x.png", "scale" : "2x" }, { "size" : "29x29", "idiom" : "iphone", "filename" : "Icon-Small@3x.png", "scale" : "3x" }, { "size" : "40x40", "idiom" : "iphone", "filename" : "Icon-40@2x.png", "scale" : "2x" }, { "size" : "40x40", "idiom" : "iphone", "filename" : "Icon-40@3x.png", "scale" : "3x" }, { "size" : "57x57", "idiom" : "iphone", "filename" : "Icon.png", "scale" : "1x" }, { "size" : "57x57", "idiom" : "iphone", "filename" : "Icon@2x.png", "scale" : "2x" }, { "size" : "60x60", "idiom" : "iphone", "filename" : "Icon-60@2x.png", "scale" : "2x" }, { "size" : "60x60", "idiom" : "iphone", "filename" : "Icon-60@3x.png", "scale" : "3x" }, { "idiom" : "ipad", "size" : "20x20", "scale" : "1x" }, { "idiom" : "ipad", "size" : "20x20", "scale" : "2x" }, { "size" : "29x29", "idiom" : "ipad", "filename" : "Icon-Small.png", "scale" : "1x" }, { "size" : "29x29", "idiom" : "ipad", "filename" : "Icon-Small@2x.png", "scale" : "2x" }, { "size" : "40x40", "idiom" : "ipad", "filename" : "Icon-40.png", "scale" : "1x" }, { "size" : "40x40", "idiom" : "ipad", "filename" : "Icon-40@2x.png", "scale" : "2x" }, { "size" : "50x50", "idiom" : "ipad", "filename" : "Icon-Small-50.png", "scale" : "1x" }, { "size" : "50x50", "idiom" : "ipad", "filename" : "Icon-Small-50@2x.png", "scale" : "2x" }, { "size" : "72x72", "idiom" : "ipad", "filename" : "Icon-72.png", "scale" : "1x" }, { "size" : "72x72", "idiom" : "ipad", "filename" : "Icon-72@2x.png", "scale" : "2x" }, { "size" : "76x76", "idiom" : "ipad", "filename" : "Icon-76.png", "scale" : "1x" }, { "size" : "76x76", "idiom" : "ipad", "filename" : "Icon-76@2x.png", "scale" : "2x" }, { "size" : "83.5x83.5", "idiom" : "ipad", "filename" : "Icon-83.5@2x.png", "scale" : "2x" }, { "idiom" : "ios-marketing", "size" : "1024x1024", "scale" : "1x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example-Swift/Other/Assets.xcassets/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example-Swift/Other/Assets.xcassets/LaunchImage.launchimage/Contents.json ================================================ { "images" : [ { "filename" : "default-portrait-1792h@3x.png", "subtype" : "1792h", "minimum-system-version" : "12.0", "extent" : "full-screen", "orientation" : "portrait", "scale" : "2x", "idiom" : "iphone" }, { "orientation" : "landscape", "minimum-system-version" : "12.0", "subtype" : "1792h", "filename" : "default-landscape-1792h@3x.png", "idiom" : "iphone", "extent" : "full-screen", "scale" : "2x" }, { "scale" : "3x", "idiom" : "iphone", "subtype" : "2688h", "extent" : "full-screen", "filename" : "default-portrait-2688h@3x.png", "minimum-system-version" : "12.0", "orientation" : "portrait" }, { "extent" : "full-screen", "orientation" : "landscape", "filename" : "default-landscape-2688h@3x.png", "scale" : "3x", "subtype" : "2688h", "idiom" : "iphone", "minimum-system-version" : "12.0" }, { "orientation" : "portrait", "idiom" : "iphone", "extent" : "full-screen", "filename" : "default-portrait-2436h@3x.png", "minimum-system-version" : "11.0", "subtype" : "2436h", "scale" : "3x" }, { "scale" : "3x", "subtype" : "2436h", "orientation" : "landscape", "extent" : "full-screen", "idiom" : "iphone", "filename" : "default-landscape-2436h@3x.png", "minimum-system-version" : "11.0" }, { "extent" : "full-screen", "scale" : "1x", "filename" : "default.png", "idiom" : "iphone", "orientation" : "portrait" }, { "orientation" : "portrait", "extent" : "full-screen", "minimum-system-version" : "7.0", "filename" : "default@2x.png", "idiom" : "iphone", "scale" : "2x" }, { "subtype" : "retina4", "idiom" : "iphone", "scale" : "2x", "orientation" : "portrait", "extent" : "full-screen", "filename" : "default-568h@2x.png" }, { "orientation" : "portrait", "scale" : "2x", "subtype" : "retina4", "idiom" : "iphone", "minimum-system-version" : "7.0", "filename" : "default-568h@2x.png", "extent" : "full-screen" }, { "idiom" : "iphone", "filename" : "default@2x.png", "scale" : "2x", "extent" : "full-screen", "orientation" : "portrait" }, { "extent" : "to-status-bar", "idiom" : "ipad", "scale" : "1x", "orientation" : "portrait", "filename" : "default~ipad.png" }, { "filename" : "default~ipad@2x.png", "orientation" : "portrait", "extent" : "to-status-bar", "scale" : "2x", "idiom" : "ipad" }, { "idiom" : "ipad", "orientation" : "landscape", "extent" : "to-status-bar", "filename" : "default~ipad~landscape.png", "scale" : "1x" }, { "scale" : "2x", "extent" : "to-status-bar", "orientation" : "landscape", "filename" : "default~ipad~landscape@2x.png", "idiom" : "ipad" }, { "orientation" : "portrait", "filename" : "default~ipad~nostatusbar.png", "extent" : "full-screen", "minimum-system-version" : "7.0", "scale" : "1x", "idiom" : "ipad" }, { "filename" : "default~ipad~nostatusbar.png", "idiom" : "ipad", "extent" : "full-screen", "scale" : "1x", "orientation" : "portrait" }, { "minimum-system-version" : "7.0", "filename" : "default~ipad~nostatusbar@2x.png", "scale" : "2x", "extent" : "full-screen", "orientation" : "portrait", "idiom" : "ipad" }, { "idiom" : "ipad", "extent" : "full-screen", "scale" : "2x", "orientation" : "portrait", "filename" : "default~ipad~nostatusbar@2x.png" }, { "extent" : "full-screen", "minimum-system-version" : "7.0", "filename" : "default~ipad~landscape~nostatusbar.png", "scale" : "1x", "orientation" : "landscape", "idiom" : "ipad" }, { "idiom" : "ipad", "orientation" : "landscape", "extent" : "full-screen", "filename" : "default~ipad~landscape~nostatusbar.png", "scale" : "1x" }, { "extent" : "full-screen", "orientation" : "landscape", "idiom" : "ipad", "filename" : "default~ipad~landscape~nostatusbar@2x.png", "minimum-system-version" : "7.0", "scale" : "2x" }, { "filename" : "default~ipad~landscape~nostatusbar@2x.png", "idiom" : "ipad", "scale" : "2x", "extent" : "full-screen", "orientation" : "landscape" }, { "subtype" : "736h", "filename" : "default-portrait-736h@3x.png", "orientation" : "portrait", "idiom" : "iphone", "scale" : "3x", "minimum-system-version" : "8.0", "extent" : "full-screen" }, { "extent" : "full-screen", "scale" : "3x", "idiom" : "iphone", "subtype" : "736h", "minimum-system-version" : "8.0", "orientation" : "landscape", "filename" : "default-landscape-736h@3x.png" }, { "orientation" : "portrait", "scale" : "2x", "minimum-system-version" : "8.0", "extent" : "full-screen", "filename" : "default-667h@2x.png", "subtype" : "667h", "idiom" : "iphone" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Example-Swift/Other/Assets.xcassets/TabBarIcon/Contents.json ================================================ { "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example-Swift/Other/Assets.xcassets/TabBarIcon/account_highlight.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "account_highlight@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" }, "properties" : { "template-rendering-intent" : "original" } } ================================================ FILE: Example-Swift/Other/Assets.xcassets/TabBarIcon/account_normal.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "account_normal@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" }, "properties" : { "template-rendering-intent" : "original" } } ================================================ FILE: Example-Swift/Other/Assets.xcassets/TabBarIcon/home_highlight.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "home_highlight@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" }, "properties" : { "template-rendering-intent" : "original" } } ================================================ FILE: Example-Swift/Other/Assets.xcassets/TabBarIcon/home_normal.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "home_normal@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" }, "properties" : { "template-rendering-intent" : "original" } } ================================================ FILE: Example-Swift/Other/Assets.xcassets/TabBarIcon/message_highlight.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "message_highlight@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" }, "properties" : { "template-rendering-intent" : "original" } } ================================================ FILE: Example-Swift/Other/Assets.xcassets/TabBarIcon/message_normal.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "message_normal@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" }, "properties" : { "template-rendering-intent" : "original" } } ================================================ FILE: Example-Swift/Other/Assets.xcassets/TabBarIcon/mycity_highlight.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "mycity_highlight@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" }, "properties" : { "template-rendering-intent" : "original" } } ================================================ FILE: Example-Swift/Other/Assets.xcassets/TabBarIcon/mycity_normal.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "mycity_normal@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" }, "properties" : { "template-rendering-intent" : "original" } } ================================================ FILE: Example-Swift/Other/Assets.xcassets/TabBarIcon/post_normal.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "post_normal@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" }, "properties" : { "template-rendering-intent" : "original" } } ================================================ FILE: Example-Swift/Other/Assets.xcassets/TabBarIcon/tabbar_background.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "tabbar_background@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Example-Swift/Other/Assets.xcassets/TabBarIcon/tapbar_top_line.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "filename" : "tapbar_top_line@2x.png", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" }, "properties" : { "template-rendering-intent" : "original" } } ================================================ FILE: Example-Swift/Other/Base.lproj/LaunchScreen.storyboard ================================================ ================================================ FILE: Example-Swift/Other/Base.lproj/Main.storyboard ================================================ ================================================ FILE: Example-Swift/Other/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleVersion 1 LSRequiresIPhoneOS UIMainStoryboardFile Main UIRequiredDeviceCapabilities armv7 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight ================================================ FILE: Example-Swift/Podfile ================================================ # Uncomment the next line to define a global platform for your project # platform :ios, '9.0' source 'git@github.com:CocoaPods/Specs.git' # Uncomment the next line to define a global platform for your project # platform :ios, '9.0' source 'git@github.com:CocoaPods/Specs.git' platform:ios,'9.0' inhibit_all_warnings! target 'CYLTabBarController-Swift' do use_frameworks! pod 'CYLTabBarController', :path => '../' end ================================================ FILE: Example-Swift/View/CYLPlusButtonSubclass.swift ================================================ // // CYLPlusButtonSubclass.swift // // v1.16.0 Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/20/15. // Copyright © 2018 https://github.com/ChenYilong . All rights reserved. // import CYLTabBarController import UIKit class CYLPlusButtonSubclass: CYLPlusButton, CYLPlusButtonSubclassing { static func plusButton() -> Any! { let button = CYLPlusButtonSubclass() button.setImage(UIImage(named: "post_normal"), for: .normal) button.titleLabel?.textAlignment = .center button.titleLabel?.font = UIFont.systemFont(ofSize: 10) button.setTitle("发布", for: .normal) button.setTitleColor(UIColor.gray, for: .normal) button.setTitle("选中", for: .selected) button.setTitleColor(UIColor.blue, for: .selected) button.adjustsImageWhenHighlighted = false button.sizeToFit() // button.addTarget(self, action: #selector(testClick(sender:)), for: .touchUpInside) return button } // @objc static func testClick(sender: UIButton){ // print("testClick") // } static func indexOfPlusButtonInTabBar() -> UInt { return 2 } static func multiplier(ofTabBarHeight _: CGFloat) -> CGFloat { return 0.3 } static func constantOfPlusButtonCenterYOffset(forTabBarHeight _: CGFloat) -> CGFloat { return -10 } static func plusChildViewController() -> UIViewController! { let vc = PublishViewController() let nav = UINavigationController(rootViewController: vc) return nav } static func shouldSelectPlusChildViewController() -> Bool { return true } override func layoutSubviews() { super.layoutSubviews() // tabbar UI layout setup let imageViewEdgeWidth: CGFloat = bounds.size.width * 0.7 let imageViewEdgeHeight: CGFloat = imageViewEdgeWidth * 0.9 let centerOfView = bounds.size.width * 0.5 let labelLineHeight = titleLabel!.font.lineHeight let verticalMargin = (bounds.size.height - labelLineHeight - imageViewEdgeHeight) * 0.5 let centerOfImageView = verticalMargin + imageViewEdgeHeight * 0.5 let centerOfTitleLabel = imageViewEdgeHeight + verticalMargin * 2 + labelLineHeight * 0.5 + 10 // imageView position layout imageView!.bounds = CGRect(x: 0, y: 0, width: imageViewEdgeWidth, height: imageViewEdgeHeight) imageView!.center = CGPoint(x: centerOfView, y: centerOfImageView) // title position layout titleLabel!.bounds = CGRect(x: 0, y: 0, width: bounds.size.width, height: labelLineHeight) titleLabel!.center = CGPoint(x: centerOfView, y: centerOfTitleLabel) } } ================================================ FILE: LICENSE ================================================ Copyright (c) 2015 CYLTabBarController(https://github.com/ChenYilong/CYLTabBarController), L.L.C. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE ================================================ FILE: Podfile ================================================ # Uncomment the next line to define a global platform for your project # platform :ios, '9.0' source 'https://cdn.cocoapods.org/' target 'CYLTabBarController' do # Comment the next line if you don't want to use dynamic frameworks use_frameworks! #pod 'CYLTabBarController', '~> 1.28.5' # 默认不依赖Lottie pod 'CYLTabBarController/Lottie', '~> 1.29.0' # 依赖Lottie库 #pod 'CYLTabBarController', :path => './' #pod 'CYLTabBarController/Lottie', :path => './' pod 'MJRefresh' end ================================================ FILE: README.md ================================================

# [CN]CYLTabBarController【一行代码实现 Lottie 动画 TabBar】 # [EN]CYLTabBarController [An animated tabBar supported by Lottie with one line of code]

-------------------------------------------- ## [CN]阅读须知 ## [EN]Before Reading - [CN] mark means Chinese language by default. - [EN] mark means English language. - [CN] [点此获取 QQ 群,Telegram 群交流信息]( https://github.com/ChenYilong/iOSBlog/issues/21) 。 - [EN]Telegram Group to communicate the features or bugs: https://t.me/CYLTabBarController # [CN]谁在用?上架APP列表[EN]who are using?List of App published APP name link icon | image |APP name link icon | image :-------------:|:-------------:|:-------------:|:-------------: 海底捞 [App Store Link](https://itunes.apple.com/cn/app/%E6%B5%B7%E5%BA%95%E6%8D%9E/id553115181?l=en&mt=8) ![enter image description here](https://is1-ssl.mzstatic.com/image/thumb/Purple123/v4/3f/8c/b2/3f8cb27c-8a47-82b2-fa08-25ca075cee59/AppIcon-1x_U007emarketing-85-220-0-9.png/690x0w.jpg) | ![enter image description here](https://is5-ssl.mzstatic.com/image/thumb/Purple128/v4/20/78/c4/2078c481-aa68-c263-ee3b-22b797ec2209/pr_source.jpg/690x0w.jpg) | C家 [App Store Link](https://itunes.apple.com/cn/app/c%E5%AE%B6/id1123394197?l=en&mt=8) ![enter image description here](https://is5-ssl.mzstatic.com/image/thumb/Purple113/v4/cf/9c/35/cf9c35c2-68fa-8d3a-e612-e2560501899b/AppIcon-0-1x_U007emarketing-0-0-85-220-0-5.png/690x0w.jpg) | Lottie 效果 ![](http://ww3.sinaimg.cn/large/006tNc79ly1g3aavtlekdg30ai0l2b2b.gif) | 淘必中-淘宝推出的一款具有营销购物功能的APP [App Store Link](https://itunes.apple.com/cn/app/%E6%B7%98%E5%BF%85%E4%B8%AD/id399737960?l=en&mt=8) ![enter image description here](https://is2-ssl.mzstatic.com/image/thumb/Purple125/v4/f2/8d/58/f28d5806-bf9d-b77b-4e41-5986d96d250b/AppIcon-1x_U007emarketing-85-220-4.png/690x0w.jpg ) | ![enter image description here](https://is4-ssl.mzstatic.com/image/thumb/Purple125/v4/67/04/be/6704be9c-de16-fcdd-0376-7bf66a3e3f82/pr_source.png/690x0w.png) | 慧诊健康 [App Store Link](https://itunes.apple.com/cn/app/%E6%85%A7%E8%AF%8A%E5%81%A5%E5%BA%B7/id1434271846?mt=8) ![enter image description here](https://is3-ssl.mzstatic.com/image/thumb/Purple124/v4/b4/ae/d3/b4aed30e-996e-2fcc-0234-ebff091c861d/AppIcon-0-1x_U007emarketing-0-0-85-220-0-10.png/690x0w.jpg)|![enter image description here](https://is3-ssl.mzstatic.com/image/thumb/Purple118/v4/6d/f3/33/6df33378-da60-45b3-1c2a-9d286f12ce55/mzl.vgjiebgy.png/690x0w.jpg) 究竟大学 [App Store Link](https://itunes.apple.com/us/app/%E7%A9%B6%E7%AB%9F%E5%A4%A7%E5%AD%A6/id1334531245?mt=8) ![enter image description here](https://is3-ssl.mzstatic.com/image/thumb/Purple123/v4/d8/4a/95/d84a9596-3d02-881e-7646-e90954ffa8bc/AppIcon-0-1x_U007emarketing-0-0-85-220-6.png/690x0w.jpg) | ![enter image description here](https://is1-ssl.mzstatic.com/image/thumb/Purple123/v4/ca/4f/f4/ca4ff420-ec42-cc9d-7c8f-d7df388a184d/pr_source.png/690x0w.jpg) | 蕉片 - 短视频拍摄剪辑出电影大片 [App Store Link](https://itunes.apple.com/us/app/%E8%95%89%E7%89%87-%E7%9F%AD%E8%A7%86%E9%A2%91%E6%8B%8D%E6%91%84%E5%89%AA%E8%BE%91%E5%87%BA%E7%94%B5%E5%BD%B1%E5%A4%A7%E7%89%87/id1235972800?mt=8) ![enter image description here](https://is1-ssl.mzstatic.com/image/thumb/Purple128/v4/2c/14/68/2c1468de-5807-253d-baa4-54cd4b43d7a3/AppIcon-1x_U007emarketing-85-220-4.png/230x0w.jpg)|![](http://ww1.sinaimg.cn/large/006tNc79ly1g3aaq6rnekj30j615hq5m.jpg) 闪剧 - 可以玩的短视频 [App Store Link](https://itunes.apple.com/us/app/%E9%97%AA%E5%89%A7-%E5%8F%AF%E4%BB%A5%E7%8E%A9%E7%9A%84%E7%9F%AD%E8%A7%86%E9%A2%91/id1360997439?mt=8) ![enter image description here](https://is2-ssl.mzstatic.com/image/thumb/Purple113/v4/e6/26/e0/e626e01e-b00d-c36c-fa3c-98c59e5b95b1/AppIcon-0-1x_U007emarketing-0-0-GLES2_U002c0-512MB-sRGB-0-0-0-85-220-0-0-0-7.png/690x0w.jpg)| ![enter image description here](https://is3-ssl.mzstatic.com/image/thumb/Purple113/v4/23/70/57/23705710-9ee4-f7f0-9763-1ad2e5cb7cf6/pr_source.jpg/690x0w.jpg) | 土狗云商城 [App Store Link](https://itunes.apple.com/cn/app/%E5%9C%9F%E7%8B%97%E4%BC%98%E4%BA%AB/id1239005385?mt=8) ![enter image description here](https://is4-ssl.mzstatic.com/image/thumb/Purple113/v4/1c/06/93/1c0693ef-db45-de8c-5b39-1b966d58c930/AppIcon-0-1x_U007emarketing-0-0-85-220-0-7.png/690x0w.jpg)|![](http://ww4.sinaimg.cn/large/006tNc79ly1g3aaqwf078j30u01sxx6r.jpg) Analyst.ai [App Store Link](https://itunes.apple.com/us/app/analyst-ai/id1345754742?mt=8) ![enter image description here](https://is1-ssl.mzstatic.com/image/thumb/Purple113/v4/33/89/1d/33891d65-022e-88a3-b495-7fea6fe77a32/AppIcon-0-1x_U007emarketing-0-0-85-220-0-5.png/690x0w.jpg)| ![enter image description here](https://is4-ssl.mzstatic.com/image/thumb/Purple123/v4/35/33/77/35337725-e80d-7b4c-6422-0cac61039917/pr_source.png/690x0w.jpg) | 美膳校园 [App Store Link](https://itunes.apple.com/us/app/%E7%BE%8E%E8%86%B3%E6%A0%A1%E5%9B%AD/id1447211131?mt=8) ![enter image description here](https://is2-ssl.mzstatic.com/image/thumb/Purple113/v4/de/f7/be/def7be95-abc6-df2e-78c5-8318eae418be/AppIcon-0-1x_U007emarketing-0-0-85-220-0-2.png/690x0w.jpg)| ![enter image description here](https://is5-ssl.mzstatic.com/image/thumb/Purple128/v4/e0/e8/aa/e0e8aadf-6692-d974-7962-778160e7eb5f/pr_source.png/690x0w.png) 全聚星 [App Store Link](https://itunes.apple.com/us/app/%E5%85%A8%E8%81%9A%E6%98%9F/id1140827531?mt=8) ![enter image description here](https://is1-ssl.mzstatic.com/image/thumb/Purple128/v4/4d/a2/57/4da25727-eda7-c7f8-8ce5-3b44591f3863/AppIcon-1x_U007emarketing-85-220-4.png/690x0w.jpg) |![enter image description here](https://is4-ssl.mzstatic.com/image/thumb/Purple118/v4/be/5f/0c/be5f0cbb-0265-b34d-bc34-ab9859f97350/mzl.bwmxymgk.jpg/690x0w.jpg) | Yesoul [App Store Link](https://itunes.apple.com/us/app/yesoul/id1144444969?mt=8) ![enter image description here](https://is5-ssl.mzstatic.com/image/thumb/Purple113/v4/3f/0b/80/3f0b80df-e7fd-7c86-c3d2-472393304509/AppIcon-0-1x_U007emarketing-0-0-sRGB-85-220-0-7.png/690x0w.jpg) | ![enter image description here](https://is4-ssl.mzstatic.com/image/thumb/Purple123/v4/bb/96/9f/bb969f5e-48e8-b721-2db3-cf26d7b916f8/pr_source.png/460x0w.jpg) 贵州充电通 [App Store Link](https://itunes.apple.com/us/app/%E8%B4%B5%E5%B7%9E%E5%85%85%E7%94%B5%E9%80%9A/id1455932848?mt=8&app=itunes&ign-mpt=uo%3D4) ![enter image description here](https://is3-ssl.mzstatic.com/image/thumb/Purple113/v4/d5/db/44/d5db4437-d409-ff48-3c19-1feabbd7b2a1/AppIcon-0-1x_U007emarketing-0-0-sRGB-85-220-0-7.png/690x0w.jpg) | ![enter image description here](https://is4-ssl.mzstatic.com/image/thumb/Purple123/v4/17/51/23/17512338-5bf2-3f4a-bda8-c4986dfe5be6/pr_source.png/690x0w.jpg) | 卓尔购 [App Store Link](https://itunes.apple.com/cn/app/%E5%8D%93%E5%B0%94%E8%B4%AD-%E6%89%B9%E5%8F%91%E9%87%87%E8%B4%AD%E8%BF%9B%E8%B4%A7%E9%A6%96%E9%80%89/id1063104387?mt=8) ![enter image description here](https://is3-ssl.mzstatic.com/image/thumb/Purple114/v4/3c/36/e5/3c36e51e-47e9-0526-5652-bbc6acf3739c/mzl.emuqqmck.png/690x0w.jpg) | ![enter image description here](https://is3-ssl.mzstatic.com/image/thumb/Purple125/v4/fc/eb/e2/fcebe232-3a72-93fc-ed3a-2942ac22ab79/pr_source.png/690x0w.png) 卓越管家 [App Store Link](https://itunes.apple.com/cn/app//id1268483803?mt=8) ![enter image description here](https://is4-ssl.mzstatic.com/image/thumb/Purple123/v4/b9/6a/d8/b96ad81a-3805-b1c8-3a56-83940fed4b01/AppIcon-0-1x_U007emarketing-0-85-220-5.png/690x0w.jpg) | ![enter image description here](https://is3-ssl.mzstatic.com/image/thumb/Purple113/v4/ca/f8/f8/caf8f846-ddc9-2ada-99c3-9758fc099288/pr_source.png/690x0w.jpg) | 悦守护 [App Store Link](https://itunes.apple.com/cn/app/%E6%82%A6%E5%AE%88%E6%8A%A4/id1347678565?mt=8) | ![](http://ww2.sinaimg.cn/large/006tNc79ly1g3a9upgmmjj30j615iads.jpg) 筑集采采购端 [App Store Link](https://itunes.apple.com/cn/app//id1041802973?mt=8) ![enter image description here](https://is2-ssl.mzstatic.com/image/thumb/Purple123/v4/f4/d2/1d/f4d21df2-57da-e0a0-5de2-2c9437553fcb/AppIcon-0-1x_U007emarketing-0-0-85-220-7.png/690x0w.jpg) | ![](http://ww1.sinaimg.cn/large/006tNc79ly1g3aa9fncl1j30j60y3adb.jpg) | 筑集采供应端 [App Store Link](https://itunes.apple.com/fr/app//id1035221629?mt=8) ![enter image description here](https://is1-ssl.mzstatic.com/image/thumb/Purple113/v4/8f/ba/6e/8fba6ec9-97e2-e008-f2f2-a30a1641cfa6/AppIcon-0-1x_U007emarketing-0-0-85-220-7.png/690x0w.jpg) | ![](http://ww3.sinaimg.cn/large/006tNc79ly1g3aaa6itrcj30j60y30xl.jpg) | 桂富宝 [App Store Link](https://itunes.apple.com/nz/app/e%E8%81%94%E7%9B%9F%E5%95%86%E5%9F%8E/id979819957) ![enter image description here](https://is2-ssl.mzstatic.com/image/thumb/Purple113/v4/6f/62/22/6f6222c7-e54e-2ea7-feb7-ce481e562248/AppIcon-0-1x_U007emarketing-0-0-85-220-0-10.png/690x0w.jpg) | ![enter image description here](https://is5-ssl.mzstatic.com/image/thumb/Purple123/v4/4c/80/90/4c8090af-17b4-c152-2ba3-3037d5e7e905/pr_source.png/690x0w.jpg) | 小猪奔奔 [App Store Link](https://itunes.apple.com/cn/app/%E5%B0%8F%E7%8C%AA%E5%A5%94%E5%A5%94-%E7%94%A8%E6%88%B7%E7%89%88/id1124274649?mt=8) ![enter image description here](https://is5-ssl.mzstatic.com/image/thumb/Purple62/v4/78/b6/fd/78b6fde6-084b-3503-b2eb-3e85fa30beb0/AppIcon-1x_U007emarketing-85-220-4.png/690x0w.jpg) | ![enter image description here](https://is4-ssl.mzstatic.com/image/thumb/Purple118/v4/c8/d5/5e/c8d55e4d-9a39-0f12-d121-1bb15d8fed56/mzl.iizreksh.png/690x0w.jpg) 娃娃坞(开发中)![](http://ww3.sinaimg.cn/large/006tNc79ly1g3aaruxhn1j30j60j60t3.jpg) | ![](http://ww1.sinaimg.cn/large/006tNc79ly1g3aaf0s1yhj30l005iwer.jpg) | 更多APP请访问 [《使用 CYLTabBarController 做的 APP,来这里报道下吧》]( https://github.com/ChenYilong/CYLTabBarController/issues/314 ) | 如果你正在使用也请提交到这里 [《使用 CYLTabBarController 做的 APP,来这里报道下吧》]( https://github.com/ChenYilong/CYLTabBarController/issues/314 ) ## [CN]导航 ## [EN]CONTENTS - [与其他自定义TabBarController的区别](#%E4%B8%8E%E5%85%B6%E4%BB%96%E8%87%AA%E5%AE%9A%E4%B9%89tabbarcontroller%E7%9A%84%E5%8C%BA%E5%88%AB) - [集成后的效果:](#%E9%9B%86%E6%88%90%E5%90%8E%E7%9A%84%E6%95%88%E6%9E%9C) - [项目结构](#%E9%A1%B9%E7%9B%AE%E7%BB%93%E6%9E%84) - [使用CYLTabBarController](#%E4%BD%BF%E7%94%A8cyltabbarcontroller) - [第一步:使用CocoaPods导入CYLTabBarController](#%E7%AC%AC%E4%B8%80%E6%AD%A5%E4%BD%BF%E7%94%A8cocoapods%E5%AF%BC%E5%85%A5cyltabbarcontroller) - [第二步:设置CYLTabBarController的两个数组:控制器数组和TabBar属性数组](#%E7%AC%AC%E4%BA%8C%E6%AD%A5%E8%AE%BE%E7%BD%AEcyltabbarcontroller%E7%9A%84%E4%B8%A4%E4%B8%AA%E6%95%B0%E7%BB%84%E6%8E%A7%E5%88%B6%E5%99%A8%E6%95%B0%E7%BB%84%E5%92%8Ctabbar%E5%B1%9E%E6%80%A7%E6%95%B0%E7%BB%84) - [第三步:将CYLTabBarController设置为window的RootViewController](#%E7%AC%AC%E4%B8%89%E6%AD%A5%E5%B0%86cyltabbarcontroller%E8%AE%BE%E7%BD%AE%E4%B8%BAwindow%E7%9A%84rootviewcontroller) - [第四步(可选):创建自定义的形状不规则加号按钮](#%E7%AC%AC%E5%9B%9B%E6%AD%A5%E5%8F%AF%E9%80%89%E5%88%9B%E5%BB%BA%E8%87%AA%E5%AE%9A%E4%B9%89%E7%9A%84%E5%BD%A2%E7%8A%B6%E4%B8%8D%E8%A7%84%E5%88%99%E5%8A%A0%E5%8F%B7%E6%8C%89%E9%92%AE) - [补充说明](#%E8%A1%A5%E5%85%85%E8%AF%B4%E6%98%8E) - [自定义 `TabBar` 样式](#%E8%87%AA%E5%AE%9A%E4%B9%89-tabbar-%E6%A0%B7%E5%BC%8F) - [捕获 TabBar 点击事件](#%E6%8D%95%E8%8E%B7-tabbar-%E7%82%B9%E5%87%BB%E4%BA%8B%E4%BB%B6) - [点击 TabBarButton 时添加动画](#%E7%82%B9%E5%87%BB-tabbarbutton-%E6%97%B6%E6%B7%BB%E5%8A%A0%E5%8A%A8%E7%94%BB) - [横竖屏适配](#%E6%A8%AA%E7%AB%96%E5%B1%8F%E9%80%82%E9%85%8D) - [访问初始化好的 CYLTabBarController 对象](#%E8%AE%BF%E9%97%AE%E5%88%9D%E5%A7%8B%E5%8C%96%E5%A5%BD%E7%9A%84-cyltabbarcontroller-%E5%AF%B9%E8%B1%A1) - [点击 PlusButton 跳转到指定 UIViewController](#%E7%82%B9%E5%87%BB-plusbutton-%E8%B7%B3%E8%BD%AC%E5%88%B0%E6%8C%87%E5%AE%9A-uiviewcontroller) - [让TabBarItem仅显示图标,并使图标垂直居中](#%E8%AE%A9tabbaritem%E4%BB%85%E6%98%BE%E7%A4%BA%E5%9B%BE%E6%A0%87%E5%B9%B6%E4%BD%BF%E5%9B%BE%E6%A0%87%E5%9E%82%E7%9B%B4%E5%B1%85%E4%B8%AD) - [多TabBar嵌套,并指定PlusButton位置](#%E5%A4%9Atabbar%E5%B5%8C%E5%A5%97%E5%B9%B6%E6%8C%87%E5%AE%9Aplusbutton%E4%BD%8D%E7%BD%AE) - [在 Swift 项目中使用 CYLTabBarController](#%E5%9C%A8-swift-%E9%A1%B9%E7%9B%AE%E4%B8%AD%E4%BD%BF%E7%94%A8-cyltabbarcontroller) - [搭配 Storyboard 使用 CYLTabBarController](#%E6%90%AD%E9%85%8D-storyboard-%E4%BD%BF%E7%94%A8-cyltabbarcontroller) - [源码实现原理](#%E6%BA%90%E7%A0%81%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86) - [FAQ](#faq) ## 与其他自定义TabBarController的区别 ## Comparetion with other Libraries [CN]特点

[EN]Features |[CN]解释

[EN]Explanation :-------------:|:-------------: [CN]一行代码支持Lottie动画TabBar样式

[EN] It only needs one line of code to have an animated TabBar with Lottie. |[CN][使用方法]( https://github.com/ChenYilong/CYLTabBarController/issues/341)

[EN][How to add animation of Lottie with one line of code.]( https://github.com/ChenYilong/CYLTabBarController/issues/341)

![https://github.com/ChenYilong](https://tva1.sinaimg.cn/large/006y8mN6ly1g6upmqhqjrg30o209r4qp.gif)

![https://github.com/ChenYilong](https://tva1.sinaimg.cn/large/006y8mN6ly1g6uqohfiw2g30cd03hdop.gif) [CN]低耦合,易删除

[EN]Loose coupling | [CN]1、TabBar设置与业务完全分离,最低只需传两个数组即可完成主流App框架搭建。

[EN]1. This library is independent of your business codes which only needs two array parameters to be passed.

[CN]2、 PlusButton 的所有设置都在单独的一个类( `CYLPlusButton` 的子类)中实现:删除该特定的类,就能完全将 PlusButton 从项目中删除掉。

[EN]2.PlusButton is also independent. If you delete the code of this class, you remove the PlusButton feature from your UI on screen completely. [CN]`TabBar` 以及 `TabBar` 内的 `TabBarItem` 均使用系统原生的控件

[EN]`TabBar` and `TabBarItem` those parts of this library both are system objects. | [CN]因为使用原生的控件,并非 `UIButton` 或 `UIView` 。好处如下:

[EN]Advantages of quitting choosing `UIButton` or `UIView`:

1. 无需反复调“间距位置等”来接近系统效果。

[EN]There is not need to adjust those object to make them close to a system object appearance.

2. 在push到下一页时 `TabBar` 的隐藏和显示之间的过渡效果跟系统一致(详见“ [集成后的效果](https://github.com/ChenYilong/CYLTabBarController#集成后的效果) ”部分,给出了效果图)

[EN]2. A push animation is same to a system objects appearance.

3. 原生控件,所以可以使用诸多系统API,比如:可以使用 ` [UITabBar appearance];` 、` [UITabBarItem appearance];` 设置样式。(详见“[补充说明](https://github.com/ChenYilong/CYLTabBarController#补充说明) ”部分,给出了响应代码示例)

[EN]3.It is convenient to use the system API such as ` [UITabBar appearance];`,` [UITabBarItem appearance];`, etc. 自动监测是否需要添加“加号”按钮,

并能自动设置位置

[EN] It is able to check if need to add a PlusButton automatically. |[CYLTabBarController](https://github.com/ChenYilong/CYLTabBarController) 既支持类似微信的“中规中矩”的 `TabBarController` 样式,并且默认就是微信这种样式,同时又支持类似“微博”或“淘宝闲鱼”这种具有不规则加号按钮的 `TabBarController` 。想支持这种样式,只需自定义一个加号按钮,[CYLTabBarController](https://github.com/ChenYilong/CYLTabBarController) 能检测到它的存在并自动将 `tabBar` 排序好,无需多余操作,并且也预留了一定接口来满足自定义需求。

“加号”按钮的样式、frame均在自定义的类中独立实现,不会涉及tabbar相关设置。 支持动态更新 | 可动态删除PlusButton ,可以动态更新样式

![https://github.com/ChenYilong](https://tva1.sinaimg.cn/large/006y8mN6ly1g6uq38ulz8g30al02w0u1.gif) 即使加号按钮超出了tabbar的区域,

超出部分依然能响应点击事件 | 红线内的区域均能响应tabbar相关的点击事件,

![https://github.com/ChenYilong](https://tva1.sinaimg.cn/large/006y8mN6ly1g6uqi6prqsj30j60g8js7.jpg) 允许指定加号按钮位置 | 效果如下:

![iTeaTime(技术清谈)](https://tva1.sinaimg.cn/large/006y8mN6gy1g92nics1hvj30a906u3ym.jpg)

Airbnb-app效果:

![iTeaTime(技术清谈)](https://tva1.sinaimg.cn/large/006y8mN6gy1g92nir57tmg308w0fsapi.gif) 支持让 `TabBarItem` 仅显示图标,并自动使图标垂直居中,支持自定义TabBar高度 | 效果可见Airbnb-app效果,或者下图

![enter image description here](https://cloud.githubusercontent.com/assets/7238866/10777333/5d7811c8-7d55-11e5-88be-8cb11bbeaf90.png) 支持角标自定义View | ![enter image description here](https://ws4.sinaimg.cn/large/006tKfTcly1fgl0yxcaboj30yi06at8t.jpg) 支持多TabBar嵌套,并指定PlusButton位置 | ![enter image description here](https://ws4.sinaimg.cn/large/006tNc79ly1fmn3005isfg308r0iltl6.gif) 支持CocoaPods |容易集成 支持Swift项目导入 | 兼容 支持横竖屏 | -- (学习交流群:515295083) ## 集成后的效果: 既支持默认样式 | 同时也支持创建自定义的形状不规则加号按钮 -------------|------------ ![https://github.com/ChenYilong](https://tva1.sinaimg.cn/large/006y8mN6ly1g6uqwf0dm7j30ku048glt.jpg)| ![https://github.com/ChenYilong](https://tva1.sinaimg.cn/large/006y8mN6ly1g6uqwv5bptj30ku04a74i.jpg) 支持横竖屏

本仓库配套Demo的效果:| [另一个Demo](https://github.com/ChenYilong/CYLTabBarControllerDemoForWeib)

使用CYLTabBarController实现了微博Tabbar框架,

效果如下 -------------|------------- ![https://github.com/ChenYilong](https://tva1.sinaimg.cn/large/006y8mN6ly1g6usablffxg30ac0j1e81.gif) | ![https://github.com/ChenYilong](https://tva1.sinaimg.cn/large/006y8mN6ly1g6usaqu6ulg30ac0j1ttj.gif) ## 项目结构 ![https://github.com/ChenYilong](https://tva1.sinaimg.cn/large/006y8mN6ly1g6uqzog2wmj30ae0a8js5.jpg) 做下说明: ```Objective-C ├── CYLTabBarController #核心库文件夹,如果不使用 CocoaPods 集成,请直接将这个文件夹拖拽带你的项目中 └── Example └── Classes    ├── Module #模块类文件夹 │   ├── Home │   ├── Message │   ├── Mine    │   └── SameCity    └── View #这里放着 CYLPlusButton 的子类 CYLPlusButtonSubclass,演示了如何创建自定义的形状不规则加号按钮 ``` ## 使用[CYLTabBarController](https://github.com/ChenYilong/CYLTabBarController) 四步完成主流App框架搭建: 1. [ 第一步:使用CocoaPods导入CYLTabBarController ](https://github.com/ChenYilong/CYLTabBarController#第一步使用cocoapods导入cyltabbarcontroller) 2. [第二步:设置CYLTabBarController的两个数组:控制器数组和TabBar属性数组](https://github.com/ChenYilong/CYLTabBarController#第二步设置cyltabbarcontroller的两个数组控制器数组和tabbar属性数组) 3. [第三步:将CYLTabBarController设置为window的RootViewController](https://github.com/ChenYilong/CYLTabBarController#第三步将cyltabbarcontroller设置为window的rootviewcontroller) 4. [第四步(可选):创建自定义的形状不规则加号按钮](https://github.com/ChenYilong/CYLTabBarController#第四步可选创建自定义的形状不规则加号按钮) ### 第一步:使用CocoaPods导入CYLTabBarController 1. CocoaPods 安装   如果您的机器上已经安装了 CocoaPods,直接进入下一步即可。   如果您的网络已经翻墙,在终端中运行如下命令直接安装:   ```   sudo gem install cocoapods   ```   如果您的网络不能翻墙,可以通过国内 Ruby China 的 RubyGems 镜像进行安装。   在终端依次运行以下命令:   ```   gem sources --add https://gems.ruby-china.com/ --remove https://rubygems.org/     sudo gem install cocoapods   ``` 2. 查询 CocoaPods 源中的本库   在终端中运行以下命令:   ```   pod search CYLTabBarController   ```    这里注意,这个命令搜索的是本机上的最新版本,并没有联网查询。如果运行以上命令,没有搜到或者搜不到最新版本,您可以运行以下命令,更新一下您本地的 CocoaPods 源列表。   ```   pod repo update   ``` 3. 使用 CocoaPods 导入   打开终端,进入到您的工程目录,执行以下命令,会自动生成一个 Podfile 文件。   ```   pod init   ```   然后使用 CocoaPods 进行安装。如果尚未安装 CocoaPods,运行以下命令进行安装: ``` gem install cocoapods ```   打开 Podfile,在您项目的 target 下加入以下内容。(此处示例可能是旧版本,使用时请替换为最新版,最新版信息可以从这里获取:)   在文件 `Podfile` 中加入以下内容: ``` pod 'CYLTabBarController', '~> 1.24.0' ```   然后在终端中运行以下命令: ``` pod install ```   或者这个命令: ``` # 禁止升级 CocoaPods 的 spec 仓库,否则会卡在 Analyzing dependencies,非常慢 pod update --verbose --no-repo-update ```   如果提示找不到库,则可去掉 `--no-repo-update`。   完成后1.24.0,CocoaPods 会在您的工程根目录下生成一个 `.xcworkspace` 文件。您需要通过此文件打开您的工程,而不是之前的 `.xcodeproj`。 **CocoaPods 使用说明** **指定 CYLTabBarController 版本** CocoaPods 中,有几种设置 CYLTabBarController 版本的方法。如: `>= 1.n.X` 会根据您本地的 CocoaPods 源列表,导入不低于 `1.(n+1).X` 版本的 CYLTabBarController。 `~> 1.n.X` 会根据您本地的 CocoaPods 源列表,介于 1.n.X~1.(n+1).0 之前版本的 CYLTabBarController。 建议选择后者:锁定版本,便于团队开发。如: (此处示例可能是旧版本,使用时请替换为最新版,最新版信息可以从这里获取:) ``` pod 'CYLTabBarController', '~> 1.24.0' ``` - 升级本地 CocoaPods 源   `CocoaPods 有一个中心化的源,默认本地会缓存 CocoaPods 源服务器上的所有 CYLTabBarController 版本。 如果搜索的时候没有搜到或者搜不到最新版本,可以执行以下命令更新一下本地的缓存。 ``` pod repo update ``` - 升级工程的 CYLTabBarController 版本 更新您工程目录中 Podfile 指定的 CYLTabBarController 版本后,在终端中执行以下命令。 ``` pod update ``` - 清除 Cocoapods 本地缓存 特殊情况下,由于网络或者别的原因,通过 CocoaPods 下载的文件可能会有问题。 这时候您可以删除 CocoaPods 的缓存(~/Library/Caches/CocoaPods/Pods/Release 目录),再次导入即可。 - 查看当前使用的 CYLTabBarController 版本 您可以在 Podfile.lock 文件中看到您工程中使用的 CYLTabBarController 版本。 关于 CocoaPods 的更多内容,您可以参考 [CocoaPods 文档](https://cocoapods.org/)。 ### 第二步:设置CYLTabBarController的两个数组:控制器数组和TabBar属性数组 ```Objective-C //MainTabBarController @interface MainTabBarController : CYLTabBarController @end - (instancetype)init { if (!(self = [super init])) { return nil; } /** * 以下两行代码目的在于手动设置让TabBarItem只显示图标,不显示文字,并让图标垂直居中。 * 等效于在 `-tabBarItemsAttributesForController` 方法中不传 `CYLTabBarItemTitle` 字段。 * 更推荐后一种做法。 */ UIEdgeInsets imageInsets = UIEdgeInsetsZero;//UIEdgeInsetsMake(4.5, 0, -4.5, 0); UIOffset titlePositionAdjustment = UIOffsetMake(0, -3.5); CYLTabBarController *tabBarController = [CYLTabBarController tabBarControllerWithViewControllers:self.viewControllers tabBarItemsAttributes:self.tabBarItemsAttributesForController imageInsets:imageInsets titlePositionAdjustment:titlePositionAdjustment context:nil ]; [self customizeTabBarAppearance:tabBarController]; self.navigationController.navigationBar.hidden = YES; return (self = (MainTabBarController *)tabBarController); } - (NSArray *)viewControllers { CYLHomeViewController *firstViewController = [[CYLHomeViewController alloc] init]; UIViewController *firstNavigationController = [[CYLBaseNavigationController alloc] initWithRootViewController:firstViewController]; [firstViewController cyl_setHideNavigationBarSeparator:YES]; CYLSameCityViewController *secondViewController = [[CYLSameCityViewController alloc] init]; UIViewController *secondNavigationController = [[CYLBaseNavigationController alloc] initWithRootViewController:secondViewController]; [secondViewController cyl_setHideNavigationBarSeparator:YES]; NSArray *viewControllers = @[ firstNavigationController, secondNavigationController, ]; return viewControllers; } - (NSArray *)tabBarItemsAttributesForController { NSDictionary *firstTabBarItemsAttributes = @{ CYLTabBarItemTitle : @"首页", CYLTabBarItemImage : self.darkMode ? @"home_highlight" : @"home_normal", /* NSString and UIImage are supported*/ CYLTabBarItemSelectedImage : @"home_highlight", /* NSString and UIImage are supported*/ }; NSDictionary *secondTabBarItemsAttributes = @{ CYLTabBarItemTitle : @"鱼塘", CYLTabBarItemImage : self.darkMode ? @"fishpond_highlight" : @"fishpond_normal", CYLTabBarItemSelectedImage : @"fishpond_highlight", }; NSArray *tabBarItemsAttributes = @[ firstTabBarItemsAttributes, secondTabBarItemsAttributes, ]; return tabBarItemsAttributes; } ``` 在这个字典中,`CYLTabBarItemImage` 和 `CYLTabBarItemSelectedImage` 支持 `NSString`、`UIImage` 两种格式。`CYLTabBarItemTitle` 不设置将只展示图标,并会对布局作出居中处理。 ### 第三步:将CYLTabBarController设置为window的RootViewController ```Objective-C - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { /* *省略部分: * */ [self.window setRootViewController:self.tabBarController]; /* *省略部分: * */ return YES; } ``` 或者将 CYLTabBarController 的子类设为 RootViewCOntroller ,也可以将CYLTabBarController子类的 NavigationViewController 作为 RootViewCOntroller,方便动态更新,Demo 中就是采用后者。 ### 第四步(可选):创建自定义的形状不规则加号按钮 创建一个继承于 CYLPlusButton 的类,要求和步骤: 1. 实现 `CYLPlusButtonSubclassing` 协议 2. 子类将自身类型进行注册:调用 `[YourClass registerPlusButton]`,需要在 RootViewCOntroller 的 ViewDidLoad 中注册,也可以在 `-application:didFinishLaunchingWithOptions:` 方法里面操作。 这里注意,不建议在子类的 `+load` 方法中调用,比如像下面这样做,在 iOS10 系统上有 Crash 的风险: ```Objective-C + (void)load { [super registerPlusButton]; } ``` 协议提供了可选方法: ```Objective-C + (NSUInteger)indexOfPlusButtonInTabBar; + (CGFloat)multiplierOfTabBarHeight:(CGFloat)tabBarHeight; + (UIViewController *)plusChildViewController; + (BOOL)shouldSelectPlusChildViewController; ``` 作用分别是: ```Objective-C + (NSUInteger)indexOfPlusButtonInTabBar; ``` 用来自定义加号按钮的位置,如果不实现默认居中,但是如果 `tabbar` 的个数是奇数则必须实现该方法,否则 `CYLTabBarController` 会抛出 `exception` 来进行提示。 主要适用于如下情景:

Airbnb-app效果:

```Objective-C + (CGFloat)multiplierOfTabBarHeight:(CGFloat)tabBarHeight; ``` 该方法是为了调整自定义按钮中心点Y轴方向的位置,建议在按钮超出了 `tabbar` 的边界时实现该方法。返回值是自定义按钮中心点Y轴方向的坐标除以 `tabbar` 的高度,如果不实现,会自动进行比对,预设一个较为合适的位置,如果实现了该方法,预设的逻辑将失效。 内部实现时,会使用该返回值来设置 PlusButton 的 centerY 坐标,公式如下: `PlusButtonCenterY = multiplierOfTabBarHeight * taBarHeight + constantOfPlusButtonCenterYOffset;` 也就是说:如果 constantOfPlusButtonCenterYOffset 为0,同时 multiplierOfTabBarHeight 的值是0.5,表示 PlusButton 居中,小于0.5表示 PlusButton 偏上,大于0.5则表示偏下。 ```Objective-C + (CGFloat)constantOfPlusButtonCenterYOffsetForTabBarHeight:(CGFloat)tabBarHeight; ``` 参考 `+multiplierOfTabBarHeight:` 中的公式: `PlusButtonCenterY = multiplierOfTabBarHeight * taBarHeight + constantOfPlusButtonCenterYOffset;` 也就是说: constantOfPlusButtonCenterYOffset 大于0会向下偏移,小于0会向上偏移。 注意:实现了该方法,但没有实现 `+multiplierOfTabBarHeight:` 方法,在这种情况下,会在预设逻辑的基础上进行偏移。 详见Demo中的 `CYLPlusButtonSubclass` 类的实现。 ```Objective-C + (UIViewController *)plusChildViewController; ``` 详见: [点击 PlusButton 跳转到指定 UIViewController](https://github.com/ChenYilong/CYLTabBarController#点击-plusbutton-跳转到指定-uiviewcontroller) 另外,如果加号按钮超出了边界,一般需要手动调用如下代码取消 tabbar 顶部默认的阴影,可在 AppDelegate 类中调用: ```Objective-C //去除 TabBar 自带的顶部阴影 [[UITabBar appearance] setShadowImage:[[UIImage alloc] init]]; ``` // iOS10 后 需要使用 `-[CYLTabBarController hideTabBarShadowImageView]` 见 AppDelegate 类中的演示; 如何调整、自定义 `PlusButton` 与其它 `TabBarItem` 的宽度? `CYLTabBarController` 规定: ```Objective-C TabBarItem 宽度 = ( TabBar 总宽度 - PlusButton 宽度 ) / (TabBarItem 个数) ``` 所以想自定义宽度,只需要修改 `PlusButton` 的宽度即可。 比如你就可以在 Demo中的 `CYLPlusButtonSubclass.m` 类里: 把 ```Objective-C [button sizeToFit]; ``` 改为 ```Objective-C button.frame = CGRectMake(0.0, 0.0, 250, 100); button.backgroundColor = [UIColor redColor]; ``` 效果如下, 1.24.0

同时你也可以顺便测试下 `CYLTabBarController` 的这一个特性: > 即使加号按钮超出了tabbar的区域,超出部分依然能响应点击事件 并且你可以在项目中的任意位置读取到 `PlusButton` 的宽度,借助 `CYLTabBarController.h` 定义的 `CYLPlusButtonWidth` 这个extern。可参考 `+[CYLTabBarControllerConfig customizeTabBarAppearance:]` 里的用法。 ## 补充说明 ### 自定义 `TabBar` 样式 如果想更进一步的自定义 `TabBar` 样式可在 `-application:didFinishLaunchingWithOptions:` 方法中设置 ```Objective-C /** * tabBarItem 的选中和不选中文字属性、背景图片 */ - (void)customizeInterface { // 普通状态下的文字属性 NSMutableDictionary *normalAttrs = [NSMutableDictionary dictionary]; normalAttrs[NSForegroundColorAttributeName] = [UIColor grayColor]; // 选中状态下的文字属性 NSMutableDictionary *selectedAttrs = [NSMutableDictionary dictionary]; selectedAttrs[NSForegroundColorAttributeName] = [UIColor darkGrayColor]; // 设置文字属性 UITabBarItem *tabBar = [UITabBarItem appearance]; [tabBar setTitleTextAttributes:normalAttrs forState:UIControlStateNormal]; [tabBar setTitleTextAttributes:selectedAttrs forState:UIControlStateSelected]; // 设置背景图片 UITabBar *tabBarAppearance = [UITabBar appearance]; [tabBarAppearance setBackgroundImage:[UIImage imageNamed:@"tabbar_background"]]; } - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { /* *省略部分: * */ [self.window makeKeyAndVisible]; [self customizeInterface]; return YES; } ``` #### 捕获 TabBar 点击事件 实现 CYLTabBarController 的如下几个代理方法即可捕获点击事件。 下面这个方法能捕获当前点击的 `TabBar` 上的控件,可以是 `UITabBarButton`、也可以 `PlusButton`、也可以是添加到 `TabBar` 上的任意 `UIControl` 的子类。但是如果 `PlusButton` 也添加了点击事件,那么点击 `PlusButton` 将不会被触发这个代理方法。 ```Objective-C //CYLTabBarController.h @protocol CYLTabBarControllerDelegate /*! * @param tabBarController The tab bar controller containing viewController. * @param control Selected UIControl in TabBar. * @attention If PlusButton also add an action, then this delegate method will not be invoked when the PlusButton is selected. */ - (void)tabBarController:(UITabBarController *)tabBarController didSelectControl:(UIControl *)control; @end ``` 下面这个方法能捕获跳转前所在的控制器,以及跳转到的目标控制器。 ```Objective-C //UITabBarController.h @protocol UITabBarControllerDelegate @optional - (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController NS_AVAILABLE_IOS(3_0); @end ``` 注意:在调用该方法时应该始终调用 ` [[self cyl_tabBarController] updateSelectionStatusIfNeededForTabBarController:tabBarController shouldSelectViewController:viewController];` 来确保 `PlusButton` 的选中状态。示例如下: ```Objective-C - (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController { [[self cyl_tabBarController] updateSelectionStatusIfNeededForTabBarController:tabBarController shouldSelectViewController:viewController]; return YES; } ``` 相关用法已经在 Demo 中展示。 遵循协议的方式如下: ```Objective-C @interface AppDelegate () @end - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { //... tabBarControllerConfig.tabBarController.delegate = self; //... return YES; } ``` ### 点击 TabBarButton 时添加动画 Demo 演示的效果图:

实现如下代理方法,就能得到对应的选中控件,可以在控件上直接添加动画。 ```Objective-C //CYLTabBarController.h @protocol CYLTabBarControllerDelegate /*! * @param tabBarController The tab bar controller containing viewController. * @param control Selected UIControl in TabBar. */ - (void)tabBarController:(UITabBarController *)tabBarController didSelectControl:(UIControl *)control; @end ``` Demo 中示例代码如下: 遵循协议 ```Objective-C @interface AppDelegate () @end ``` ```Objective-C //AppDelegate.m - (void)tabBarController:(UITabBarController *)tabBarController didSelectControl:(UIControl *)control { UIView *animationView; // 如果 PlusButton 也添加了点击事件,那么点击 PlusButton 后不会触发该代理方法。 if ([control isKindOfClass:[CYLExternPlusButton class]]) { UIButton *button = CYLExternPlusButton; animationView = button.imageView; } else if ([control isKindOfClass:NSClassFromString(@"UITabBarButton")]) { for (UIView *subView in control.subviews) { if ([subView isKindOfClass:NSClassFromString(@"UITabBarSwappableImageView")]) { animationView = subView; } } } if ([self cyl_tabBarController].selectedIndex % 2 == 0) { [self addScaleAnimationOnView:animationView]; } else { [self addRotateAnimationOnView:animationView]; } } //缩放动画 - (void)addScaleAnimationOnView:(UIView *)animationView { //需要实现的帧动画,这里根据需求自定义 CAKeyframeAnimation *animation = [CAKeyframeAnimation animation]; animation.keyPath = @"transform.scale"; animation.values = @[@1.0,@1.3,@0.9,@1.15,@0.95,@1.02,@1.0]; animation.duration = 1; animation.calculationMode = kCAAnimationCubic; [animationView.layer addAnimation:animation forKey:nil]; } //旋转动画 - (void)addRotateAnimationOnView:(UIView *)animationView { [UIView animateWithDuration:0.32 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{ animationView.layer.transform = CATransform3DMakeRotation(M_PI, 0, 1, 0); } completion:nil]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [UIView animateWithDuration:0.70 delay:0 usingSpringWithDamping:1 initialSpringVelocity:0.2 options:UIViewAnimationOptionCurveEaseOut animations:^{ animationView.layer.transform = CATransform3DMakeRotation(2 * M_PI, 0, 1, 0); } completion:nil]; }); } ``` ### 横竖屏适配 `TabBar` 横竖屏适配时,如果你添加了 `PlusButton`,且适配时用到了 `TabBarItem` 的宽度, 不建议使用系统的`UIDeviceOrientationDidChangeNotification` , 请使用库里的 `CYLTabBarItemWidthDidChangeNotification` 来更新 `TabBar` 布局,最典型的场景就是,根据 `TabBarItem` 在不同横竖屏状态下的宽度变化来切换选中的`TabBarItem` 的背景图片。Demo 里 `CYLTabBarControllerConfig.m` 给出了这一场景的用法: `CYLTabBarController.h` 中提供了 `CYLTabBarItemWidth` 这一extern常量,并且会在 `TabBarItem` 的宽度发生变化时,及时更新该值,所以用法就如下所示: ```Objective-C - (void)updateTabBarCustomizationWhenTabBarItemWidthDidUpdate { void (^deviceOrientationDidChangeBlock)(NSNotification *) = ^(NSNotification *notification) { [self tabBarItemWidthDidUpdate]; }; [[NSNotificationCenter defaultCenter] addObserverForName:CYLTabBarItemWidthDidChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:deviceOrientationDidChangeBlock]; } - (void)tabBarItemWidthDidUpdate { UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation]; if ((orientation == UIDeviceOrientationLandscapeLeft) || (orientation == UIDeviceOrientationLandscapeRight)) { NSLog(@"Landscape Left or Right !"); } else if (orientation == UIDeviceOrientationPortrait){ NSLog(@"Landscape portrait!"); } CGSize selectionIndicatorImageSize = CGSizeMake(CYLTabBarItemWidth, [self cyl_tabBarController].tabBar.bounds.size.height); [[self cyl_tabBarController].tabBar setSelectionIndicatorImage:[[self class] imageFromColor:[UIColor yellowColor] forSize:selectionIndicatorImageSize withCornerRadius:0]]; } ```

### 访问初始化好的 CYLTabBarController 对象 对于任意 `NSObject` 对象: `CYLTabBarController.h` 中为 `NSObject` 提供了分类方法 `-cyl_tabBarController` ,所以在任意对象中,一行代码就可以访问到一个初始化好的 `CYLTabBarController` 对象,`-cyl_tabBarController` 的作用你可以这样理解:与获取单例对象的 `+shareInstance` 方法作用一样。 接口如下: ```Objective-C // CYLTabBarController.h @interface NSObject (CYLTabBarController) /** * If `self` is kind of `UIViewController`, this method will return the nearest ancestor in the view controller hierarchy that is a tab bar controller. If `self` is not kind of `UIViewController`, it will return the `rootViewController` of the `rootWindow` as long as you have set the `CYLTabBarController` as the `rootViewController`. Otherwise return nil. (read-only) */ @property (nonatomic, readonly) CYLTabBarController *cyl_tabBarController; @end ``` 用法: ```Objective-C //导入 CYLTabBarController.h #import "CYLTabBarController.h" - (void)viewDidLoad { [super viewDidLoad]; CYLTabBarController *tabbarController = [self cyl_tabBarController]; /*...*/ } ``` ### 点击 PlusButton 跳转到指定 UIViewController 提供了一个协议方法来完成本功能:

实现该方法后,能让 PlusButton 的点击效果与跟点击其他 TabBar 按钮效果一样,跳转到该方法指定的 UIViewController 。 注意:必须同时实现 `+indexOfPlusButtonInTabBar` 来指定 PlusButton 的位置。 遵循几个协议: ```Objective-C #pragma mark - CYLPlusButtonSubclassing + (UIViewController *)plusChildViewController { UIViewController *plusChildViewController = [[UIViewController alloc] init]; plusChildViewController.view.backgroundColor = [UIColor redColor]; plusChildViewController.navigationItem.title = @"PlusChildViewController"; UIViewController *plusChildNavigationController = [[UINavigationController alloc] initWithRootViewController:plusChildViewController]; return plusChildNavigationController; } + (NSUInteger)indexOfPlusButtonInTabBar { return 2; } + (BOOL)shouldSelectPlusChildViewController { BOOL isSelected = CYLExternPlusButton.selected; if (isSelected) { // HDLLogDebug("🔴类名与方法名:%@(在第%@行),描述:%@", @(__PRETTY_FUNCTION__), @(__LINE__), @"PlusButton is selected"); } else { // HDLLogDebug("🔴类名与方法名:%@(在第%@行),描述:%@", @(__PRETTY_FUNCTION__), @(__LINE__), @"PlusButton is not selected"); } return YES; } + (CGFloat)multiplierOfTabBarHeight:(CGFloat)tabBarHeight { return 0.3; } + (CGFloat)constantOfPlusButtonCenterYOffsetForTabBarHeight:(CGFloat)tabBarHeight { return (CYL_IS_IPHONE_X ? - 6 : 4); } //+ (NSString *)tabBarContext { // return NSStringFromClass([self class]); //} ``` 另外你可以通过下面这个方法获取到 `PlusButton` 的点击事件: ```Objective-C + (BOOL)shouldSelectPlusChildViewController; ``` 用法如下: ```Objective-C + (BOOL)shouldSelectPlusChildViewController { BOOL isSelected = CYLExternPlusButton.selected; if (isSelected) { NSLog(@"🔴类名与方法名:%@(在第%@行),描述:%@", @(__PRETTY_FUNCTION__), @(__LINE__), @"PlusButton is selected"); } else { NSLog(@"🔴类名与方法名:%@(在第%@行),描述:%@", @(__PRETTY_FUNCTION__), @(__LINE__), @"PlusButton is not selected"); } return YES; } ``` ### 让TabBarItem仅显示图标,并使图标垂直居中 要想实现该效果,只需要在设置 `tabBarItemsAttributes`该属性时不传 title 即可。 比如:在Demo的基础上,注释掉图中红框部分:

注释前 | 注释后 -------------|------------- ![https://github.com/ChenYilong](https://tva1.sinaimg.cn/large/006y8mN6ly1g6urbvymxij30yi05g74r.jpg)|![https://github.com/ChenYilong](https://tva1.sinaimg.cn/large/006y8mN6ly1g6urc80bdoj30yi05iq3b.jpg) 可以通过这种方式来达到 Airbnb-app 的效果:

如果想手动设置偏移量来达到该效果: 可以在 `-setViewControllers:` 方法前设置 `CYLTabBarController` 的 `imageInsets` 和 `titlePositionAdjustment` 属性 这里注意:设置这两个属性后,`TabBar` 中所有的 `TabBarItem` 都将被设置。并且第一种做法的逻辑将不会执行,也就是说该做法优先级要高于第一种做法。 做法在demo中已经给出。 但是想达到Airbnb-app的效果只有这个接口是不行的,还需要自定义下 `TabBar` 的高度,你需要设置 `CYLTabBarController` 的 `tabBarHeight` 属性。你可以在Demo的 `CYLTabBarControllerConfig.m` 中的 `-customizeTabBarAppearance:` 方法中设置。 注:“仅显示图标,并使图标垂直居中”这里所指的“图标”,其所属的类是私有类: `UITabBarSwappableImageView`,所以 `CYLTabBarController` 在相关的接口命名时会包含 `SwappableImageView` 字样。另外,使用该特性需要 `pod update` 到 1.5.5以上的版本。 ### 多TabBar嵌套,并指定PlusButton位置 该功能旧版本可能并不支持,建议更新最新版中使用。 效果图:

实现 PlusButton 的如下协议方法指定 context: ```Objective-C //CYLPlusButtonSubclassing + (NSString *)tabBarContext; ``` 当该值与 TabBarController 的 context 能够匹配上,PlusButton 将会展示。如果 PlusButton 与 TabBarController 均未制定 context 值,那么默认 context 值是相等的。 目前仅支持一个 PlusButton 展示一次,不限层级。如果与多个 TabBarController 的 context 能够匹配上,仅展示在最先一次的匹配上的 TabBarController 上。 ### 在 Swift 项目中使用 CYLTabBarController 仓库中给出了一个Swift Demo,文件夹叫做 Example-Swift。 如果想在Swift 项目中,将本库作为静态库使用: CocoaPods 1.5.0+ (with Xcode 9+): ```Objective-C platform :ios, '8.0' # Uncomment the next line when you want all Pods as static framework # use_modular_headers! pod 'CYLTabBarController', '~> 1.29.0', :modular_headers => true ``` 作为动态库使用: ```Objective-C platform :ios, '8.0' use_frameworks! ``` 感谢[@WeMadeCode](https://github.com/WeMadeCode) 提供的 Swift 版 Demo,原仓库地址:[WeMadeCode/CYLTabBarController-Swift](https://github.com/WeMadeCode/CYLTabBarController-Swift) 具体的编写步骤参考热心网友提供的教程: [《从头开始swift2.1 仿搜材通项目(三) 主流框架Tabbed的搭建》]( http://www.jianshu.com/p/c5bc2eae0f55?nomobile=yes ) 这里注意,文章的早期一个版本的示例代码有问题(笔者注:现在已经更新了),少了设置 PlusButton 大小的代码: 这将导致 PlusButton 点击事件失效,具体修改代码如下:

### 搭配 Storyboard 使用 CYLTabBarController 参考: - 见这里 [issue讨论]( https://github.com/ChenYilong/CYLTabBarController/issues/170 ) - [这里](https://github.com/ChenYilong/CYLDeallocBlockExecutor) ,里面有个文件夹CYLTabBarControllerTestDemo,这个Demo演示了如何搭配 Storyboard 使用。 ### 源码实现原理 参考: [《[Note] CYLTabBarController》]( http://www.jianshu.com/p/8758d8014f86 ) 更多文档信息可查看 [ ***CocoaDocs:CYLTabBarController*** ](http://cocoadocs.org/docsets/CYLTabBarController/1.2.1/index.html) 。 ## FAQ 更多Q-A内容,可以在这里查看: [issue-FAQ](https://github.com/ChenYilong/CYLTabBarController/issues?utf8=✓&q=+label%3AQ-A+) Q:为什么放置6个TabBarItem会显示异常? A: Apple 规定: > 一个 `TabBar` 上只能出现最多5个 `TabBarItem` ,第六个及更多的将不被显示。 另外注意,Apple检测的是 `UITabBarItem` 及其子类,所以放置“加号按钮”,这是 `UIButton` 不在“5个”里面。 最多只能添加5个 `TabBarItem` ,也就是说加上“加号按钮”,一共最多在一个 `TabBar` 上放置6个控件。否则第6个及之后出现 `TabBarItem` 会被自动屏蔽掉。而且就Apple的审核机制来说,超过5个也会被直接拒绝上架。 Q:我把 demo 两侧的 item 各去掉一个后,按钮的响应区域就变成下图的样子了:

A:v1.5.5 版本已经修复了该问题,现在不会出现类似的问题了:点击按钮区域却不响应,响应区域有偏移。 Q: 如何实现添加选中背景色的功能 ,像下面这样:

A:我已经在 Demo 中添加了如何实现该功能的代码: 详情见 `CYLTabBarControllerConfig` 类中下面方法的实现: ```Objective-C /** * 更多TabBar自定义设置:比如:tabBarItem 的选中和不选中文字和背景图片属性、tabbar 背景图片属性 */ - (void)customizeTabBarAppearance:(CYLTabBarController *)tabBarController; ``` 效果如下:

Q: 当 `ViewController` 设置的 `self.title` 和 `tabBarItemsAttributes` 中对应的 `title` 不一致的时候,会出现如图的错误,排序不对了 A:在 v1.0.7 版本中已经修复了该 bug,但是也需要注意: 请勿使用 `self.title = @"同城"; ` 这种方式,请使用 `self.navigationItem.title = @"同城"; ` `self.title = @"同城"; ` 这种方式,如果和 `tabBarItemsAttributes` 中对应的 `title` 不一致的时候可能会导致如下现象(不算 bug,但看起来也很奇怪):

规则如下: ```Objective-C self.navigationItem.title = @"同城"; //✅sets navigation bar title.The right way to set the title of the navigation self.tabBarItem.title = @"同城"; //❌sets tab bar title. Even the `tabBarItem.title` changed, this will be ignored in tabbar. self.title = @"同城1"; //❌sets both of these. Do not do this‼️‼️ This may cause something strange like this : http://i68.tinypic.com/282l3x4.jpg ``` Q : 当使用这个方法时 `-[UIViewController cyl_popSelectTabBarChildViewControllerAtIndex:]` 系列方法时,会出现如下的黑边问题。

A: 这个是 iOS 系统的BUG,经测试iOS9.3已经修复了,如果在更早起版本中出现了,可以通过下面将 `rootWindow` 的背景色改为白色来避免:比如你可以 `Appdelegate` 类里这样设置: ```Objective-C //#import "CYLTabBarController.h" [[self cyl_tabBarController] rootWindow].backgroundColor = [UIColor whiteColor]; ``` Q:我现在已经做好了一个比较简单的中间凸起的 icon 但是超过了49这个高度的位置是不能效应的 我想请问你的demo哪个功能是可以使我超出的范围也可以响应的呢? A: 这个是自动做的,但是 `CYLTabBarController` 只能保证的是:只要是 `UIButton` 的 frame 区域内就能响应。 请把 button 的背景颜色设置为显眼的颜色,比如红色,比如像下面的plus按钮,红色部分是能接收点击事件的,但是超出了红色按钮的,黄色的图片区域,依然是无法响应点击事件的。

这是因为,在响应链上,`UIControl` 能响应点击事件, `UIImage` 无法响应。 Q:为什么在iOS10上会Crash,iOS9上不会? A: 在注册加号按钮时,需要在 `-application:didFinishLaunchingWithOptions:` 方法里面调用 `[YourClass registerPlusButton]` 这里注意,不能在子类的 `+load` 方法中调用,比如像下面这样做,在 iOS10 系统上有 Crash 的风险: ```Objective-C + (void)load { [super registerPlusButton]; } ``` Q: 我的样式是点击 `plusButton` 后跳转到一个 `ViewController`,但是选中了一次中间的 `plusButton` 之后,再点别的 `tabItem` ,中间不会变成 `normal` 的状态。 A: 有两种情况会造成这个问题: 1. 应该是你的 `tabBar` 设置了 `delegate` 了,你要是 `tabBar` 的代理没设置的话,默认会有这个 `selected` 状态切换的处理。你设置代理后,会覆盖我的行为。所以手动加上就好了。 ```Objective-C - (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController { [[self cyl_tabBarController] updateSelectionStatusIfNeededForTabBarController:tabBarController shouldSelectViewController:viewController]; return YES; } ``` 2. `plusButton` 添加了自定义点击事件或者自定义手势,因为这样会造成点击事件冲突或手势冲突,当需要 `pushViewController` 的时候,这个库会自动的添加点击事件,你这里重新加了点击事件所以冲突了; 在你项目的基础,把 `plusButton` 的点击事件取消掉,也就是 `addTarget` 这一行注释掉,手势事件也同理,应该就ok了 A: `PlusButton` 与其他的 `TabBarItem` 距离没有平均分布 (对应于 [issue#36](https://github.com/ChenYilong/CYLTabBarController/issues/36#issuecomment-269165471) ) 把这 Demo 里的这一行代码改下: ```Objective-C [button sizeToFit]; ``` 改成: ```Objective-C button.frame = CGRectMake(0.0, 0.0, w, h); ``` 那么如果单是放一个照相机的图片,一般是多大的尺寸? 这个要看设计图,通常情况下,你可以写死与其他TabBarItem一样大小: ```Objective-C [UIScreen mainScreen].bounds.size.width / [CYLTabBarController allItemsInTabBarCount] ``` Q:如何兼容 Lottie 动画? A:用法见:https://github.com/ChenYilong/CYLTabBarController/issues/341 ## Star History [![Star History Chart](https://api.star-history.com/svg?repos=ChenYilong/CYLTabBarController&type=Date)](https://star-history.com/#ChenYilong/CYLTabBarController&Date) (更多iOS开发干货,欢迎关注 [微博@iOS程序犭袁](http://weibo.com/luohanchenyilong/) ) -------------------------------------------- Posted by Posted by [微博@iOS程序犭袁](http://weibo.com/luohanchenyilong/) & [公众号@iTeaTime技术清谈](https://mp.weixin.qq.com/s/A4e5h3xgIEh6PInf1Rjqsw) 原创作品,版权声明:License MIT

================================================ FILE: package.json ================================================ { "name": "CYLTabBarController", "version": "1.0.0", "description": "

", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "repository": { "type": "git", "url": "git+https://github.com/ChenYilong/CYLTabBarController.git" }, "keywords": [], "author": "", "license": "ISC", "bugs": { "url": "https://github.com/ChenYilong/CYLTabBarController/issues" }, "homepage": "https://github.com/ChenYilong/CYLTabBarController#readme", "config": { "commitizen": { "path": "cz-conventional-changelog" } } }