Showing preview only (608K chars total). Download the full file or copy to clipboard to get everything.
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
---
<p align="center"><a href="https://github.com/ChenYilong/CYLTabBarController"><img src="https://repository-images.githubusercontent.com/44896762/c1d6e880-a8d8-11e9-8bb4-2da8ebc06f0a"></a></p>
--------------------------------------------
<p align="center">
<a href="https://github.com/ChenYilong/CYLTabBarController/blob/master/CYLTabBarController.podspec"><img src="https://img.shields.io/badge/Pod-GetLatestVersion-green.svg?style=flat"></a>
<a href=""><img src="https://img.shields.io/badge/Swift-compatible-orange.svg"></a>
<a href=""><img src="https://img.shields.io/badge/platform-iOS%208.0%2B-ff69b5152950834.svg"></a>
<a href="https://github.com/ChenYilong/CYLTabBarController/blob/master/LICENSE"><img src="https://img.shields.io/badge/license-MIT-green.svg?style=flat"></a>
</p>
<p align="center">
<a href="https://github.com/ChenYilong/iOSBlog/issues/21"><img src="https://img.shields.io/static/v1.svg?label=QQ%E3%80%81Telegram%20Group&color=blue&message=%E7%82%B9%E5%87%BB%E8%8E%B7%E5%8F%96QQ%E3%80%81Telegram%E7%BE%A4%E4%BF%A1%E6%81%AF&color=green"></a>
</p>
<p align="center">
<a href="https://github.com/ChenYilong/CYLTabBarController/releases.atom"><img src="https://img.shields.io/badge/RSS feed (full text feed)-订阅仓库版本更新-yellow.svg"></a>
</p>
<p align="center">
<a href="https://github.com/ChenYilong/iOSBlog/releases.atom"><img src="https://img.shields.io/badge/RSS feed (full text feed)-订阅我的博客更新-yellow.svg"></a>
</p>
<p align="center"><a href="https://mp.weixin.qq.com/s/A4e5h3xgIEh6PInf1Rjqsw"><img src="http://ww4.sinaimg.cn/large/006tNc79ly1g5zsnmaw40g30go04ck08.gif"></a></p>
<p align="center">
<a href="http://ww2.sinaimg.cn/large/006tNc79ly1g5et6q6sm5j30go0goaar.jpg"><img src="http://ww1.sinaimg.cn/large/006tNc79ly1g5esb5j4oaj300w00rdfn.jpg"></a>
<a href="http://weibo.com/luohanchenyilong"><img src="https://tva1.sinaimg.cn/large/006y8mN6ly1g6um2edt3jj300w00q3y9.jpg"></a>
<a href="https://twitter.com/iOSChenYilong"><img src="http://ww3.sinaimg.cn/large/006tNc79ly1g5erhikv2kj300w00wgld.jpg"></a>
<a href="https://github.com/ChenYilong"><img src="http://ww3.sinaimg.cn/large/006tNc79gy1g5ercvzgxzj300w00wmwx.jpg"></a>
<a href="https://qm.qq.com/cgi-bin/qm/qr?k=SEdIYBh52YzquCEo8cmPwgkko1VgSAlw&authKey=sGcG%2BGB81DW%2Ba8v3dCufFSNoxhykAU61Uz%2B%2BqDiKQN2BGHP2xHYVI2tc0Cah2lpu"><img src="http://ww1.sinaimg.cn/large/006tNc79ly1g5euf38fedj300w00wjr5.jpg"></a>
<a href="https://t.me/iosobjc"><img src="http://ww2.sinaimg.cn/large/006tNc79ly1g5eus39934j300w00w0r1.jpg"></a>
<a href="http://s.zhihu.com/BU5Mp"><img src="http://ww4.sinaimg.cn/large/006tNc79ly1g5eu9melwaj300w00w3ya.jpg"></a>
</p>
--------------------------------------------
## 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.
<!--- 尽量提供一个可以复现的Demo,我的邮箱:luohanchenyilong@163.com。或者前往 Telegram 群交流:https://t.me/iosobjc -->
## 4. Here is my Debug log
<!--- 请尽量提供详细的日志打印信息,控制台默认会有网络请求的打印信息,请将相关的日志贴出-->
----------
<p align="center"><a href="http://weibo.com/u/1692391497?s=6uyXnP" target="_blank"><img border="0" src="http://service.t.sina.com.cn/widget/qmd/1692391497/b46c844b/1.png"/></a></a>
================================================
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
---
<p align="center"><a href="https://github.com/ChenYilong/CYLTabBarController"><img src="https://repository-images.githubusercontent.com/44896762/c1d6e880-a8d8-11e9-8bb4-2da8ebc06f0a"></a></p>
--------------------------------------------
<p align="center">
<a href="https://github.com/ChenYilong/CYLTabBarController/blob/master/CYLTabBarController.podspec"><img src="https://img.shields.io/badge/Pod-GetLatestVersion-green.svg?style=flat"></a>
<a href=""><img src="https://img.shields.io/badge/Swift-compatible-orange.svg"></a>
<a href=""><img src="https://img.shields.io/badge/platform-iOS%208.0%2B-ff69b5152950834.svg"></a>
<a href="https://github.com/ChenYilong/CYLTabBarController/blob/master/LICENSE"><img src="https://img.shields.io/badge/license-MIT-green.svg?style=flat"></a>
</p>
<p align="center">
<a href="https://github.com/ChenYilong/iOSBlog/issues/21"><img src="https://img.shields.io/static/v1.svg?label=QQ%E3%80%81Telegram%20Group&color=blue&message=%E7%82%B9%E5%87%BB%E8%8E%B7%E5%8F%96QQ%E3%80%81Telegram%E7%BE%A4%E4%BF%A1%E6%81%AF&color=green"></a>
</p>
<p align="center">
<a href="https://github.com/ChenYilong/CYLTabBarController/releases.atom"><img src="https://img.shields.io/badge/RSS feed (full text feed)-订阅仓库版本更新-yellow.svg"></a>
</p>
<p align="center">
<a href="https://github.com/ChenYilong/iOSBlog/releases.atom"><img src="https://img.shields.io/badge/RSS feed (full text feed)-订阅我的博客更新-yellow.svg"></a>
</p>
<p align="center"><a href="https://mp.weixin.qq.com/s/A4e5h3xgIEh6PInf1Rjqsw"><img src="http://ww4.sinaimg.cn/large/006tNc79ly1g5zsnmaw40g30go04ck08.gif"></a></p>
<p align="center">
<a href="http://ww2.sinaimg.cn/large/006tNc79ly1g5et6q6sm5j30go0goaar.jpg"><img src="http://ww1.sinaimg.cn/large/006tNc79ly1g5esb5j4oaj300w00rdfn.jpg"></a>
<a href="http://weibo.com/luohanchenyilong"><img src="https://tva1.sinaimg.cn/large/006y8mN6ly1g6um2edt3jj300w00q3y9.jpg"></a>
<a href="https://twitter.com/iOSChenYilong"><img src="http://ww3.sinaimg.cn/large/006tNc79ly1g5erhikv2kj300w00wgld.jpg"></a>
<a href="https://github.com/ChenYilong"><img src="http://ww3.sinaimg.cn/large/006tNc79gy1g5ercvzgxzj300w00wmwx.jpg"></a>
<a href="https://qm.qq.com/cgi-bin/qm/qr?k=SEdIYBh52YzquCEo8cmPwgkko1VgSAlw&authKey=sGcG%2BGB81DW%2Ba8v3dCufFSNoxhykAU61Uz%2B%2BqDiKQN2BGHP2xHYVI2tc0Cah2lpu"><img src="http://ww1.sinaimg.cn/large/006tNc79ly1g5euf38fedj300w00wjr5.jpg"></a>
<a href="https://t.me/iosobjc"><img src="http://ww2.sinaimg.cn/large/006tNc79ly1g5eus39934j300w00w0r1.jpg"></a>
<a href="http://s.zhihu.com/BU5Mp"><img src="http://ww4.sinaimg.cn/large/006tNc79ly1g5eu9melwaj300w00w3ya.jpg"></a>
</p>
--------------------------------------------
**Is your feature request related to a problem? Please describe.**
<!--- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]-->
**Describe the solution you'd like**
<!--- A clear and concise description of what you want to happen.-->
**Describe alternatives you've considered**
<!--- A clear and concise description of any alternative solutions or features you've considered.-->
**Additional context**
<!--- Add any other context or screenshots about the feature request here.-->
================================================
FILE: .github/ISSUE_TEMPLATE/qa----.md
================================================
---
name: QA问题询问
about: 使用方法或者不确定是否为bug,可选用本模版
title: "[Q-A]使用方法询问:"
labels: Q-A
assignees: ChenYilong
---
<p align="center"><a href="https://github.com/ChenYilong/CYLTabBarController"><img src="https://repository-images.githubusercontent.com/44896762/c1d6e880-a8d8-11e9-8bb4-2da8ebc06f0a"></a></p>
--------------------------------------------
<p align="center">
<a href="https://github.com/ChenYilong/CYLTabBarController/blob/master/CYLTabBarController.podspec"><img src="https://img.shields.io/badge/Pod-GetLatestVersion-green.svg?style=flat"></a>
<a href=""><img src="https://img.shields.io/badge/Swift-compatible-orange.svg"></a>
<a href=""><img src="https://img.shields.io/badge/platform-iOS%208.0%2B-ff69b5152950834.svg"></a>
<a href="https://github.com/ChenYilong/CYLTabBarController/blob/master/LICENSE"><img src="https://img.shields.io/badge/license-MIT-green.svg?style=flat"></a>
</p>
<p align="center">
<a href="https://github.com/ChenYilong/iOSBlog/issues/21"><img src="https://img.shields.io/static/v1.svg?label=QQ%E3%80%81Telegram%20Group&color=blue&message=%E7%82%B9%E5%87%BB%E8%8E%B7%E5%8F%96QQ%E3%80%81Telegram%E7%BE%A4%E4%BF%A1%E6%81%AF&color=green"></a>
</p>
<p align="center">
<a href="https://github.com/ChenYilong/CYLTabBarController/releases.atom"><img src="https://img.shields.io/badge/RSS feed (full text feed)-订阅仓库版本更新-yellow.svg"></a>
</p>
<p align="center">
<a href="https://github.com/ChenYilong/iOSBlog/releases.atom"><img src="https://img.shields.io/badge/RSS feed (full text feed)-订阅我的博客更新-yellow.svg"></a>
</p>
<p align="center"><a href="https://mp.weixin.qq.com/s/A4e5h3xgIEh6PInf1Rjqsw"><img src="http://ww4.sinaimg.cn/large/006tNc79ly1g5zsnmaw40g30go04ck08.gif"></a></p>
<p align="center">
<a href="http://ww2.sinaimg.cn/large/006tNc79ly1g5et6q6sm5j30go0goaar.jpg"><img src="http://ww1.sinaimg.cn/large/006tNc79ly1g5esb5j4oaj300w00rdfn.jpg"></a>
<a href="http://weibo.com/luohanchenyilong"><img src="https://tva1.sinaimg.cn/large/006y8mN6ly1g6um2edt3jj300w00q3y9.jpg"></a>
<a href="https://twitter.com/iOSChenYilong"><img src="http://ww3.sinaimg.cn/large/006tNc79ly1g5erhikv2kj300w00wgld.jpg"></a>
<a href="https://github.com/ChenYilong"><img src="http://ww3.sinaimg.cn/large/006tNc79gy1g5ercvzgxzj300w00wmwx.jpg"></a>
<a href="https://qm.qq.com/cgi-bin/qm/qr?k=SEdIYBh52YzquCEo8cmPwgkko1VgSAlw&authKey=sGcG%2BGB81DW%2Ba8v3dCufFSNoxhykAU61Uz%2B%2BqDiKQN2BGHP2xHYVI2tc0Cah2lpu"><img src="http://ww1.sinaimg.cn/large/006tNc79ly1g5euf38fedj300w00wjr5.jpg"></a>
<a href="https://t.me/iosobjc"><img src="http://ww2.sinaimg.cn/large/006tNc79ly1g5eus39934j300w00w0r1.jpg"></a>
<a href="http://s.zhihu.com/BU5Mp"><img src="http://ww4.sinaimg.cn/large/006tNc79ly1g5eu9melwaj300w00w3ya.jpg"></a>
</p>
--------------------------------------------
## My issue:
<!--- Please describe which issue do you want to fix. -->
<!--- Please mention me to merge with wechat:chenyilong1010, 或者前往 Telegram 群交流:https://t.me/iosobjc -->
================================================
FILE: .github/issue_template.md
================================================

----------
<p align="center">
<a href="https://github.com/ChenYilong/CYLTabBarController/blob/master/CYLTabBarController.podspec"><img src="https://img.shields.io/badge/Pod-GetLatestVersion-green.svg?style=flat"></a>
<a href=""><img src="https://img.shields.io/badge/Swift-compatible-orange.svg"></a>
<a href=""><img src="https://img.shields.io/badge/platform-iOS%208.0%2B-ff69b5152950834.svg"></a>
<a href="https://github.com/ChenYilong/CYLTabBarController/blob/master/LICENSE"><img src="https://img.shields.io/badge/license-MIT-green.svg?style=flat"></a>
</p>
<p align="center">
<a href="https://github.com/ChenYilong/iOSBlog/issues/21"><img src="https://img.shields.io/static/v1.svg?label=QQ%E3%80%81Telegram%20Group&color=blue&message=%E7%82%B9%E5%87%BB%E8%8E%B7%E5%8F%96QQ%E3%80%81Telegram%E7%BE%A4%E4%BF%A1%E6%81%AF&color=green"></a>
</p>
<p align="center">
<a href="https://twitter.com/stevechen1010"><img src="https://img.shields.io/twitter/url/http/shields.io.svg?style=social&maxAge=2592000"></a>
<a href="http://weibo.com/luohanchenyilong"><img src="http://i67.tinypic.com/wbulbr.jpg"></a>
</a><a href="https://t.me/CYLTabBarController"><img src="http://i66.tinypic.com/of2hbn.jpg"></a></a>
</p>
----------
## 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.
<!--- 尽量提供一个可以复现的Demo,我的邮箱:luohanchenyilong@163.com。或者前往 Telegram 群交流:https://t.me/iosobjc -->
## 4. Here is my Debug log
<!--- 请尽量提供详细的日志打印信息,控制台默认会有网络请求的打印信息,请将相关的日志贴出-->
----------
<p align="center"><a href="http://weibo.com/u/1692391497?s=6uyXnP" target="_blank"><img border="0" src="http://service.t.sina.com.cn/widget/qmd/1692391497/b46c844b/1.png"/></a></a>
================================================
FILE: .github/pull_request_template.md
================================================
<p align="center"><a href="https://github.com/ChenYilong/CYLTabBarController"><img src="https://repository-images.githubusercontent.com/44896762/c1d6e880-a8d8-11e9-8bb4-2da8ebc06f0a"></a></p>
--------------------------------------------
<p align="center">
<a href="https://github.com/ChenYilong/CYLTabBarController/blob/master/CYLTabBarController.podspec"><img src="https://img.shields.io/badge/Pod-GetLatestVersion-green.svg?style=flat"></a>
<a href=""><img src="https://img.shields.io/badge/Swift-compatible-orange.svg"></a>
<a href=""><img src="https://img.shields.io/badge/platform-iOS%208.0%2B-ff69b5152950834.svg"></a>
<a href="https://github.com/ChenYilong/CYLTabBarController/blob/master/LICENSE"><img src="https://img.shields.io/badge/license-MIT-green.svg?style=flat"></a>
</p>
<p align="center">
<a href="https://github.com/ChenYilong/iOSBlog/issues/21"><img src="https://img.shields.io/static/v1.svg?label=QQ%E3%80%81Telegram%20Group&color=blue&message=%E7%82%B9%E5%87%BB%E8%8E%B7%E5%8F%96QQ%E3%80%81Telegram%E7%BE%A4%E4%BF%A1%E6%81%AF&color=green"></a>
</p>
<p align="center">
<a href="https://github.com/ChenYilong/CYLTabBarController/releases.atom"><img src="https://img.shields.io/badge/RSS feed (full text feed)-订阅仓库版本更新-yellow.svg"></a>
</p>
<p align="center">
<a href="https://github.com/ChenYilong/iOSBlog/releases.atom"><img src="https://img.shields.io/badge/RSS feed (full text feed)-订阅我的博客更新-yellow.svg"></a>
</p>
<p align="center"><a href="https://mp.weixin.qq.com/s/A4e5h3xgIEh6PInf1Rjqsw"><img src="http://ww4.sinaimg.cn/large/006tNc79ly1g5zsnmaw40g30go04ck08.gif"></a></p>
<p align="center">
<a href="http://ww2.sinaimg.cn/large/006tNc79ly1g5et6q6sm5j30go0goaar.jpg"><img src="http://ww1.sinaimg.cn/large/006tNc79ly1g5esb5j4oaj300w00rdfn.jpg"></a>
<a href="http://weibo.com/luohanchenyilong"><img src="https://tva1.sinaimg.cn/large/006y8mN6ly1g6um2edt3jj300w00q3y9.jpg"></a>
<a href="https://twitter.com/iOSChenYilong"><img src="http://ww3.sinaimg.cn/large/006tNc79ly1g5erhikv2kj300w00wgld.jpg"></a>
<a href="https://github.com/ChenYilong"><img src="http://ww3.sinaimg.cn/large/006tNc79gy1g5ercvzgxzj300w00wmwx.jpg"></a>
<a href="https://qm.qq.com/cgi-bin/qm/qr?k=SEdIYBh52YzquCEo8cmPwgkko1VgSAlw&authKey=sGcG%2BGB81DW%2Ba8v3dCufFSNoxhykAU61Uz%2B%2BqDiKQN2BGHP2xHYVI2tc0Cah2lpu"><img src="http://ww1.sinaimg.cn/large/006tNc79ly1g5euf38fedj300w00wjr5.jpg"></a>
<a href="https://t.me/iosobjc"><img src="http://ww2.sinaimg.cn/large/006tNc79ly1g5eus39934j300w00w0r1.jpg"></a>
<a href="http://s.zhihu.com/BU5Mp"><img src="http://ww4.sinaimg.cn/large/006tNc79ly1g5eu9melwaj300w00w3ya.jpg"></a>
</p>
--------------------------------------------
## My issue:
<!--- Please describe which issue do you want to fix. -->
## What I have done:
<!--- Please mention me to merge with wechat:chenyilong1010, 或者前往 Telegram 群交流:https://t.me/iosobjc -->
================================================
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 <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
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 <QuartzCore/QuartzCore.h>
@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 <NSObject>
@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 <UIKit/UIKit.h>
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<UIViewController *> *)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 <UIKit/UIKit.h>
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 <UIKit/UIKit.h>
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 <UIKit/UIKit.h>
#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<CYLPlusButtonSubclassing> *CYLExternPlusButton;
FOUNDATION_EXTERN UIViewController *CYLPlusChildViewController;
@interface CYLPlusButton : UIButton
+ (void)registerPlusButton;
+ (void)removePlusButton;
- (void)plusChildViewControllerButtonClicked:(UIButton<CYLPlusButtonSubclassing> *)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<CYLPlusButtonSubclassing> *CYLExternPlusButton = nil;
UIViewController *CYLPlusChildViewController = nil;
@implementation CYLPlusButton
#pragma mark -
#pragma mark - public Methods
+ (void)registerPlusButton {
if (![self conformsToProtocol:@protocol(CYLPlusButtonSubclassing)]) {
return;
}
Class<CYLPlusButtonSubclassing> class = self;
UIButton<CYLPlusButtonSubclassing> *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<CYLPlusButtonSubclassing> *)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<CYLPlusButtonSubclassing> *)plusButton {
id target = self;
NSArray<NSString *> *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 <UIKit/UIKit.h>
#import "CYLTabBar.h"
NS_ASSUME_NONNULL_BEGIN
@interface CYLTabBar (CYLTabBarControllerExtention)
- (NSArray<UIControl *> *)cyl_visibleControls;
- (NSArray<UIControl *> *)cyl_subTabBarButtons;
- (NSArray<UIControl *> *)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 <objc/runtime.h>
#import "CYLTabBar.h"
#if __has_include(<Lottie/Lottie.h>)
#import <Lottie/Lottie.h>
#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<UIControl *> *)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<UIControl *> *)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(<Lottie/Lottie.h>)
[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(<Lottie/Lottie.h>)
[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 <UIKit/UIKit.h>
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 <objc/runtime.h>
#import "UIControl+CYLTabBarControllerExtention.h"
#import "CYLTabBar+CYLTabBarControllerExtention.h"
static void *const CYLTabBarContext = (void*)&CYLTabBarContext;
@interface CYLTabBar ()
/** 发布按钮 */
@property (nonatomic, strong) UIButton<CYLPlusButtonSubclassing> *plusButton;
@property (nonatomic, assign) CGFloat tabBarItemWidth;
@property (nonatomic, copy) NSArray<UIControl *> *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<CYLPlusButtonSubclassing> *)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<CYLPlusButtonSubclassing> *)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 <NSObject, UITabBarControllerDelegate>
@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 <CYLTabBarControllerDelegate>
@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<UIViewController *> *viewControllers;
/*!
* The Attributes of items which is displayed on the tab bar.
*/
@property (nonatomic, readwrite, copy) NSArray<NSDictionary *> *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<UIViewController *> *)viewControllers
tabBarItemsAttributes:(NSArray<NSDictionary *> *)tabBarItemsAttributes;
+ (instancetype)tabBarControllerWithViewControllers:(NSArray<UIViewController *> *)viewControllers
tabBarItemsAttributes:(NSArray<NSDictionary *> *)tabBarItemsAttributes;
- (instancetype)initWithViewControllers:(NSArray<UIViewController *> *)viewControllers
tabBarItemsAttributes:(NSArray<NSDictionary *> *)tabBarItemsAttributes
imageInsets:(UIEdgeInsets)imageInsets
titlePositionAdjustment:(UIOffset)titlePositionAdjustment;
+ (instancetype)tabBarControllerWithViewControllers:(NSArray<UIViewController *> *)viewControllers
tabBarItemsAttributes:(NSArray<NSDictionary *> *)tabBarItemsAttributes
imageInsets:(UIEdgeInsets)imageInsets
titlePositionAdjustment:(UIOffset)titlePositionAdjustment;
- (instancetype)initWithViewControllers:(NSArray<UIViewController *> *)viewControllers
tabBarItemsAttributes:(NSArray<NSDictionary *> *)tabBarItemsAttributes
imageInsets:(UIEdgeInsets)imageInsets
titlePositionAdjustment:(UIOffset)titlePositionAdjustment
context:(NSString *)context;
+ (instancetype)tabBarControllerWithViewControllers:(NSArray<UIViewController *> *)viewControllers
tabBarItemsAttributes:(NSArray<NSDictionary *> *)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<UIApplicationDelegate>)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 <objc/runtime.h>
#import "UIViewController+CYLTabBarControllerExtention.h"
#import "UIControl+CYLTabBarControllerExtention.h"
#import "UIImage+CYLTabBarControllerExtention.h"
#if __has_include(<Lottie/Lottie.h>)
#import <Lottie/Lottie.h>
#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 () <UITabBarControllerDelegate>
@property (nonatomic, assign, getter=isObservingTabImageViewDefaultOffset) BOOL observingTabImageViewDefaultOffset;
@property (nonatomic, assign, getter=shouldInvokeOnceViewDidLayoutSubViewsBlock) BOOL invokeOnceViewDidLayoutSubViewsBlock;
@property (nonatomic, strong) NSMutableArray<NSURL *> *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<CYLPlusButtonSubclassing> *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<UIViewController *> *)viewControllers tabBarItemsAttributes:(NSArray<NSDictionary *> *)tabBarItemsAttributes {
return [self initWithViewControllers:viewControllers
tabBarItemsAttributes:tabBarItemsAttributes
imageInsets:UIEdgeInsetsZero
titlePositionAdjustment:UIOffsetZero
context:nil];
}
- (instancetype)initWithViewControllers:(NSArray<UIViewController *> *)viewControllers
tabBarItemsAttributes:(NSArray<NSDictionary *> *)tabBarItemsAttributes
imageInsets:(UIEdgeInsets)imageInsets
titlePositionAdjustment:(UIOffset)titlePositionAdjustment {
return [self initWithViewControllers:viewControllers
tabBarItemsAttributes:tabBarItemsAttributes
imageInsets:imageInsets
titlePositionAdjustment:titlePositionAdjustment
context:nil];
}
- (instancetype)initWithViewControllers:(NSArray<UIViewController *> *)viewControllers
tabBarItemsAttributes:(NSArray<NSDictionary *> *)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<UIViewController *> *)viewControllers
tabBarItemsAttributes:(NSArray<NSDictionary *> *)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<UIViewController *> *)viewControllers
tabBarItemsAttributes:(NSArray<NSDictionary *> *)tabBarItemsAttributes
imageInsets:(UIEdgeInsets)imageInsets
titlePositionAdjustment:(UIOffset)titlePositionAdjustment {
return [[self alloc] initWithViewControllers:viewControllers
tabBarItemsAttributes:tabBarItemsAttributes
imageInsets:imageInsets
titlePositionAdjustment:titlePositionAdjustment
context:nil];
}
+ (instancetype)tabBarControllerWithViewControllers:(NSArray<UIViewController *> *)viewControllers tabBarItemsAttributes:(NSArray<NSDictionary *> *)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<UIApplicationDelegate>)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<UITabBarItem *> *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<UIApplicationDelegate> delegate = ((id<UIApplicationDelegate>)[[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<UIApplicationDelegate> delegate = ((id<UIApplicationDelegate>)[[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 <UIKit/UIKit.h>
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<UIApplicationDelegate> *)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 <objc/runtime.h>
@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<UIApplicationDelegate> *)cyl_sharedAppDelegate {
id<UIApplicationDelegate> appDelegate = [UIApplication sharedApplication].delegate;
return (UIResponder<UIApplicationDelegate> *)appDelegate;
}
- (void)cyl_forceUpdateInterfaceOrientation:(UIInterfaceOrientation)orientation {
UIResponder<UIApplicationDelegate> *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 <UIKit/UIKit.h>
#import "UIView+CYLBadgeExtention.h"
#import "CYLBadgeProtocol.h"
NS_ASSUME_NONNULL_BEGIN
@interface UIBarButtonItem (CYLBadgeExtention)<CYLBadgeProtocol>
- (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 <objc/runtime.h>
#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 <UIKit/UIKit.h>
#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(<UIKit/UIScene.h>)
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(<UIKit/UIScene.h>)
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(<UIKit/UIScene.h>)
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(<UIKit/UIScene.h>)
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(<UIKit/UIScene.h>)
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(<UIKit/UIScene.h>)
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(<UIKit/UIScene.h>)
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(<UIKit/UIScene.h>)
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(<UIKit/UIScene.h>)
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(<UIKit/UIScene.h>)
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(<UIKit/UIScene.h>)
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(<UIKit/UIScene.h>)
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(<UIKit/UIScene.h>)
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(<UIKit/UIScene.h>)
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(<UIKit/UIScene.h>)
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(<UIKit/UIScene.h>)
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(<UIKit/UIScene.h>)
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(<UIKit/UIScene.h>)
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(<UIKit/UIScene.h>)
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(<UIKit/UIScene.h>)
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(<UIKit/UIScene.h>)
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(<UIKit/UIScene.h>)
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(<UIKit/UIScene.h>)
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(<UIKit/UIScene.h>)
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(<UIKit/UIScene.h>)
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(<UIKit/UIScene.h>)
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(<UIKit/UIScene.h>)
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(<UIKit/UIScene.h>)
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(<UIKit/UIScene.h>)
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(<UIKit/UIScene.h>)
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(<UIKit/UIScene.h>)
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(<UIKit/UIScene.h>)
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(<UIKit/UIScene.h>)
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(<UIKit/UIScene.h>)
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(<UIKit/UIScene.h>)
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 <UIKit/UIKit.h>
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 <objc/runtime.h>
#import "UIView+CYLTabBarControllerExtention.h"
#import "CYLConstants.h"
#import "CYLTabBarController.h"
#if __has_include(<Lottie/Lottie.h>)
#import <Lottie/Lottie.h>
#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(<Lottie/Lottie.h>)
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 <UIKit/UIKit.h>
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(<UIKit/UIScene.h>)
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<UITraitEnvironment>)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<UITraitEnvironment>)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(<UIKit/UIScene.h>)
//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 <UIKit/UIKit.h>
#import "UIView+CYLBadgeExtention.h"
#import "CYLBadgeProtocol.h"
NS_ASSUME_NONNULL_BEGIN
@interface UITabBarItem (CYLBadgeExtention)<CYLBadgeProtocol>
- (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 <objc/runtime.h>
#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 <UIKit/UIKit.h>
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 <UIKit/UIKit.h>
#import "CYLBadgeProtocol.h"
NS_ASSUME_NONNULL_BEGIN
#pragma mark -- badge apis
@interface UIView (CYLBadgeExtention)<CYLBadgeProtocol>
- (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 <objc/runtime.h>
#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 <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#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 <UIKit/UIKit.h>
#import "UIView+CYLTabBarControllerExtention.h"
#import "CYLPlusButton.h"
#if __has_include(<Lottie/Lottie.h>)
#import <Lottie/Lottie.h>
#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
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
Condensed preview — 156 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (627K chars).
[
{
"path": ".gitattributes",
"chars": 60,
"preview": "*.h linguist-detectable=false\n*.m linguist-detectable=false\n"
},
{
"path": ".github/ISSUE_TEMPLATE/-en-bug-report--cn-bug---.md",
"chars": 3696,
"preview": "---\nname: \"[EN]Bug report.[CN]bug反馈.\"\nabout: Create a report to help us improve\ntitle: \"[bug]:\"\nlabels: bug\nassignees: C"
},
{
"path": ".github/ISSUE_TEMPLATE/-en-feature-request--cn---------.md",
"chars": 3376,
"preview": "---\nname: \"[EN]Feature request.[CN]希望添加新功能.\"\nabout: Suggest an idea for this project\ntitle: \"[Feature request]希望添加新功能:\"\n"
},
{
"path": ".github/ISSUE_TEMPLATE/qa----.md",
"chars": 2967,
"preview": "---\nname: QA问题询问\nabout: 使用方法或者不确定是否为bug,可选用本模版\ntitle: \"[Q-A]使用方法询问:\"\nlabels: Q-A\nassignees: ChenYilong\n\n---\n\n<p align=\"c"
},
{
"path": ".github/issue_template.md",
"chars": 2173,
"preview": "\n\n\n----------\n\n\n<p align=\"center\">\n<a href=\"https://gi"
},
{
"path": ".github/pull_request_template.md",
"chars": 2884,
"preview": "<p align=\"center\"><a href=\"https://github.com/ChenYilong/CYLTabBarController\"><img src=\"https://repository-images.github"
},
{
"path": ".gitignore",
"chars": 542,
"preview": "\n.DS_Store \nCYLTabBarController.xcodeproj/project.xcworkspace/xcuserdata/chenyilong.xcuserdatad/UserInterfaceState.xcuse"
},
{
"path": "CHANGELOG.md",
"chars": 0,
"preview": ""
},
{
"path": "CYLTabBarController/CAAnimation+CYLBadgeExtention.h",
"chars": 2277,
"preview": "/*\n // CYLTabBarController\n // CYLTabBarController\n //\n // Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/"
},
{
"path": "CYLTabBarController/CAAnimation+CYLBadgeExtention.m",
"chars": 5991,
"preview": "/*\n // CYLTabBarController\n // CYLTabBarController\n //\n // Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/"
},
{
"path": "CYLTabBarController/CYLBadgeProtocol.h",
"chars": 5094,
"preview": "/*\n // CYLTabBarController\n // CYLTabBarController\n //\n // Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/"
},
{
"path": "CYLTabBarController/CYLBaseNavigationController.h",
"chars": 359,
"preview": "/*\n // CYLTabBarController\n // CYLTabBarController\n //\n // Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/"
},
{
"path": "CYLTabBarController/CYLBaseNavigationController.m",
"chars": 1146,
"preview": "/*\n // CYLTabBarController\n // CYLTabBarController\n //\n // Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/"
},
{
"path": "CYLTabBarController/CYLBaseTableViewController.h",
"chars": 357,
"preview": "/*\n // CYLTabBarController\n // CYLTabBarController\n //\n // Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/"
},
{
"path": "CYLTabBarController/CYLBaseTableViewController.m",
"chars": 1186,
"preview": "/*\n // CYLTabBarController\n // CYLTabBarController\n //\n // Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/"
},
{
"path": "CYLTabBarController/CYLBaseViewController.h",
"chars": 347,
"preview": "/*\n // CYLTabBarController\n // CYLTabBarController\n //\n // Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/"
},
{
"path": "CYLTabBarController/CYLBaseViewController.m",
"chars": 1169,
"preview": "/*\n // CYLTabBarController\n // CYLTabBarController\n //\n // Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/"
},
{
"path": "CYLTabBarController/CYLConstants.h",
"chars": 1571,
"preview": "//\n// CYLTabBarController.h\n// CYLTabBarController\n//\n// v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohancheny"
},
{
"path": "CYLTabBarController/CYLPlusButton.h",
"chars": 3004,
"preview": "//\n// CYLPlusButton.h\n// CYLTabBarController\n//\n// v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/"
},
{
"path": "CYLTabBarController/CYLPlusButton.m",
"chars": 3976,
"preview": "//\n// CYLPlusButton.m\n// CYLTabBarController\n//\n// v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/"
},
{
"path": "CYLTabBarController/CYLTabBar+CYLTabBarControllerExtention.h",
"chars": 1016,
"preview": "/*\n // CYLTabBarController\n // CYLTabBarController\n //\n // Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/"
},
{
"path": "CYLTabBarController/CYLTabBar+CYLTabBarControllerExtention.m",
"chars": 7865,
"preview": "/*\n // CYLTabBarController\n // CYLTabBarController\n //\n // Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/"
},
{
"path": "CYLTabBarController/CYLTabBar.h",
"chars": 669,
"preview": "//\n// CYLTabBar.h\n// CYLTabBarController\n//\n// v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) o"
},
{
"path": "CYLTabBarController/CYLTabBar.m",
"chars": 14995,
"preview": "//\n// CYLTabBar.m\n// CYLTabBarController\n//\n// v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) o"
},
{
"path": "CYLTabBarController/CYLTabBarController.h",
"chars": 6873,
"preview": "//\n// CYLTabBarController.h\n// CYLTabBarController\n//\n// v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohancheny"
},
{
"path": "CYLTabBarController/CYLTabBarController.m",
"chars": 32914,
"preview": "//\n// CYLTabBarController.m\n// CYLTabBarController\n//\n// v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohancheny"
},
{
"path": "CYLTabBarController/NSObject+CYLTabBarControllerExtention.h",
"chars": 812,
"preview": "//\n// CYLTabBarController.h\n// CYLTabBarController\n//\n// v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohancheny"
},
{
"path": "CYLTabBarController/NSObject+CYLTabBarControllerExtention.m",
"chars": 5297,
"preview": "//\n// CYLTabBarController.h\n// CYLTabBarController\n//\n// v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohancheny"
},
{
"path": "CYLTabBarController/UIBarButtonItem+CYLBadgeExtention.h",
"chars": 984,
"preview": "/*\n // CYLTabBarController\n // CYLTabBarController\n //\n // Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/"
},
{
"path": "CYLTabBarController/UIBarButtonItem+CYLBadgeExtention.m",
"chars": 3603,
"preview": "/*\n // CYLTabBarController\n // CYLTabBarController\n //\n // Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/"
},
{
"path": "CYLTabBarController/UIColor+CYLTabBarControllerExtention.h",
"chars": 5744,
"preview": "//\n// UIColor+CYLTabBarControllerExtention.h\n// CYLTabBarController\n//\n// v1.21.x Created by 微博@iOS程序犭袁 ( http://weib"
},
{
"path": "CYLTabBarController/UIColor+CYLTabBarControllerExtention.m",
"chars": 14461,
"preview": "//\n// UIColor+CYLTabBarControllerExtention.h\n// CYLTabBarController\n//\n// v1.21.x Created by 微博@iOS程序犭袁 ( http://weib"
},
{
"path": "CYLTabBarController/UIControl+CYLTabBarControllerExtention.h",
"chars": 2474,
"preview": "//\n// CYLTabBarController.m\n// CYLTabBarController\n//\n// v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohancheny"
},
{
"path": "CYLTabBarController/UIControl+CYLTabBarControllerExtention.m",
"chars": 15205,
"preview": "//\n// CYLTabBarController.m\n// CYLTabBarController\n//\n// v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohancheny"
},
{
"path": "CYLTabBarController/UIImage+CYLTabBarControllerExtention.h",
"chars": 369,
"preview": "//\n// UIImage+CYLTabBarControllerExtention.h\n// CYLTabBarController\n//\n// Created by chenyilong on 18/4/2019.\n// Cop"
},
{
"path": "CYLTabBarController/UIImage+CYLTabBarControllerExtention.m",
"chars": 3212,
"preview": "//\n// UIImage+CYLTabBarControllerExtention.m\n// CYLTabBarController\n//\n// Created by chenyilong on 18/4/2019.\n// Cop"
},
{
"path": "CYLTabBarController/UITabBarItem+CYLBadgeExtention.h",
"chars": 1155,
"preview": "/*\n // CYLTabBarController\n // CYLTabBarController\n //\n // Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/"
},
{
"path": "CYLTabBarController/UITabBarItem+CYLBadgeExtention.m",
"chars": 5769,
"preview": "/*\n // CYLTabBarController\n // CYLTabBarController\n //\n // Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/"
},
{
"path": "CYLTabBarController/UITabBarItem+CYLTabBarControllerExtention.h",
"chars": 413,
"preview": "//\n// CYLTabBarController.m\n// CYLTabBarController\n//\n// v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohancheny"
},
{
"path": "CYLTabBarController/UITabBarItem+CYLTabBarControllerExtention.m",
"chars": 504,
"preview": "//\n// CYLTabBarController.m\n// CYLTabBarController\n//\n// v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohancheny"
},
{
"path": "CYLTabBarController/UIView+CYLBadgeExtention.h",
"chars": 1186,
"preview": "/*\n // CYLTabBarController\n // CYLTabBarController\n //\n // Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/"
},
{
"path": "CYLTabBarController/UIView+CYLBadgeExtention.m",
"chars": 15834,
"preview": "/*\n // CYLTabBarController\n // CYLTabBarController\n //\n // Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/"
},
{
"path": "CYLTabBarController/UIView+CYLTabBarControllerExtention.h",
"chars": 1274,
"preview": "//\n// CYLTabBarController.m\n// CYLTabBarController\n//\n// v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohancheny"
},
{
"path": "CYLTabBarController/UIView+CYLTabBarControllerExtention.m",
"chars": 8487,
"preview": "//\n// CYLTabBarController.m\n// CYLTabBarController\n//\n// v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohancheny"
},
{
"path": "CYLTabBarController/UIViewController+CYLNavigationControllerExtention.h",
"chars": 1748,
"preview": "/*\n // CYLTabBarController\n // CYLTabBarController\n //\n // Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/"
},
{
"path": "CYLTabBarController/UIViewController+CYLNavigationControllerExtention.m",
"chars": 6494,
"preview": "/*\n // CYLTabBarController\n // CYLTabBarController\n //\n // Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/"
},
{
"path": "CYLTabBarController/UIViewController+CYLTabBarControllerExtention.h",
"chars": 7350,
"preview": "//\n// UIViewController+CYLTabBarControllerExtention.h\n// CYLTabBarController\n//\n// v1.21.x Created by 微博@iOS程序犭袁 ( ht"
},
{
"path": "CYLTabBarController/UIViewController+CYLTabBarControllerExtention.m",
"chars": 17345,
"preview": "//\n// UIViewController+CYLTabBarControllerExtention.m\n// CYLTabBarController\n//\n// v1.21.x Created by 微博@iOS程序犭袁 ( ht"
},
{
"path": "CYLTabBarController.podspec",
"chars": 1162,
"preview": "Pod::Spec.new do |s|\n s.name = \"CYLTabBarController\"\n s.version = \"1.29.2\"\n s.summary = \"Highly cus"
},
{
"path": "CYLTabBarController.xcodeproj/project.pbxproj",
"chars": 35487,
"preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
},
{
"path": "CYLTabBarController.xcodeproj/xcshareddata/xcschemes/CYLTabBarController.xcscheme",
"chars": 2948,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n LastUpgradeVersion = \"1100\"\n version = \"1.3\">\n <BuildAction\n "
},
{
"path": "CYLTabBarControllerTests/CYLTabBarControllerTests.m",
"chars": 975,
"preview": "//\n// CYLTabBarControllerTests.m\n// CYLTabBarControllerTests\n//\n// v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/l"
},
{
"path": "CYLTabBarControllerTests/Info.plist",
"chars": 733,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "Example/AppDelegate.h",
"chars": 358,
"preview": "//\n// AppDelegate.h\n// CYLTabBarControllerDemo\n//\n// v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilon"
},
{
"path": "Example/AppDelegate.m",
"chars": 2627,
"preview": "//\n// AppDelegate.m\n// CYLTabBarController\n//\n// v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ )"
},
{
"path": "Example/Base.lproj/LaunchScreen.xib",
"chars": 3814,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVe"
},
{
"path": "Example/Base.lproj/Main.storyboard",
"chars": 1575,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard"
},
{
"path": "Example/CYLMainRootViewController.h",
"chars": 534,
"preview": "//\n// CYLMainRootViewController.h\n// CYLTabBarController\n//\n// Created by chenyilong on 7/3/2019.\n// Copyright © 201"
},
{
"path": "Example/CYLMainRootViewController.m",
"chars": 927,
"preview": "//\n// CYLMainRootViewController.m\n// CYLTabBarController\n//\n// Created by chenyilong on 7/3/2019.\n// Copyright © 201"
},
{
"path": "Example/Classes/Module/Home/CYLHomeViewController.h",
"chars": 522,
"preview": "//\n// CYLHomeViewController.h\n// CYLTabBarController\n//\n// v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanche"
},
{
"path": "Example/Classes/Module/Home/CYLHomeViewController.m",
"chars": 5198,
"preview": "//\n// CYLHomeViewController.m\n// CYLTabBarController\n//\n// v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanche"
},
{
"path": "Example/Classes/Module/Message/CYLMessageViewController.h",
"chars": 499,
"preview": "//\n// CYLMessageViewController.h\n// CYLTabBarController\n//\n// v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohan"
},
{
"path": "Example/Classes/Module/Message/CYLMessageViewController.m",
"chars": 3736,
"preview": "//\n// CYLMessageViewController.m\n// CYLTabBarController\n//\n// v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohan"
},
{
"path": "Example/Classes/Module/Mine/CYLMineViewController.h",
"chars": 512,
"preview": "//\n// CYLMineViewController.h\n// CYLTabBarController\n//\n// v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanche"
},
{
"path": "Example/Classes/Module/Mine/CYLMineViewController.m",
"chars": 3149,
"preview": "//\n// CYLMineViewController.m\n// CYLTabBarController\n//\n// v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanche"
},
{
"path": "Example/Classes/Module/Other/CYLPlusDemoChildViewController.h",
"chars": 258,
"preview": "//\n// CYLPlusDemoChildViewController.h\n// CYLTabBarController\n//\n// Created by chenyilong on 19/12/2017.\n// Copyrigh"
},
{
"path": "Example/Classes/Module/Other/CYLPlusDemoChildViewController.m",
"chars": 996,
"preview": "//\n// CYLPlusDemoChildViewController.m\n// CYLTabBarController\n//\n// Created by chenyilong on 19/12/2017.\n// Copyrigh"
},
{
"path": "Example/Classes/Module/SameCity/CYLDetailsViewController.h",
"chars": 428,
"preview": "//\n// CYLDetailsViewController.h\n// CYLTabBarController\n//\n// v1.21.x Created by Robert Dimitrov on 11/8/14.\n// Copy"
},
{
"path": "Example/Classes/Module/SameCity/CYLDetailsViewController.m",
"chars": 1985,
"preview": "//\n// CYLDetailsViewController.m\n// CYLTabBarController\n//\n// v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohan"
},
{
"path": "Example/Classes/Module/SameCity/CYLSameCityViewController.h",
"chars": 502,
"preview": "//\n// CYLSameCityViewController.h\n// CYLTabBarController\n//\n// v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luoha"
},
{
"path": "Example/Classes/Module/SameCity/CYLSameCityViewController.m",
"chars": 3141,
"preview": "//\n// CYLSameCityViewController.m\n// CYLTabBarController\n//\n// v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luoha"
},
{
"path": "Example/Classes/Other/LottieResources/gray_tabbar_home_animation.json",
"chars": 5118,
"preview": "{\"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\""
},
{
"path": "Example/Classes/Other/LottieResources/gray_tabbar_me_animation.json",
"chars": 5889,
"preview": "{\"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\":\""
},
{
"path": "Example/Classes/Other/LottieResources/gray_tabbar_message_animation.json",
"chars": 8633,
"preview": "{\"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\""
},
{
"path": "Example/Classes/Other/LottieResources/green_lottie_tab_discover.json",
"chars": 7823,
"preview": "{\"v\":\"5.1.16\",\"fr\":30,\"ip\":0,\"op\":30,\"w\":60,\"h\":60,\"nm\":\"Tab_Discovery_Active\",\"ddd\":0,\"assets\":[],\"layers\":[{\"ddd\":0,\"i"
},
{
"path": "Example/Classes/Other/LottieResources/green_lottie_tab_home.json",
"chars": 6403,
"preview": "{\"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"
},
{
"path": "Example/Classes/Other/LottieResources/green_lottie_tab_mine.json",
"chars": 4245,
"preview": "{\"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"
},
{
"path": "Example/Classes/Other/LottieResources/green_lottie_tab_news.json",
"chars": 7809,
"preview": "{\"v\":\"5.1.16\",\"fr\":30,\"ip\":0,\"op\":30,\"w\":60,\"h\":60,\"nm\":\"Tab_Knowledge_Active\",\"ddd\":0,\"assets\":[],\"layers\":[{\"ddd\":0,\"i"
},
{
"path": "Example/Classes/Other/LottieResources/tab_home_animate.json",
"chars": 15667,
"preview": "{\"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"
},
{
"path": "Example/Classes/Other/LottieResources/tab_me_animate.json",
"chars": 12789,
"preview": "{\"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"
},
{
"path": "Example/Classes/Other/LottieResources/tab_message_animate.json",
"chars": 24179,
"preview": "{\"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"
},
{
"path": "Example/Classes/Other/LottieResources/tab_search_animate.json",
"chars": 16421,
"preview": "{\"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"
},
{
"path": "Example/Classes/View/CYLPlusButtonSubclass.h",
"chars": 338,
"preview": "//\n// CYLPlusButtonSubclass.h\n// CYLTabBarControllerDemo\n//\n// v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luoha"
},
{
"path": "Example/Classes/View/CYLPlusButtonSubclass.m",
"chars": 6980,
"preview": "//\n// CYLPlusButtonSubclass.m\n// CYLTabBarControllerDemo\n//\n// v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luoha"
},
{
"path": "Example/Images.xcassets/AppIcon.appiconset/Contents.json",
"chars": 2912,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"iphone\",\n \"size\" : \"20x20\",\n \"scale\" : \"2x\"\n },\n {\n \"idiom\""
},
{
"path": "Example/Images.xcassets/Contents.json",
"chars": 62,
"preview": "{\n \"info\" : {\n \"author\" : \"xcode\",\n \"version\" : 1\n }\n}"
},
{
"path": "Example/Images.xcassets/LaunchImage.launchimage/Contents.json",
"chars": 5549,
"preview": "{\n \"images\" : [\n {\n \"filename\" : \"default-portrait-1792h@3x.png\",\n \"subtype\" : \"1792h\",\n \"minimum-sys"
},
{
"path": "Example/Images.xcassets/NavBar/Contents.json",
"chars": 62,
"preview": "{\n \"info\" : {\n \"version\" : 1,\n \"author\" : \"xcode\"\n }\n}"
},
{
"path": "Example/Images.xcassets/NavBar/home_bar_scan.imageset/Contents.json",
"chars": 356,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : \"universal\",\n "
},
{
"path": "Example/Images.xcassets/NavBar/home_title_slogan.imageset/Contents.json",
"chars": 364,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : \"universal\",\n "
},
{
"path": "Example/Images.xcassets/NavBar/icon_search.imageset/Contents.json",
"chars": 352,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : \"universal\",\n "
},
{
"path": "Example/Images.xcassets/TabBarIcon/Contents.json",
"chars": 62,
"preview": "{\n \"info\" : {\n \"version\" : 1,\n \"author\" : \"xcode\"\n }\n}"
},
{
"path": "Example/Images.xcassets/TabBarIcon/TabBar_Bg_Shadow.imageset/Contents.json",
"chars": 316,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : \"universal\",\n "
},
{
"path": "Example/Images.xcassets/TabBarIcon/account/Contents.json",
"chars": 62,
"preview": "{\n \"info\" : {\n \"version\" : 1,\n \"author\" : \"xcode\"\n }\n}"
},
{
"path": "Example/Images.xcassets/TabBarIcon/account/account_highlight.imageset/Contents.json",
"chars": 408,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \"account_highlight.png\",\n \"scale\" : \"1x\"\n "
},
{
"path": "Example/Images.xcassets/TabBarIcon/account/account_normal.imageset/Contents.json",
"chars": 399,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \"account_normal.png\",\n \"scale\" : \"1x\"\n },"
},
{
"path": "Example/Images.xcassets/TabBarIcon/fishpond/Contents.json",
"chars": 62,
"preview": "{\n \"info\" : {\n \"version\" : 1,\n \"author\" : \"xcode\"\n }\n}"
},
{
"path": "Example/Images.xcassets/TabBarIcon/fishpond/fishpond_highlight.imageset/Contents.json",
"chars": 411,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \"fishpond_highlight.png\",\n \"scale\" : \"1x\"\n "
},
{
"path": "Example/Images.xcassets/TabBarIcon/fishpond/fishpond_normal.imageset/Contents.json",
"chars": 402,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \"fishpond_normal.png\",\n \"scale\" : \"1x\"\n }"
},
{
"path": "Example/Images.xcassets/TabBarIcon/home/Contents.json",
"chars": 62,
"preview": "{\n \"info\" : {\n \"version\" : 1,\n \"author\" : \"xcode\"\n }\n}"
},
{
"path": "Example/Images.xcassets/TabBarIcon/home/home_highlight.imageset/Contents.json",
"chars": 399,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \"home_highlight.png\",\n \"scale\" : \"1x\"\n },"
},
{
"path": "Example/Images.xcassets/TabBarIcon/home/home_normal.imageset/Contents.json",
"chars": 390,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \"home_normal.png\",\n \"scale\" : \"1x\"\n },\n "
},
{
"path": "Example/Images.xcassets/TabBarIcon/home_select_cover.imageset/Contents.json",
"chars": 364,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : \"universal\",\n "
},
{
"path": "Example/Images.xcassets/TabBarIcon/lottie_placeholder/Contents.json",
"chars": 62,
"preview": "{\n \"info\" : {\n \"version\" : 1,\n \"author\" : \"xcode\"\n }\n}"
},
{
"path": "Example/Images.xcassets/TabBarIcon/lottie_placeholder/gray_tabbar_home_animation_lottie_placeholder.imageset/Contents.json",
"chars": 345,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : \"universal\",\n "
},
{
"path": "Example/Images.xcassets/TabBarIcon/lottie_placeholder/gray_tabbar_me_animation_lottie_placeholder.imageset/Contents.json",
"chars": 343,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : \"universal\",\n "
},
{
"path": "Example/Images.xcassets/TabBarIcon/lottie_placeholder/gray_tabbar_message_animation_lottie_placeholder.imageset/Contents.json",
"chars": 348,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : \"universal\",\n "
},
{
"path": "Example/Images.xcassets/TabBarIcon/message/Contents.json",
"chars": 62,
"preview": "{\n \"info\" : {\n \"version\" : 1,\n \"author\" : \"xcode\"\n }\n}"
},
{
"path": "Example/Images.xcassets/TabBarIcon/message/message_highlight.imageset/Contents.json",
"chars": 408,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \"message_highlight.png\",\n \"scale\" : \"1x\"\n "
},
{
"path": "Example/Images.xcassets/TabBarIcon/message/message_normal.imageset/Contents.json",
"chars": 399,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \"message_normal.png\",\n \"scale\" : \"1x\"\n },"
},
{
"path": "Example/Images.xcassets/TabBarIcon/post/Contents.json",
"chars": 62,
"preview": "{\n \"info\" : {\n \"version\" : 1,\n \"author\" : \"xcode\"\n }\n}"
},
{
"path": "Example/Images.xcassets/TabBarIcon/post/post_highlight.imageset/Contents.json",
"chars": 358,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : \"universal\",\n "
},
{
"path": "Example/Images.xcassets/TabBarIcon/post/post_normal.imageset/Contents.json",
"chars": 352,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : \"universal\",\n "
},
{
"path": "Example/Images.xcassets/TabBarIcon/tabbarBg.imageset/Contents.json",
"chars": 346,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : \"universal\",\n "
},
{
"path": "Example/Images.xcassets/TabBarIcon/tabbar_background.imageset/Contents.json",
"chars": 317,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : \"universal\",\n "
},
{
"path": "Example/Images.xcassets/TabBarIcon/tapbar_top_line.imageset/Contents.json",
"chars": 384,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : \"universal\",\n "
},
{
"path": "Example/Images.xcassets/TabBarIcon/videoback.imageset/Contents.json",
"chars": 348,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : \"universal\",\n "
},
{
"path": "Example/Images.xcassets/home-float-icon.imageset/Contents.json",
"chars": 403,
"preview": "{\n \"images\" : [\n {\n \"filename\" : \"home-float-icon.jpg\",\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n }"
},
{
"path": "Example/Images.xcassets/icon_tabbar_plus.imageset/Contents.json",
"chars": 363,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n },\n {\n \"filename\" : \"icon_tabbar_pl"
},
{
"path": "Example/Images.xcassets/navigationbar_background_tall.imageset/Contents.json",
"chars": 329,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : \"universal\",\n "
},
{
"path": "Example/Info.plist",
"chars": 1512,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "Example/MainTabBarController.h",
"chars": 530,
"preview": "//\n// MainTabBarController.h\n// CYLTabBarController\n//\n// v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchen"
},
{
"path": "Example/MainTabBarController.m",
"chars": 24214,
"preview": "//\n// MainTabBarController.m\n// CYLTabBarController\n//\n// v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchen"
},
{
"path": "Example/main.m",
"chars": 414,
"preview": "//\n// main.m\n// CYLTabBarController\n//\n// v1.21.x Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 15/"
},
{
"path": "Example-Swift/AppDelegate.swift",
"chars": 2574,
"preview": "//\n// AppDelegate.swift\n//\n// v1.16.0 Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/20/15.\n// Co"
},
{
"path": "Example-Swift/CYLTabbarController-Swift.xcodeproj/project.pbxproj",
"chars": 25273,
"preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 48;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
},
{
"path": "Example-Swift/MainTabBarController.swift",
"chars": 362,
"preview": "//\n// MainTabBarController.swift\n//\n// v1.16.0 Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/20/1"
},
{
"path": "Example-Swift/Module/Connection/Controller/ConnectionViewController.swift",
"chars": 913,
"preview": "//\n// ConnectionViewController.swift\n//\n// v1.16.0 Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/"
},
{
"path": "Example-Swift/Module/Home/Controller/HomeViewController.swift",
"chars": 903,
"preview": "//\n// HomeViewController.swift\n//\n// v1.16.0 Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/20/15."
},
{
"path": "Example-Swift/Module/Message/Controller/MessageViewController.swift",
"chars": 850,
"preview": "//\n// MessageViewController.swift\n// SwiftDemo\n//\n// Created by Anthony on 2017/12/29.\n// Copyright © 2017年 Anthony."
},
{
"path": "Example-Swift/Module/Personal/Controller/PersonalViewController.swift",
"chars": 910,
"preview": "//\n// PersonalViewController.swift\n//\n// v1.16.0 Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/20"
},
{
"path": "Example-Swift/Module/Publish/Controller/PublishViewController.swift",
"chars": 993,
"preview": "//\n// PublishViewController.swift\n// CYLTabbarController-Swift\n// v1.16.0 Created by 微博@iOS程序犭袁 ( http://weibo.com/lu"
},
{
"path": "Example-Swift/Other/Assets.xcassets/AppIcon.appiconset/Contents.json",
"chars": 2912,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"iphone\",\n \"size\" : \"20x20\",\n \"scale\" : \"2x\"\n },\n {\n \"idiom\""
},
{
"path": "Example-Swift/Other/Assets.xcassets/Contents.json",
"chars": 62,
"preview": "{\n \"info\" : {\n \"version\" : 1,\n \"author\" : \"xcode\"\n }\n}"
},
{
"path": "Example-Swift/Other/Assets.xcassets/LaunchImage.launchimage/Contents.json",
"chars": 5549,
"preview": "{\n \"images\" : [\n {\n \"filename\" : \"default-portrait-1792h@3x.png\",\n \"subtype\" : \"1792h\",\n \"minimum-sys"
},
{
"path": "Example-Swift/Other/Assets.xcassets/TabBarIcon/Contents.json",
"chars": 62,
"preview": "{\n \"info\" : {\n \"version\" : 1,\n \"author\" : \"xcode\"\n }\n}"
},
{
"path": "Example-Swift/Other/Assets.xcassets/TabBarIcon/account_highlight.imageset/Contents.json",
"chars": 386,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : \"universal\",\n "
},
{
"path": "Example-Swift/Other/Assets.xcassets/TabBarIcon/account_normal.imageset/Contents.json",
"chars": 383,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : \"universal\",\n "
},
{
"path": "Example-Swift/Other/Assets.xcassets/TabBarIcon/home_highlight.imageset/Contents.json",
"chars": 383,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : \"universal\",\n "
},
{
"path": "Example-Swift/Other/Assets.xcassets/TabBarIcon/home_normal.imageset/Contents.json",
"chars": 380,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : \"universal\",\n "
},
{
"path": "Example-Swift/Other/Assets.xcassets/TabBarIcon/message_highlight.imageset/Contents.json",
"chars": 386,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : \"universal\",\n "
},
{
"path": "Example-Swift/Other/Assets.xcassets/TabBarIcon/message_normal.imageset/Contents.json",
"chars": 383,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : \"universal\",\n "
},
{
"path": "Example-Swift/Other/Assets.xcassets/TabBarIcon/mycity_highlight.imageset/Contents.json",
"chars": 385,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : \"universal\",\n "
},
{
"path": "Example-Swift/Other/Assets.xcassets/TabBarIcon/mycity_normal.imageset/Contents.json",
"chars": 382,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : \"universal\",\n "
},
{
"path": "Example-Swift/Other/Assets.xcassets/TabBarIcon/post_normal.imageset/Contents.json",
"chars": 380,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : \"universal\",\n "
},
{
"path": "Example-Swift/Other/Assets.xcassets/TabBarIcon/tabbar_background.imageset/Contents.json",
"chars": 317,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : \"universal\",\n "
},
{
"path": "Example-Swift/Other/Assets.xcassets/TabBarIcon/tapbar_top_line.imageset/Contents.json",
"chars": 384,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : \"universal\",\n "
},
{
"path": "Example-Swift/Other/Base.lproj/LaunchScreen.storyboard",
"chars": 1844,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3"
},
{
"path": "Example-Swift/Other/Base.lproj/Main.storyboard",
"chars": 3366,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3"
},
{
"path": "Example-Swift/Other/Info.plist",
"chars": 1397,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "Example-Swift/Podfile",
"chars": 424,
"preview": "# Uncomment the next line to define a global platform for your project\n# platform :ios, '9.0'\nsource 'git@github.com:Coc"
},
{
"path": "Example-Swift/View/CYLPlusButtonSubclass.swift",
"chars": 2715,
"preview": "//\n// CYLPlusButtonSubclass.swift\n//\n// v1.16.0 Created by 微博@iOS程序犭袁 ( http://weibo.com/luohanchenyilong/ ) on 10/20/"
},
{
"path": "LICENSE",
"chars": 1142,
"preview": "Copyright (c) 2015 CYLTabBarController(https://github.com/ChenYilong/CYLTabBarController), L.L.C. All rights reserved.\n\n"
},
{
"path": "Podfile",
"chars": 486,
"preview": "# Uncomment the next line to define a global platform for your project\n# platform :ios, '9.0'\nsource 'https://cdn.cocoap"
},
{
"path": "README.md",
"chars": 50255,
"preview": "<p align=\"center\"><a href=\"https://github.com/ChenYilong/CYLTabBarController\"><img src=\"https://repository-images.github"
},
{
"path": "package.json",
"chars": 792,
"preview": "{\n \"name\": \"CYLTabBarController\",\n \"version\": \"1.0.0\",\n \"description\": \"<p align=\\\"center\\\"><a href=\\\"https://github."
}
]
About this extraction
This page contains the full source code of the ChenYilong/CYLTabBarController GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 156 files (560.0 KB), approximately 196.8k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.