├── .DS_Store
├── .gitignore
├── .swift-version
├── .travis.yml
├── CHANGELOG.md
├── CONTRIBUTIONS.md
├── HHTabBarView.podspec
├── HHTabBarView
├── HHTabBarView.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── HHTabBarView
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ ├── Contents.json
│ ├── location-pin.imageset
│ │ ├── Contents.json
│ │ ├── location-pin-1.png
│ │ ├── location-pin-2.png
│ │ └── location-pin.png
│ ├── refresh.imageset
│ │ ├── Contents.json
│ │ ├── refresh-1.png
│ │ ├── refresh-2.png
│ │ └── refresh.png
│ ├── sofa.imageset
│ │ ├── Contents.json
│ │ ├── sofa-1.png
│ │ ├── sofa-2.png
│ │ └── sofa.png
│ ├── target.imageset
│ │ ├── Contents.json
│ │ ├── target-1.png
│ │ ├── target-2.png
│ │ └── target.png
│ └── umbrella.imageset
│ │ ├── Contents.json
│ │ ├── umbrella-1.png
│ │ ├── umbrella-2.png
│ │ └── umbrella.png
│ ├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
│ ├── FirstViewController.swift
│ ├── Info.plist
│ ├── SecondViewController.swift
│ └── Source
│ ├── HHButton+Extension.swift
│ ├── HHTabBarView.swift
│ ├── HHTabButton.swift
│ └── HHTabLabel.swift
├── LICENSE
├── README.md
├── Screenshots
├── 1.png
├── 2.png
├── 3.png
├── 4.png
├── 5.png
├── 6.png
├── 7.png
├── 8.png
└── HHTabBarFlow.gif
└── logo
├── favicon.png
├── favicon.svg
├── logotype-a.png
├── logotype-a.svg
├── logotype-b.png
└── logotype-b.svg
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hemangshah/HHTabBarView/3dc02898857d4d6bba99bd3b368ff7f664968d36/.DS_Store
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Created by https://www.gitignore.io/api/xcode,swift,objective-c
3 |
4 | ### Objective-C ###
5 | # Xcode
6 | #
7 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
8 |
9 | ## Build generated
10 | build/
11 | DerivedData/
12 |
13 | ## Various settings
14 | *.pbxuser
15 | !default.pbxuser
16 | *.mode1v3
17 | !default.mode1v3
18 | *.mode2v3
19 | !default.mode2v3
20 | *.perspectivev3
21 | !default.perspectivev3
22 | xcuserdata/
23 |
24 | ## Other
25 | *.moved-aside
26 | *.xccheckout
27 | *.xcscmblueprint
28 |
29 | ## Obj-C/Swift specific
30 | *.hmap
31 | *.ipa
32 | *.dSYM.zip
33 | *.dSYM
34 |
35 | # CocoaPods - Refactored to standalone file
36 |
37 |
38 | # Carthage - Refactored to standalone file
39 |
40 | # fastlane
41 | #
42 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
43 | # screenshots whenever they are needed.
44 | # For more information about the recommended setup visit:
45 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
46 |
47 | fastlane/report.xml
48 | fastlane/Preview.html
49 | fastlane/screenshots
50 | fastlane/test_output
51 |
52 | # Code Injection
53 | #
54 | # After new code Injection tools there's a generated folder /iOSInjectionProject
55 | # https://github.com/johnno1962/injectionforxcode
56 |
57 | iOSInjectionProject/
58 |
59 | ### Objective-C Patch ###
60 |
61 | ### Swift ###
62 | # Xcode
63 | #
64 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
65 |
66 | ## Build generated
67 |
68 | ## Various settings
69 |
70 | ## Other
71 |
72 | ## Obj-C/Swift specific
73 |
74 | ## Playgrounds
75 | timeline.xctimeline
76 | playground.xcworkspace
77 |
78 | # Swift Package Manager
79 | #
80 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
81 | # Packages/
82 | # Package.pins
83 | .build/
84 |
85 | # CocoaPods - Refactored to standalone file
86 |
87 | # Carthage - Refactored to standalone file
88 |
89 | # fastlane
90 | #
91 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
92 | # screenshots whenever they are needed.
93 | # For more information about the recommended setup visit:
94 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
95 |
96 |
97 | ### Swift.SwiftPackageManager Stack ###
98 | Packages
99 | .build
100 | xcuserdata
101 |
102 | ### Xcode ###
103 | # Xcode
104 | #
105 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
106 |
107 | ## Build generated
108 |
109 | ## Various settings
110 |
111 | ## Other
112 |
113 | ### Xcode Patch ###
114 | *.xcodeproj/*
115 | !*.xcodeproj/project.pbxproj
116 | !*.xcodeproj/xcshareddata/
117 | !*.xcworkspace/contents.xcworkspacedata
118 | /*.gcno
119 |
120 | # End of https://www.gitignore.io/api/xcode,swift,objective-c
121 |
--------------------------------------------------------------------------------
/.swift-version:
--------------------------------------------------------------------------------
1 | 4.2
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: swift
2 | osx_image: xcode10.2
3 |
4 | branches:
5 | only:
6 | - master
7 |
8 | script:
9 | - cd HHTabBarView/
10 | - xcodebuild clean build CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO
11 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 |
5 | Latest release is available [here](https://github.com/hemangshah/HHTabBarView/releases/latest).
6 |
7 | ## [2.3.0](https://github.com/hemangshah/HHTabBarView/releases/tag/2.3.0) – Sep 24, 2019
8 | - Fixed: We can now go back by tapping on the same tab again in navigation hierarchy.
9 | - Support for Swift 5.0
10 |
11 | ## [2.2.0](https://github.com/hemangshah/HHTabBarView/releases/tag/2.2.0) – Dec 15, 2018
12 | - Fixed: https://github.com/hemangshah/HHTabBarView/issues/13
13 | - Fixed: https://github.com/hemangshah/HHTabBarView/issues/12
14 | - Support for Swift 4.2
15 |
16 | ## [2.1.0](https://github.com/hemangshah/HHTabBarView/releases/tag/2.1.0) – Sep 16, 2018
17 | - Fixed: https://github.com/hemangshah/HHTabBarView/issues/9
18 | - Minor code refactoring.
19 |
20 | ## [2.0.0](https://github.com/hemangshah/HHTabBarView/releases/tag/2.0.0) – Aug 18, 2018
21 | - Updated code base to allow user to add HHTabBarView at top position as well.
22 | - Minor code refactoring.
23 |
24 | ## [1.3.0](https://github.com/hemangshah/HHTabBarView/releases/tag/1.3.0) - Apr 02, 2018
25 | - Left to Right and Right to Left UI management as per the language. Example: English <–> Arabic.
26 | - Code refactoring.
27 |
28 | ## [1.2.0](https://github.com/hemangshah/HHTabBarView/releases/tag/1.2.0) - Feb 26, 2018
29 | - Huge code refactoring.
30 | - Swift 4.x support. Note: Revoked Swift 3.x support.
31 | - Customized position for title and image.
32 |
33 | ## [1.1.2](https://github.com/hemangshah/HHTabBarView/releases/tag/1.1.2) - Nov 26, 2017
34 | - Removed default black color for the HHTabButton title.
35 | - Allows selecting a particular tab programmatically.
36 | - Fixed a glitch when setting a title and an image together.
37 |
38 | ## [1.1.1](https://github.com/hemangshah/HHTabBarView/releases/tag/1.1.1) - Nov 07, 2017
39 | - Updated for iPhone X.
40 |
41 | ## [1.1.0](https://github.com/hemangshah/HHTabBarView/releases/tag/1.1.0) - Oct 26, 2017
42 | - Improvements.
43 |
44 | ## [1.0.0](https://github.com/hemangshah/HHTabBarView/releases/tag/1.0.0) - Oct 22, 2017
45 | - First Release over CocoaPods.
46 |
--------------------------------------------------------------------------------
/CONTRIBUTIONS.md:
--------------------------------------------------------------------------------
1 | Without these peoples repos and posts, I couldn't have made a better Printer.
2 |
3 | > In order of help received.
4 |
5 | 1. Stack Overflow posts.
6 | 2. [thellimist](https://github.com/thellimist/EZPods) for a step by step guide to add the HHTabBarView on CocoaPods.
7 | 3. [These lovely people who encouraged me to keep developing on the HHTabBarView](https://github.com/hemangshah/HHTabBarView/stargazers).
8 | 4. [These great people who raised issues and provided me enough informations to fixed it.](https://github.com/hemangshah/HHTabBarView/issues?q=is%3Aissue+is%3Aclosed)
9 | 5. [Tobaloidee](https://github.com/Tobaloidee) for providing such a cool logo.
10 | 6. [... and this list shouldn't end without these very helpful contributors.](https://github.com/hemangshah/HHTabBarView/graphs/contributors)
11 |
12 | **Thank you so much.** 💙
13 |
--------------------------------------------------------------------------------
/HHTabBarView.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = 'HHTabBarView'
3 | s.module_name = 'HHTabBarView'
4 | s.version = '2.3.0'
5 | s.summary = 'A lightweight customized tabbar view. 📌'
6 | s.description = 'HHTabBarView is an easy to setup and use replacement of default tabbar.'
7 | s.homepage = 'https://github.com/hemangshah/HHTabBarView'
8 | s.license = 'MIT'
9 | s.author = { 'hemangshah' => 'hemangshah.in@gmail.com' }
10 | s.source = { :git => 'https://github.com/hemangshah/HHTabBarView.git', :tag => s.version.to_s }
11 | s.platform = :ios, '9.0'
12 | s.requires_arc = true
13 | s.source_files = '**/Source/*.swift'
14 | end
--------------------------------------------------------------------------------
/HHTabBarView/HHTabBarView.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 6B2E6E982164BE0800CF06CB /* HHButton+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B2E6E972164BE0800CF06CB /* HHButton+Extension.swift */; };
11 | F19556761F2894DF00E891AB /* HHTabLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F19556751F2894DF00E891AB /* HHTabLabel.swift */; };
12 | F1C7BB4B1F25EEBB00D91CAB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F1C7BB3D1F25EEBB00D91CAB /* Assets.xcassets */; };
13 | F1C7BB4C1F25EEBB00D91CAB /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F1C7BB3F1F25EEBB00D91CAB /* LaunchScreen.storyboard */; };
14 | F1C7BB4D1F25EEBB00D91CAB /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F1C7BB411F25EEBB00D91CAB /* Main.storyboard */; };
15 | F1C7BB4E1F25EEBB00D91CAB /* HHTabBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1C7BB441F25EEBB00D91CAB /* HHTabBarView.swift */; };
16 | F1C7BB4F1F25EEBB00D91CAB /* HHTabButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1C7BB451F25EEBB00D91CAB /* HHTabButton.swift */; };
17 | F1C7BB501F25EEBB00D91CAB /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1C7BB461F25EEBB00D91CAB /* AppDelegate.swift */; };
18 | F1C7BB511F25EEBB00D91CAB /* FirstViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1C7BB471F25EEBB00D91CAB /* FirstViewController.swift */; };
19 | F1C7BB531F25EEBB00D91CAB /* SecondViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1C7BB491F25EEBB00D91CAB /* SecondViewController.swift */; };
20 | /* End PBXBuildFile section */
21 |
22 | /* Begin PBXFileReference section */
23 | 6B2E6E972164BE0800CF06CB /* HHButton+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HHButton+Extension.swift"; sourceTree = ""; };
24 | F19556751F2894DF00E891AB /* HHTabLabel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HHTabLabel.swift; sourceTree = ""; };
25 | F1C7BB3C1F25EEBB00D91CAB /* HHTabBarView.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HHTabBarView.app; sourceTree = BUILT_PRODUCTS_DIR; };
26 | F1C7BB3D1F25EEBB00D91CAB /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = HHTabBarView/Assets.xcassets; sourceTree = ""; };
27 | F1C7BB401F25EEBB00D91CAB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = LaunchScreen.storyboard; sourceTree = ""; };
28 | F1C7BB421F25EEBB00D91CAB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Main.storyboard; sourceTree = ""; };
29 | F1C7BB441F25EEBB00D91CAB /* HHTabBarView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HHTabBarView.swift; sourceTree = ""; };
30 | F1C7BB451F25EEBB00D91CAB /* HHTabButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HHTabButton.swift; sourceTree = ""; };
31 | F1C7BB461F25EEBB00D91CAB /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = HHTabBarView/AppDelegate.swift; sourceTree = ""; };
32 | F1C7BB471F25EEBB00D91CAB /* FirstViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FirstViewController.swift; path = HHTabBarView/FirstViewController.swift; sourceTree = ""; };
33 | F1C7BB481F25EEBB00D91CAB /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = HHTabBarView/Info.plist; sourceTree = ""; };
34 | F1C7BB491F25EEBB00D91CAB /* SecondViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SecondViewController.swift; path = HHTabBarView/SecondViewController.swift; sourceTree = ""; };
35 | /* End PBXFileReference section */
36 |
37 | /* Begin PBXFrameworksBuildPhase section */
38 | F1C7BB241F25EE7800D91CAB /* Frameworks */ = {
39 | isa = PBXFrameworksBuildPhase;
40 | buildActionMask = 2147483647;
41 | files = (
42 | );
43 | runOnlyForDeploymentPostprocessing = 0;
44 | };
45 | /* End PBXFrameworksBuildPhase section */
46 |
47 | /* Begin PBXGroup section */
48 | F1C7BB1E1F25EE7800D91CAB = {
49 | isa = PBXGroup;
50 | children = (
51 | F1C7BB431F25EEBB00D91CAB /* Source */,
52 | F1C7BB461F25EEBB00D91CAB /* AppDelegate.swift */,
53 | F1C7BB471F25EEBB00D91CAB /* FirstViewController.swift */,
54 | F1C7BB491F25EEBB00D91CAB /* SecondViewController.swift */,
55 | F1C7BB481F25EEBB00D91CAB /* Info.plist */,
56 | F1C7BB3D1F25EEBB00D91CAB /* Assets.xcassets */,
57 | F1C7BB3E1F25EEBB00D91CAB /* Base.lproj */,
58 | F1C7BB3C1F25EEBB00D91CAB /* HHTabBarView.app */,
59 | );
60 | sourceTree = "";
61 | };
62 | F1C7BB3E1F25EEBB00D91CAB /* Base.lproj */ = {
63 | isa = PBXGroup;
64 | children = (
65 | F1C7BB3F1F25EEBB00D91CAB /* LaunchScreen.storyboard */,
66 | F1C7BB411F25EEBB00D91CAB /* Main.storyboard */,
67 | );
68 | name = Base.lproj;
69 | path = HHTabBarView/Base.lproj;
70 | sourceTree = "";
71 | };
72 | F1C7BB431F25EEBB00D91CAB /* Source */ = {
73 | isa = PBXGroup;
74 | children = (
75 | F1C7BB441F25EEBB00D91CAB /* HHTabBarView.swift */,
76 | F1C7BB451F25EEBB00D91CAB /* HHTabButton.swift */,
77 | F19556751F2894DF00E891AB /* HHTabLabel.swift */,
78 | 6B2E6E972164BE0800CF06CB /* HHButton+Extension.swift */,
79 | );
80 | name = Source;
81 | path = HHTabBarView/Source;
82 | sourceTree = "";
83 | };
84 | /* End PBXGroup section */
85 |
86 | /* Begin PBXNativeTarget section */
87 | F1C7BB261F25EE7800D91CAB /* HHTabBarView */ = {
88 | isa = PBXNativeTarget;
89 | buildConfigurationList = F1C7BB391F25EE7800D91CAB /* Build configuration list for PBXNativeTarget "HHTabBarView" */;
90 | buildPhases = (
91 | F1C7BB231F25EE7800D91CAB /* Sources */,
92 | F1C7BB241F25EE7800D91CAB /* Frameworks */,
93 | F1C7BB251F25EE7800D91CAB /* Resources */,
94 | );
95 | buildRules = (
96 | );
97 | dependencies = (
98 | );
99 | name = HHTabBarView;
100 | productName = HHTabBarView;
101 | productReference = F1C7BB3C1F25EEBB00D91CAB /* HHTabBarView.app */;
102 | productType = "com.apple.product-type.application";
103 | };
104 | /* End PBXNativeTarget section */
105 |
106 | /* Begin PBXProject section */
107 | F1C7BB1F1F25EE7800D91CAB /* Project object */ = {
108 | isa = PBXProject;
109 | attributes = {
110 | LastSwiftUpdateCheck = 0830;
111 | LastUpgradeCheck = 1020;
112 | ORGANIZATIONNAME = "Hemang Shah";
113 | TargetAttributes = {
114 | F1C7BB261F25EE7800D91CAB = {
115 | CreatedOnToolsVersion = 8.3;
116 | LastSwiftMigration = 1020;
117 | ProvisioningStyle = Automatic;
118 | };
119 | };
120 | };
121 | buildConfigurationList = F1C7BB221F25EE7800D91CAB /* Build configuration list for PBXProject "HHTabBarView" */;
122 | compatibilityVersion = "Xcode 3.2";
123 | developmentRegion = en;
124 | hasScannedForEncodings = 0;
125 | knownRegions = (
126 | en,
127 | Base,
128 | );
129 | mainGroup = F1C7BB1E1F25EE7800D91CAB;
130 | productRefGroup = F1C7BB1E1F25EE7800D91CAB;
131 | projectDirPath = "";
132 | projectRoot = "";
133 | targets = (
134 | F1C7BB261F25EE7800D91CAB /* HHTabBarView */,
135 | );
136 | };
137 | /* End PBXProject section */
138 |
139 | /* Begin PBXResourcesBuildPhase section */
140 | F1C7BB251F25EE7800D91CAB /* Resources */ = {
141 | isa = PBXResourcesBuildPhase;
142 | buildActionMask = 2147483647;
143 | files = (
144 | F1C7BB4D1F25EEBB00D91CAB /* Main.storyboard in Resources */,
145 | F1C7BB4B1F25EEBB00D91CAB /* Assets.xcassets in Resources */,
146 | F1C7BB4C1F25EEBB00D91CAB /* LaunchScreen.storyboard in Resources */,
147 | );
148 | runOnlyForDeploymentPostprocessing = 0;
149 | };
150 | /* End PBXResourcesBuildPhase section */
151 |
152 | /* Begin PBXSourcesBuildPhase section */
153 | F1C7BB231F25EE7800D91CAB /* Sources */ = {
154 | isa = PBXSourcesBuildPhase;
155 | buildActionMask = 2147483647;
156 | files = (
157 | F1C7BB501F25EEBB00D91CAB /* AppDelegate.swift in Sources */,
158 | F1C7BB4E1F25EEBB00D91CAB /* HHTabBarView.swift in Sources */,
159 | 6B2E6E982164BE0800CF06CB /* HHButton+Extension.swift in Sources */,
160 | F19556761F2894DF00E891AB /* HHTabLabel.swift in Sources */,
161 | F1C7BB4F1F25EEBB00D91CAB /* HHTabButton.swift in Sources */,
162 | F1C7BB531F25EEBB00D91CAB /* SecondViewController.swift in Sources */,
163 | F1C7BB511F25EEBB00D91CAB /* FirstViewController.swift in Sources */,
164 | );
165 | runOnlyForDeploymentPostprocessing = 0;
166 | };
167 | /* End PBXSourcesBuildPhase section */
168 |
169 | /* Begin PBXVariantGroup section */
170 | F1C7BB3F1F25EEBB00D91CAB /* LaunchScreen.storyboard */ = {
171 | isa = PBXVariantGroup;
172 | children = (
173 | F1C7BB401F25EEBB00D91CAB /* Base */,
174 | );
175 | name = LaunchScreen.storyboard;
176 | sourceTree = "";
177 | };
178 | F1C7BB411F25EEBB00D91CAB /* Main.storyboard */ = {
179 | isa = PBXVariantGroup;
180 | children = (
181 | F1C7BB421F25EEBB00D91CAB /* Base */,
182 | );
183 | name = Main.storyboard;
184 | sourceTree = "";
185 | };
186 | /* End PBXVariantGroup section */
187 |
188 | /* Begin XCBuildConfiguration section */
189 | F1C7BB371F25EE7800D91CAB /* Debug */ = {
190 | isa = XCBuildConfiguration;
191 | buildSettings = {
192 | ALWAYS_SEARCH_USER_PATHS = NO;
193 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
194 | CLANG_ANALYZER_NONNULL = YES;
195 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
196 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
197 | CLANG_CXX_LIBRARY = "libc++";
198 | CLANG_ENABLE_MODULES = YES;
199 | CLANG_ENABLE_OBJC_ARC = YES;
200 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
201 | CLANG_WARN_BOOL_CONVERSION = YES;
202 | CLANG_WARN_COMMA = YES;
203 | CLANG_WARN_CONSTANT_CONVERSION = YES;
204 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
205 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
206 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
207 | CLANG_WARN_EMPTY_BODY = YES;
208 | CLANG_WARN_ENUM_CONVERSION = YES;
209 | CLANG_WARN_INFINITE_RECURSION = YES;
210 | CLANG_WARN_INT_CONVERSION = YES;
211 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
212 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
213 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
214 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
215 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
216 | CLANG_WARN_STRICT_PROTOTYPES = YES;
217 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
218 | CLANG_WARN_UNREACHABLE_CODE = YES;
219 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
220 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
221 | COPY_PHASE_STRIP = NO;
222 | DEBUG_INFORMATION_FORMAT = dwarf;
223 | ENABLE_STRICT_OBJC_MSGSEND = YES;
224 | ENABLE_TESTABILITY = YES;
225 | GCC_C_LANGUAGE_STANDARD = gnu99;
226 | GCC_DYNAMIC_NO_PIC = NO;
227 | GCC_NO_COMMON_BLOCKS = YES;
228 | GCC_OPTIMIZATION_LEVEL = 0;
229 | GCC_PREPROCESSOR_DEFINITIONS = (
230 | "DEBUG=1",
231 | "$(inherited)",
232 | );
233 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
234 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
235 | GCC_WARN_UNDECLARED_SELECTOR = YES;
236 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
237 | GCC_WARN_UNUSED_FUNCTION = YES;
238 | GCC_WARN_UNUSED_VARIABLE = YES;
239 | IPHONEOS_DEPLOYMENT_TARGET = 10.3;
240 | MTL_ENABLE_DEBUG_INFO = YES;
241 | ONLY_ACTIVE_ARCH = YES;
242 | SDKROOT = iphoneos;
243 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
244 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
245 | SWIFT_VERSION = 4.2;
246 | };
247 | name = Debug;
248 | };
249 | F1C7BB381F25EE7800D91CAB /* Release */ = {
250 | isa = XCBuildConfiguration;
251 | buildSettings = {
252 | ALWAYS_SEARCH_USER_PATHS = NO;
253 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
254 | CLANG_ANALYZER_NONNULL = YES;
255 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
256 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
257 | CLANG_CXX_LIBRARY = "libc++";
258 | CLANG_ENABLE_MODULES = YES;
259 | CLANG_ENABLE_OBJC_ARC = YES;
260 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
261 | CLANG_WARN_BOOL_CONVERSION = YES;
262 | CLANG_WARN_COMMA = YES;
263 | CLANG_WARN_CONSTANT_CONVERSION = YES;
264 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
265 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
266 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
267 | CLANG_WARN_EMPTY_BODY = YES;
268 | CLANG_WARN_ENUM_CONVERSION = YES;
269 | CLANG_WARN_INFINITE_RECURSION = YES;
270 | CLANG_WARN_INT_CONVERSION = YES;
271 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
272 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
273 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
274 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
275 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
276 | CLANG_WARN_STRICT_PROTOTYPES = YES;
277 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
278 | CLANG_WARN_UNREACHABLE_CODE = YES;
279 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
280 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
281 | COPY_PHASE_STRIP = NO;
282 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
283 | ENABLE_NS_ASSERTIONS = NO;
284 | ENABLE_STRICT_OBJC_MSGSEND = YES;
285 | GCC_C_LANGUAGE_STANDARD = gnu99;
286 | GCC_NO_COMMON_BLOCKS = YES;
287 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
288 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
289 | GCC_WARN_UNDECLARED_SELECTOR = YES;
290 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
291 | GCC_WARN_UNUSED_FUNCTION = YES;
292 | GCC_WARN_UNUSED_VARIABLE = YES;
293 | IPHONEOS_DEPLOYMENT_TARGET = 10.3;
294 | MTL_ENABLE_DEBUG_INFO = NO;
295 | SDKROOT = iphoneos;
296 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
297 | SWIFT_VERSION = 4.2;
298 | VALIDATE_PRODUCT = YES;
299 | };
300 | name = Release;
301 | };
302 | F1C7BB3A1F25EE7800D91CAB /* Debug */ = {
303 | isa = XCBuildConfiguration;
304 | buildSettings = {
305 | CLANG_ENABLE_MODULES = YES;
306 | INFOPLIST_FILE = HHTabBarView/Info.plist;
307 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
308 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
309 | PRODUCT_BUNDLE_IDENTIFIER = com.hemangshah.HHTabBarView;
310 | PRODUCT_NAME = "$(TARGET_NAME)";
311 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
312 | SWIFT_VERSION = 5.0;
313 | };
314 | name = Debug;
315 | };
316 | F1C7BB3B1F25EE7800D91CAB /* Release */ = {
317 | isa = XCBuildConfiguration;
318 | buildSettings = {
319 | CLANG_ENABLE_MODULES = YES;
320 | INFOPLIST_FILE = HHTabBarView/Info.plist;
321 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
322 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
323 | PRODUCT_BUNDLE_IDENTIFIER = com.hemangshah.HHTabBarView;
324 | PRODUCT_NAME = "$(TARGET_NAME)";
325 | SWIFT_VERSION = 5.0;
326 | };
327 | name = Release;
328 | };
329 | /* End XCBuildConfiguration section */
330 |
331 | /* Begin XCConfigurationList section */
332 | F1C7BB221F25EE7800D91CAB /* Build configuration list for PBXProject "HHTabBarView" */ = {
333 | isa = XCConfigurationList;
334 | buildConfigurations = (
335 | F1C7BB371F25EE7800D91CAB /* Debug */,
336 | F1C7BB381F25EE7800D91CAB /* Release */,
337 | );
338 | defaultConfigurationIsVisible = 0;
339 | defaultConfigurationName = Release;
340 | };
341 | F1C7BB391F25EE7800D91CAB /* Build configuration list for PBXNativeTarget "HHTabBarView" */ = {
342 | isa = XCConfigurationList;
343 | buildConfigurations = (
344 | F1C7BB3A1F25EE7800D91CAB /* Debug */,
345 | F1C7BB3B1F25EE7800D91CAB /* Release */,
346 | );
347 | defaultConfigurationIsVisible = 0;
348 | defaultConfigurationName = Release;
349 | };
350 | /* End XCConfigurationList section */
351 | };
352 | rootObject = F1C7BB1F1F25EE7800D91CAB /* Project object */;
353 | }
354 |
--------------------------------------------------------------------------------
/HHTabBarView/HHTabBarView.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/HHTabBarView/HHTabBarView.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/HHTabBarView/HHTabBarView/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // HHTabBarView
4 | //
5 | // Created by Hemang Shah on 7/17/17.
6 | // Copyright © 2017 Hemang Shah. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 | /////Start ------ Setup HHTabBarView ------
17 |
18 | //1
19 | //Initialize and keeping reference of HHTabBarView.
20 | let hhTabBarView = HHTabBarView.shared
21 |
22 | //Keeping reference of iOS default UITabBarController.
23 | let referenceUITabBarController = HHTabBarView.shared.referenceUITabBarController
24 |
25 | //2
26 | func setupReferenceUITabBarController() {
27 |
28 | //Creating a storyboard reference
29 | let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
30 |
31 | //First and Second Tab ViewControllers will be taken from the UIStoryBoard
32 | //Creating navigation controller for navigation inside the first tab.
33 | let navigationController1: UINavigationController = UINavigationController(rootViewController: storyboard.instantiateViewController(withIdentifier: "FirstViewControllerID"))
34 |
35 | //Creating navigation controller for navigation inside the second tab.
36 | let navigationController2: UINavigationController = UINavigationController(rootViewController: storyboard.instantiateViewController(withIdentifier: "SecondViewControllerID"))
37 |
38 | //Third, Fourth and Fifth will be created runtime.
39 | let sofaViewController = UIViewController()
40 | sofaViewController.title = "Sofa"
41 | sofaViewController.view.backgroundColor = .white
42 | let sofaNavigationController: UINavigationController = UINavigationController(rootViewController: sofaViewController)
43 |
44 | let targetViewController = UIViewController()
45 | targetViewController.title = "Target"
46 | targetViewController.view.backgroundColor = .white
47 | let targetNavigationController: UINavigationController = UINavigationController(rootViewController: targetViewController)
48 |
49 | let umbrellaViewController = UIViewController()
50 | umbrellaViewController.title = "Umbrella"
51 | umbrellaViewController.view.backgroundColor = .white
52 | let umbrellaNavigationController: UINavigationController = UINavigationController(rootViewController: umbrellaViewController)
53 |
54 | //Update referenced TabbarController with your viewcontrollers
55 | referenceUITabBarController.setViewControllers([navigationController1, navigationController2, sofaNavigationController, targetNavigationController, umbrellaNavigationController], animated: false)
56 | }
57 |
58 | //3
59 | func setupHHTabBarView() {
60 |
61 | //Default & Selected Background Color
62 | let defaultTabColor = UIColor.black.withAlphaComponent(0.8)
63 | let selectedTabColor = UIColor(red: 28/255, green: 158/255, blue: 247/255, alpha: 1.0)
64 | let tabFont = UIFont.init(name: "Helvetica-Light", size: 12.0)
65 | let spacing: CGFloat = 3.0
66 |
67 | //Create Custom Tabs
68 | //Note: As tabs are subclassed of UIButton so you can modify it as much as possible.
69 |
70 | let titles = ["Location", "Refresh", "Sofa", "Target", "Umbrella"]
71 | let icons = [UIImage(named: "location-pin")!, UIImage(named: "refresh")!, UIImage(named: "sofa")!, UIImage(named: "target")!, UIImage(named: "umbrella")!]
72 | var tabs = [HHTabButton]()
73 |
74 | for index in 0...4 {
75 | let tab = HHTabButton(withTitle: titles[index], tabImage: icons[index], index: index)
76 | tab.titleLabel?.font = tabFont
77 | tab.setHHTabBackgroundColor(color: defaultTabColor, forState: .normal)
78 | tab.setHHTabBackgroundColor(color: selectedTabColor, forState: .selected)
79 | tab.imageToTitleSpacing = spacing
80 | tab.imageVerticalAlignment = .top
81 | tab.imageHorizontalAlignment = .center
82 | tabs.append(tab)
83 | }
84 |
85 | //Set HHTabBarView position.
86 | hhTabBarView.tabBarViewPosition = .bottom
87 |
88 | //Set this value according to your UI requirements.
89 | hhTabBarView.tabBarViewTopPositionValue = 64
90 |
91 | //Set Default Index for HHTabBarView.
92 | hhTabBarView.tabBarTabs = tabs
93 |
94 | // To modify badge label.
95 | // Note: You should only modify badgeLabel after assigning tabs array.
96 | // Example:
97 | //t1.badgeLabel?.backgroundColor = .white
98 | //t1.badgeLabel?.textColor = selectedTabColor
99 | //t1.badgeLabel?.font = UIFont.boldSystemFont(ofSize: 20.0)
100 |
101 | //Handle Tab Change Event
102 | hhTabBarView.defaultIndex = 0
103 |
104 | //Show Animation on Switching Tabs
105 | hhTabBarView.tabChangeAnimationType = .none
106 |
107 | //Handle Tab Changes
108 | hhTabBarView.onTabTapped = { (tabIndex, isSameTab, controller) in
109 | if isSameTab {
110 | if let navcon = controller as? UINavigationController {
111 | navcon.popToRootViewController(animated: true)
112 | } else if let vc = controller as? UIViewController {
113 | vc.navigationController?.popToRootViewController(animated: true)
114 | }
115 | }
116 | print("Selected Tab Index:\(tabIndex)")
117 | }
118 | }
119 |
120 | //4
121 | // MARK: App Life Cycle
122 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
123 |
124 | //Setup HHTabBarView
125 | setupReferenceUITabBarController()
126 | setupHHTabBarView()
127 |
128 | //This is important.
129 | //Setup Application Window
130 | window = UIWindow.init(frame: UIScreen.main.bounds)
131 | window?.rootViewController = referenceUITabBarController
132 | window?.makeKeyAndVisible()
133 |
134 | return true
135 | }
136 |
137 | /////End ------ SETUP HHTabBarView ------
138 |
139 |
140 | func applicationWillResignActive(_ application: UIApplication) { }
141 | func applicationDidEnterBackground(_ application: UIApplication) { }
142 | func applicationWillEnterForeground(_ application: UIApplication) { }
143 | func applicationDidBecomeActive(_ application: UIApplication) { }
144 | func applicationWillTerminate(_ application: UIApplication) { }
145 | }
146 |
--------------------------------------------------------------------------------
/HHTabBarView/HHTabBarView/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/HHTabBarView/HHTabBarView/Assets.xcassets/location-pin.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "location-pin-2.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "location-pin-1.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "location-pin.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/HHTabBarView/HHTabBarView/Assets.xcassets/location-pin.imageset/location-pin-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hemangshah/HHTabBarView/3dc02898857d4d6bba99bd3b368ff7f664968d36/HHTabBarView/HHTabBarView/Assets.xcassets/location-pin.imageset/location-pin-1.png
--------------------------------------------------------------------------------
/HHTabBarView/HHTabBarView/Assets.xcassets/location-pin.imageset/location-pin-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hemangshah/HHTabBarView/3dc02898857d4d6bba99bd3b368ff7f664968d36/HHTabBarView/HHTabBarView/Assets.xcassets/location-pin.imageset/location-pin-2.png
--------------------------------------------------------------------------------
/HHTabBarView/HHTabBarView/Assets.xcassets/location-pin.imageset/location-pin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hemangshah/HHTabBarView/3dc02898857d4d6bba99bd3b368ff7f664968d36/HHTabBarView/HHTabBarView/Assets.xcassets/location-pin.imageset/location-pin.png
--------------------------------------------------------------------------------
/HHTabBarView/HHTabBarView/Assets.xcassets/refresh.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "refresh-2.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "refresh-1.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "refresh.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/HHTabBarView/HHTabBarView/Assets.xcassets/refresh.imageset/refresh-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hemangshah/HHTabBarView/3dc02898857d4d6bba99bd3b368ff7f664968d36/HHTabBarView/HHTabBarView/Assets.xcassets/refresh.imageset/refresh-1.png
--------------------------------------------------------------------------------
/HHTabBarView/HHTabBarView/Assets.xcassets/refresh.imageset/refresh-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hemangshah/HHTabBarView/3dc02898857d4d6bba99bd3b368ff7f664968d36/HHTabBarView/HHTabBarView/Assets.xcassets/refresh.imageset/refresh-2.png
--------------------------------------------------------------------------------
/HHTabBarView/HHTabBarView/Assets.xcassets/refresh.imageset/refresh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hemangshah/HHTabBarView/3dc02898857d4d6bba99bd3b368ff7f664968d36/HHTabBarView/HHTabBarView/Assets.xcassets/refresh.imageset/refresh.png
--------------------------------------------------------------------------------
/HHTabBarView/HHTabBarView/Assets.xcassets/sofa.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "sofa-2.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "sofa-1.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "sofa.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/HHTabBarView/HHTabBarView/Assets.xcassets/sofa.imageset/sofa-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hemangshah/HHTabBarView/3dc02898857d4d6bba99bd3b368ff7f664968d36/HHTabBarView/HHTabBarView/Assets.xcassets/sofa.imageset/sofa-1.png
--------------------------------------------------------------------------------
/HHTabBarView/HHTabBarView/Assets.xcassets/sofa.imageset/sofa-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hemangshah/HHTabBarView/3dc02898857d4d6bba99bd3b368ff7f664968d36/HHTabBarView/HHTabBarView/Assets.xcassets/sofa.imageset/sofa-2.png
--------------------------------------------------------------------------------
/HHTabBarView/HHTabBarView/Assets.xcassets/sofa.imageset/sofa.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hemangshah/HHTabBarView/3dc02898857d4d6bba99bd3b368ff7f664968d36/HHTabBarView/HHTabBarView/Assets.xcassets/sofa.imageset/sofa.png
--------------------------------------------------------------------------------
/HHTabBarView/HHTabBarView/Assets.xcassets/target.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "target-2.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "target-1.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "target.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/HHTabBarView/HHTabBarView/Assets.xcassets/target.imageset/target-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hemangshah/HHTabBarView/3dc02898857d4d6bba99bd3b368ff7f664968d36/HHTabBarView/HHTabBarView/Assets.xcassets/target.imageset/target-1.png
--------------------------------------------------------------------------------
/HHTabBarView/HHTabBarView/Assets.xcassets/target.imageset/target-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hemangshah/HHTabBarView/3dc02898857d4d6bba99bd3b368ff7f664968d36/HHTabBarView/HHTabBarView/Assets.xcassets/target.imageset/target-2.png
--------------------------------------------------------------------------------
/HHTabBarView/HHTabBarView/Assets.xcassets/target.imageset/target.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hemangshah/HHTabBarView/3dc02898857d4d6bba99bd3b368ff7f664968d36/HHTabBarView/HHTabBarView/Assets.xcassets/target.imageset/target.png
--------------------------------------------------------------------------------
/HHTabBarView/HHTabBarView/Assets.xcassets/umbrella.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "umbrella-2.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "umbrella-1.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "umbrella.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/HHTabBarView/HHTabBarView/Assets.xcassets/umbrella.imageset/umbrella-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hemangshah/HHTabBarView/3dc02898857d4d6bba99bd3b368ff7f664968d36/HHTabBarView/HHTabBarView/Assets.xcassets/umbrella.imageset/umbrella-1.png
--------------------------------------------------------------------------------
/HHTabBarView/HHTabBarView/Assets.xcassets/umbrella.imageset/umbrella-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hemangshah/HHTabBarView/3dc02898857d4d6bba99bd3b368ff7f664968d36/HHTabBarView/HHTabBarView/Assets.xcassets/umbrella.imageset/umbrella-2.png
--------------------------------------------------------------------------------
/HHTabBarView/HHTabBarView/Assets.xcassets/umbrella.imageset/umbrella.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hemangshah/HHTabBarView/3dc02898857d4d6bba99bd3b368ff7f664968d36/HHTabBarView/HHTabBarView/Assets.xcassets/umbrella.imageset/umbrella.png
--------------------------------------------------------------------------------
/HHTabBarView/HHTabBarView/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/HHTabBarView/HHTabBarView/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
30 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
--------------------------------------------------------------------------------
/HHTabBarView/HHTabBarView/FirstViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FirstViewController.swift
3 | // HHTabBarView
4 | //
5 | // Created by Hemang Shah on 7/17/17.
6 | // Copyright © 2017 Hemang Shah. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class FirstViewController: UIViewController {
12 |
13 | override func viewDidLoad() {
14 | super.viewDidLoad()
15 | // Do any additional setup after loading the view.
16 | self.title = "Location"
17 | }
18 |
19 | override func viewWillAppear(_ animated: Bool) {
20 | super.viewWillAppear(animated)
21 | // This will be helpful in locking the current tab if we're already in the first view-controller in navigation flow.
22 | HHTabBarView.shared.lockCurrentTab()
23 | }
24 |
25 | override func viewWillDisappear(_ animated: Bool) {
26 | super.viewWillDisappear(animated)
27 | // This will be helpful to unlock the locked tab when we're going forward from the first view-controller in navigation flow.
28 | HHTabBarView.shared.unlockAllTabs()
29 | }
30 | }
31 |
32 | extension FirstViewController: UITableViewDataSource {
33 | func numberOfSections(in tableView: UITableView) -> Int {
34 | return 1
35 | }
36 |
37 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
38 | return 100
39 | }
40 |
41 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
42 | let cell = tableView.dequeueReusableCell(withIdentifier: "cellIdentifier", for: indexPath)
43 | cell.textLabel?.text = "Location \(indexPath.row)"
44 | return cell
45 | }
46 | }
47 |
48 | extension FirstViewController: UITableViewDelegate {
49 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
50 | tableView.deselectRow(at: indexPath, animated: false)
51 | let viewController = UIViewController()
52 | viewController.title = "Location \(indexPath.row)"
53 | viewController.view.backgroundColor = UIColor.white
54 | self.navigationController?.pushViewController(viewController, animated: true)
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/HHTabBarView/HHTabBarView/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 2.3.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIRequiredDeviceCapabilities
26 |
27 | armv7
28 |
29 | UISupportedInterfaceOrientations
30 |
31 | UIInterfaceOrientationPortrait
32 | UIInterfaceOrientationLandscapeLeft
33 | UIInterfaceOrientationLandscapeRight
34 |
35 | UISupportedInterfaceOrientations~ipad
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationPortraitUpsideDown
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/HHTabBarView/HHTabBarView/SecondViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // HHTabBarView
4 | //
5 | // Created by Hemang Shah on 7/17/17.
6 | // Copyright © 2017 Hemang Shah. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class SecondViewController: UIViewController {
12 |
13 | var apd = UIApplication.shared.delegate as! AppDelegate
14 |
15 | override func viewDidLoad() {
16 | super.viewDidLoad()
17 | // Do any additional setup after loading the view, typically from a nib.
18 | self.title = "Refresh"
19 | }
20 |
21 | @IBAction func actionShowHideTabBar(_ sender: UISwitch) {
22 | apd.hhTabBarView.toggleShowOrHide()
23 | }
24 |
25 | @IBAction func actionShowHideNavigationBar(_ sender: UISwitch) {
26 | self.navigationController?.isNavigationBarHidden = !sender.isOn
27 | }
28 |
29 | @IBAction func actionShowHideBadge(_ sender: UISwitch) {
30 | if sender.isOn {
31 | apd.hhTabBarView.updateBadge(forTabIndex: 0, withValue: Int(arc4random()%30) + 1)
32 | apd.hhTabBarView.updateBadge(forTabIndex: 2, withValue: Int(arc4random()%30) + 1)
33 | apd.hhTabBarView.updateBadge(forTabIndex: 3, withValue: Int(arc4random()%30) + 1)
34 | apd.hhTabBarView.updateBadge(forTabIndex: 4, withValue: Int(arc4random()%30) + 1)
35 | } else {
36 | //Setting 0 will hide the Badge.
37 | apd.hhTabBarView.updateBadge(forTabIndex: 0, withValue: 0)
38 | apd.hhTabBarView.updateBadge(forTabIndex: 2, withValue: 0)
39 | apd.hhTabBarView.updateBadge(forTabIndex: 3, withValue: 0)
40 | apd.hhTabBarView.updateBadge(forTabIndex: 4, withValue: 0)
41 | }
42 | }
43 |
44 | @IBAction func actionLockUnlockLastTab(_ sender: UISwitch) {
45 | if sender.isOn {
46 | apd.hhTabBarView.lockTabIndexes = [4]
47 | } else {
48 | apd.hhTabBarView.lockTabIndexes = []
49 | }
50 | }
51 |
52 | @IBAction func actionShowTabChangeAnimation(_ sender: UISwitch) {
53 | if sender.isOn {
54 | apd.hhTabBarView.tabChangeAnimationType = .shake
55 | } else {
56 | apd.hhTabBarView.tabChangeAnimationType = .none
57 | }
58 | }
59 |
60 | @IBAction func actionReverseTabs(_ sender: UISwitch) {
61 | if sender.isOn {
62 | self.apd.hhTabBarView.rightToLeft()
63 | } else {
64 | self.apd.hhTabBarView.leftToRight()
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/HHTabBarView/HHTabBarView/Source/HHButton+Extension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HHButton+Extension.swift
3 | // HHTabBarView
4 | //
5 | // Created by Hemang on 03/10/18.
6 | // Copyright © 2018 Hemang Shah. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | public extension HHTabButton {
12 |
13 | internal func pulsate() {
14 | let pulse = CASpringAnimation(keyPath: "transform.scale")
15 | pulse.duration = 0.15
16 | pulse.fromValue = 0.95
17 | pulse.toValue = 1.0
18 | pulse.autoreverses = true
19 | pulse.repeatCount = 2
20 | pulse.initialVelocity = 0.5
21 | pulse.damping = 1.0
22 | layer.add(pulse, forKey: "pulse")
23 | }
24 |
25 | internal func flash() {
26 | let flash = CABasicAnimation(keyPath: "opacity")
27 | flash.duration = 0.15
28 | flash.fromValue = 1
29 | flash.toValue = 0.1
30 | flash.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
31 | flash.autoreverses = true
32 | flash.repeatCount = 3
33 | layer.add(flash, forKey: nil)
34 | }
35 |
36 | internal func shake() {
37 | let shake = CABasicAnimation(keyPath: "position")
38 | shake.duration = 0.05
39 | shake.repeatCount = 2
40 | shake.autoreverses = true
41 | let fromPoint = CGPoint(x: center.x - 5, y: center.y)
42 | let fromValue = NSValue(cgPoint: fromPoint)
43 | let toPoint = CGPoint(x: center.x + 5, y: center.y)
44 | let toValue = NSValue(cgPoint: toPoint)
45 | shake.fromValue = fromValue
46 | shake.toValue = toValue
47 | layer.add(shake, forKey: "position")
48 | }
49 |
50 | ///Set Background Color for various UIButton states.
51 | func setHHTabBackgroundColor(color: UIColor, forState: UIControl.State) {
52 | UIGraphicsBeginImageContext(CGSize(width: 1, height: 1))
53 | UIGraphicsGetCurrentContext()!.setFillColor(color.cgColor)
54 | UIGraphicsGetCurrentContext()!.fill(CGRect(x: 0, y: 0, width: 1, height: 1))
55 | let colorImage = UIGraphicsGetImageFromCurrentImageContext()
56 | UIGraphicsEndImageContext()
57 | self.setBackgroundImage(colorImage, for: forState)
58 | self.setBackgroundImage(colorImage, for: .highlighted)
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/HHTabBarView/HHTabBarView/Source/HHTabBarView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HHTabBarView.swift
3 | // HHTabBarView
4 | //
5 | // Created by Hemang Shah on 7/17/17.
6 | // Copyright © 2017 Hemang Shah. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | private let hhTabBarViewHeight: CGFloat = 49.0
12 |
13 | ///Animation Types for Tab Changes.
14 | public enum HHTabBarTabChangeAnimationType {
15 | case flash, shake, pulsate, none
16 | }
17 |
18 | ///Position Types for HHTabBarView.
19 | public enum HHTabBarViewPosition {
20 | case top, bottom
21 | }
22 |
23 | private extension UIScreen {
24 | class var width: CGFloat {
25 | return UIScreen.main.bounds.size.width
26 | }
27 |
28 | class var height: CGFloat {
29 | return UIScreen.main.bounds.size.height
30 | }
31 | }
32 |
33 | ///Easily configured HHTabBarView class to replace the iOS default UITabBarController.
34 | public class HHTabBarView: UIView {
35 |
36 | ///Singleton
37 | public static var shared = HHTabBarView()
38 |
39 | ///For Internal Navigation
40 | private(set) public var referenceUITabBarController = UITabBarController()
41 | ///Current Tab Index: Internal Usage Only.
42 | private(set) var currentTabIndex: Int = 0
43 |
44 | // MARK: Setters
45 | ///Animation Type. Default: none.
46 | public var tabChangeAnimationType: HHTabBarTabChangeAnimationType = .none
47 |
48 | ///TabBarView Position. Default: bottom. Also, don't forget to set 'tabBarViewTopPositionValue' if tabBarViewPosition = 'top'.
49 | public var tabBarViewPosition: HHTabBarViewPosition = .bottom
50 |
51 | /// If tabBarViewPosition = top then you should set it according to your UI requirements.
52 | public var tabBarViewTopPositionValue: CGFloat = 64.0
53 |
54 | ///Set HHTabButton for HHTabBarView.
55 | public var tabBarTabs = [HHTabButton]() {
56 | didSet {
57 | createTabs()
58 | }
59 | }
60 |
61 | ///Set the default tab for HHTabBarView.
62 | public var defaultIndex = 0 {
63 | didSet {
64 | if isTabsAvailable() {
65 | selectTabAtIndex(withIndex: defaultIndex)
66 | }
67 | }
68 | }
69 |
70 | //Lock Index for Tabs
71 | ///Specify indexes of tabs to lock. [0, 2, 3]
72 | public var lockTabIndexes = [Int]() {
73 | didSet {
74 | lockUnlockTabs()
75 | }
76 | }
77 |
78 | ///Update Badge Value for Specific Tab.
79 | public func updateBadge(forTabIndex index: Int, withValue value: Int) {
80 | if isTabsAvailable() {
81 | let hhTabButton = tabBarTabs[index]
82 | hhTabButton.badgeValue = value
83 | }
84 | }
85 |
86 | ///Reverse the Tabs from RightToLeft [Usage English/Arabic UI]
87 | public func rightToLeft() {
88 | let t = CGAffineTransform.init(scaleX: -1, y: -1)
89 | self.transform = t
90 | _ = self.subviews.map { $0.transform = t }
91 | }
92 |
93 | ///Reverse the Tabs from LeftToRight [Usage English/Arabic UI]
94 | public func leftToRight() {
95 | let t = CGAffineTransform.init(scaleX: 1, y: 1)
96 | self.transform = t
97 | _ = self.subviews.map { $0.transform = t }
98 | }
99 |
100 | ///Completion Handler for Tab Changes
101 | public var onTabTapped:((_ tabIndex: Int, _ isSameTab: Bool, _ controller: Any?) -> Void)? = nil
102 |
103 | // MARK: Init
104 | private override init(frame: CGRect) {
105 | super.init(frame: frame)
106 | }
107 |
108 | @available(*, unavailable)
109 | required public init?(coder aDecoder: NSCoder) {
110 | fatalError("init(coder:) has not been implemented")
111 | }
112 |
113 | required
114 | convenience public init() {
115 | //Set frame for HHTabBarView.
116 | let rect = CGRect.init(x: 0.0, y: 0.0, width: UIScreen.width, height: hhTabBarViewHeight)
117 | self.init(frame: rect)
118 | //You can configure it to any background color you want.
119 | backgroundColor = .clear
120 | //For Portrait/Landscape.
121 | autoresizingMask = [.flexibleWidth, .flexibleBottomMargin, .flexibleLeftMargin, .flexibleRightMargin]
122 | //Adding to UITabBarController's subview.
123 | referenceUITabBarController.view.addSubview(self)
124 | //This is important otherwise tabBar will be visible if tabChangeAnimationType = .flash
125 | referenceUITabBarController.tabBar.isHidden = true
126 | referenceUITabBarController.tabBar.alpha = 0.0
127 | }
128 |
129 | public override func layoutSubviews() {
130 | frame = getHHTabBarViewFrame()
131 | }
132 |
133 | ///Helper to Select a Particular Tab.
134 | public func selectTabAtIndex(withIndex tabIndex: Int) {
135 | // Tab Selection/Deselection
136 | _ = tabBarTabs.map { $0.isSelected = ($0.tabIndex == tabIndex) ? true : false}
137 | // Apply Tab Changes in UITabBarController
138 | referenceUITabBarController.selectedIndex = tabIndex
139 | // Lock or Unlock the Tabs if requires.
140 | lockUnlockTabs()
141 |
142 | currentTabIndex = tabIndex
143 | }
144 |
145 | /// A convenience method to show or hide HHTabBarView.
146 | public func toggleShowOrHide() {
147 | self.isHidden = !isHidden
148 | }
149 |
150 | // Overriding Default Properties
151 | /// To hide the HHTabBarView.
152 | override public var isHidden: Bool {
153 | willSet {
154 | self.referenceUITabBarController.tabBar.isHidden = !isHidden
155 | }
156 | }
157 |
158 | /// Lock Current tab, if don't want to select the same tab again.
159 | public func lockCurrentTab() {
160 | for (index, tab) in tabBarTabs.enumerated() {
161 | if index == currentTabIndex {
162 | if let controllers = self.referenceUITabBarController.viewControllers, let navcon = controllers[currentTabIndex] as? UINavigationController {
163 | if navcon.viewControllers.count == 1 {
164 | tab.isUserInteractionEnabled = false
165 | break
166 | }
167 | }
168 | }
169 | }
170 | }
171 |
172 | /// Unlock all of the tabs at once.
173 | public func unlockAllTabs(ignoreAlreadyLocked: Bool = false) {
174 | unlockAllTabs(); if ignoreAlreadyLocked { lockSpecifiedTab() }
175 | }
176 |
177 | // MARK: Helpers
178 | private func getHHTabBarViewFrame() -> CGRect {
179 | let screentWidth = UIScreen.width
180 | let screentHeight = UIScreen.height
181 | var tabBarHeight = hhTabBarViewHeight
182 |
183 | if tabBarViewPosition == .top {
184 | return CGRect.init(x: 0.0, y: tabBarViewTopPositionValue, width: screentWidth, height: tabBarHeight)
185 | } else {
186 | if #available(iOS 11.0, *) {
187 | let bottomPadding = referenceUITabBarController.tabBar.safeAreaInsets.bottom
188 | tabBarHeight += bottomPadding
189 | }
190 | return CGRect.init(x: 0.0, y: (screentHeight - tabBarHeight), width: screentWidth, height: tabBarHeight)
191 | }
192 | }
193 |
194 | private func isTabsAvailable() -> Bool {
195 | return tabBarTabs.isEmpty ? false : true
196 | }
197 |
198 | private func unlockAllTabs() {
199 | _ = tabBarTabs.map { $0.isUserInteractionEnabled = true }
200 | }
201 |
202 | private func lockUnlockTabs() {
203 | //Unlock All Tabs Before Locking.
204 | unlockAllTabs()
205 | //Then Lock the provided Tab Indexes.
206 | lockSpecifiedTab()
207 | }
208 |
209 | private func lockSpecifiedTab() {
210 | if !lockTabIndexes.isEmpty {
211 | for index in lockTabIndexes {
212 | let hhTabButton = tabBarTabs[index]
213 | hhTabButton.isUserInteractionEnabled = false
214 | }
215 | }
216 | }
217 |
218 | private func createTabs() {
219 | var xPos: CGFloat = 0.0
220 | let yPos: CGFloat = 0.0
221 | let width = frame.size.width/CGFloat(tabBarTabs.count)
222 | let height = frame.size.height
223 | for hhTabButton in tabBarTabs {
224 | hhTabButton.frame = CGRect.init(x: xPos, y: yPos, width: width, height: height)
225 | hhTabButton.addTarget(self, action: #selector(actionTabTapped(tab:)), for: .touchUpInside)
226 | hhTabButton.badgeValue = 0
227 | addSubview(hhTabButton)
228 | xPos += width
229 | }
230 | defaultIndex = 0
231 | }
232 |
233 | //Actions
234 | @objc private func actionTabTapped(tab: HHTabButton) {
235 | let tappedTabIndex = tab.tabIndex
236 | var isSameTab: Bool = false
237 | let controller = referenceUITabBarController.viewControllers?[tappedTabIndex]
238 | if currentTabIndex == tappedTabIndex {
239 | isSameTab = true
240 | } else {
241 | isSameTab = false
242 | animateTabBarButton(tabBarButton: tab)
243 | selectTabAtIndex(withIndex: tab.tabIndex)
244 | }
245 | onTabTapped?(tappedTabIndex, isSameTab, controller)
246 | }
247 |
248 | //Perform Animation on Tab Changes.
249 | private func animateTabBarButton(tabBarButton: HHTabButton) {
250 | switch self.tabChangeAnimationType {
251 | case .flash: tabBarButton.flash()
252 | case .shake: tabBarButton.shake()
253 | case .pulsate: tabBarButton.pulsate()
254 | default: break
255 | }
256 | }
257 | }
258 |
--------------------------------------------------------------------------------
/HHTabBarView/HHTabBarView/Source/HHTabButton.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HHTabButton.swift
3 | // HHTabBarView
4 | //
5 | // Created by Hemang Shah on 7/17/17.
6 | // Copyright © 2017 Hemang Shah. All rights reserved.
7 | //
8 |
9 | /*
10 | Idea of custom positions of title and image.
11 | Credits: https://gist.github.com/gbitaudeau/6540847de8f5ee9f2e0393a00d2cb11e
12 | */
13 |
14 | import UIKit
15 |
16 | ///This is to show tabs inside the HHTabBarView. As it's subclassed of UIButton you can configure it as much as iOS supports.
17 | public class HHTabButton: UIButton {
18 |
19 | ///Vertical Alignments
20 | public enum VerticalAlignment: String {
21 | case center, top, bottom, unset
22 | }
23 |
24 | ///Horizontal Alignments
25 | public enum HorizontalAlignment: String {
26 | case center, left, right, unset
27 | }
28 |
29 | ///Spacing between then image and title.
30 | public var imageToTitleSpacing: CGFloat = 8.0 {
31 | didSet {
32 | setNeedsLayout()
33 | }
34 | }
35 |
36 | ///Vertical alignment for the image.
37 | public var imageVerticalAlignment: VerticalAlignment = .unset {
38 | didSet {
39 | setNeedsLayout()
40 | }
41 | }
42 |
43 | ///Horizontal alignment for the image.
44 | public var imageHorizontalAlignment: HorizontalAlignment = .unset {
45 | didSet {
46 | setNeedsLayout()
47 | }
48 | }
49 |
50 | ///Set extra content edgeInsets.
51 | public var extraContentEdgeInsets: UIEdgeInsets = UIEdgeInsets.zero
52 |
53 | override public var contentEdgeInsets: UIEdgeInsets {
54 | get {
55 | return super.contentEdgeInsets
56 | }
57 | set {
58 | super.contentEdgeInsets = newValue
59 | self.extraContentEdgeInsets = newValue
60 | }
61 | }
62 |
63 | ///Set extra image edgeInsets.
64 | public var extraImageEdgeInsets: UIEdgeInsets = UIEdgeInsets.zero
65 |
66 | override public var imageEdgeInsets: UIEdgeInsets {
67 | get {
68 | return super.imageEdgeInsets
69 | }
70 | set {
71 | super.imageEdgeInsets = newValue
72 | self.extraImageEdgeInsets = newValue
73 | }
74 | }
75 |
76 | ///Set extra title edgeInsets.
77 | public var extraTitleEdgeInsets:UIEdgeInsets = UIEdgeInsets.zero
78 |
79 | override public var titleEdgeInsets: UIEdgeInsets {
80 | get {
81 | return super.titleEdgeInsets
82 | }
83 | set {
84 | super.titleEdgeInsets = newValue
85 | self.extraTitleEdgeInsets = newValue
86 | }
87 | }
88 |
89 | ///Unique index of tabs. (Should be start with 0)
90 | public var tabIndex:Int = 0
91 |
92 | ///To set badge value.
93 | internal var badgeValue: Int = 0 {
94 | willSet {
95 | self.addBadgeView()
96 | } didSet {
97 | self.updateBadgeView()
98 | }
99 | }
100 |
101 | ///Configure badge Label. Should be configure only after setting tabs array to HHTabBarView.
102 | public var badgeLabel: HHTabLabel?
103 |
104 | // MARK:Init
105 | required convenience public init(withTitle tabTitle: String?, tabImage: UIImage?, index: Int) {
106 | self.init(frame: CGRect.zero)
107 | self.setupButton(withTitle: tabTitle, tabImage: tabImage, index: index)
108 | }
109 |
110 | fileprivate func setupButton(withTitle tabTitle: String?, tabImage: UIImage?, index: Int) {
111 | self.backgroundColor = UIColor.clear
112 | self.autoresizingMask = [.flexibleWidth, .flexibleLeftMargin, .flexibleRightMargin, .flexibleHeight]
113 | self.tabIndex = index
114 | self.setImage(tabImage, for: .normal)
115 | self.setImage(tabImage, for: .selected)
116 | self.setTitle(tabTitle, for: .normal)
117 | self.setTitle(tabTitle, for: .selected)
118 | }
119 |
120 | //This is to add BadgeView within the HHTabButton. See badgeValue var to understand the usage.
121 | fileprivate func addBadgeView() {
122 |
123 | //If badge label is already created, no need to recreate.
124 | guard self.badgeLabel == nil else {
125 | return
126 | }
127 |
128 | let badgeSize: CGFloat = 20.0
129 | let margin: CGFloat = 3.0
130 | self.badgeLabel = HHTabLabel.init(frame: CGRect.init(x: self.frame.size.width - (badgeSize + margin), y: margin, width: badgeSize, height: badgeSize))
131 | self.badgeLabel!.isHidden = true //By default.
132 | self.addSubview(self.badgeLabel!)
133 | }
134 |
135 | //This is to update BadgeView within the HHTabButton. See badgeValue var to understand the usage.
136 | fileprivate func updateBadgeView() {
137 | if let label = self.badgeLabel {
138 | if self.badgeValue <= 0 {
139 | label.isHidden = true
140 | label.text = ""
141 | } else {
142 | label.isHidden = false
143 | label.text = String(self.badgeValue)
144 | }
145 | }
146 | }
147 |
148 | // MARK: Init
149 | public override init(frame: CGRect) {
150 | super.init(frame: frame)
151 | }
152 |
153 | required public init?(coder aDecoder: NSCoder) {
154 | fatalError("init(coder:) has not been implemented")
155 | }
156 |
157 | // MARK: LayoutSubviews
158 | override public func layoutSubviews() {
159 | if let imageSize = self.imageView?.image?.size,
160 | let font = self.titleLabel?.font,
161 | let textSize = self.titleLabel?.attributedText?.size() ?? self.titleLabel?.text?.size(withAttributes: [NSAttributedString.Key.font: font]) {
162 |
163 | var _imageEdgeInsets = UIEdgeInsets.zero
164 | var _titleEdgeInsets = UIEdgeInsets.zero
165 | var _contentEdgeInsets = UIEdgeInsets.zero
166 |
167 | let halfImageToTitleSpacing = imageToTitleSpacing / 2.0
168 |
169 | switch imageVerticalAlignment {
170 | case .bottom:
171 | _imageEdgeInsets.top = (textSize.height + imageToTitleSpacing) / 2.0
172 | _imageEdgeInsets.bottom = (-textSize.height - imageToTitleSpacing) / 2.0
173 | _titleEdgeInsets.top = (-imageSize.height - imageToTitleSpacing) / 2.0
174 | _titleEdgeInsets.bottom = (imageSize.height + imageToTitleSpacing) / 2.0
175 | _contentEdgeInsets.top = (min (imageSize.height, textSize.height) + imageToTitleSpacing) / 2.0
176 | _contentEdgeInsets.bottom = (min (imageSize.height, textSize.height) + imageToTitleSpacing) / 2.0
177 | //only works with contentVerticalAlignment = .center
178 | contentVerticalAlignment = .center
179 | case .top:
180 | _imageEdgeInsets.top = (-textSize.height - imageToTitleSpacing) / 2.0
181 | _imageEdgeInsets.bottom = (textSize.height + imageToTitleSpacing) / 2.0
182 | _titleEdgeInsets.top = (imageSize.height + imageToTitleSpacing) / 2.0
183 | _titleEdgeInsets.bottom = (-imageSize.height - imageToTitleSpacing) / 2.0
184 | _contentEdgeInsets.top = (min (imageSize.height, textSize.height) + imageToTitleSpacing) / 2.0
185 | _contentEdgeInsets.bottom = (min (imageSize.height, textSize.height) + imageToTitleSpacing) / 2.0
186 | //only works with contentVerticalAlignment = .center
187 | contentVerticalAlignment = .center
188 | case .center:
189 | //only works with contentVerticalAlignment = .center
190 | contentVerticalAlignment = .center
191 | break
192 | case .unset:
193 | break
194 | }
195 |
196 | switch imageHorizontalAlignment {
197 | case .left:
198 | _imageEdgeInsets.left = -halfImageToTitleSpacing
199 | _imageEdgeInsets.right = halfImageToTitleSpacing
200 | _titleEdgeInsets.left = halfImageToTitleSpacing
201 | _titleEdgeInsets.right = -halfImageToTitleSpacing
202 | _contentEdgeInsets.left = halfImageToTitleSpacing
203 | _contentEdgeInsets.right = halfImageToTitleSpacing
204 | case .right:
205 | _imageEdgeInsets.left = textSize.width + halfImageToTitleSpacing
206 | _imageEdgeInsets.right = -textSize.width - halfImageToTitleSpacing
207 | _titleEdgeInsets.left = -imageSize.width - halfImageToTitleSpacing
208 | _titleEdgeInsets.right = imageSize.width + halfImageToTitleSpacing
209 | _contentEdgeInsets.left = halfImageToTitleSpacing
210 | _contentEdgeInsets.right = halfImageToTitleSpacing
211 | case .center:
212 | _imageEdgeInsets.left = textSize.width / 2.0
213 | _imageEdgeInsets.right = -textSize.width / 2.0
214 | _titleEdgeInsets.left = -imageSize.width / 2.0
215 | _titleEdgeInsets.right = imageSize.width / 2.0
216 | _contentEdgeInsets.left = -((imageSize.width + textSize.width) - max (imageSize.width, textSize.width)) / 2.0
217 | _contentEdgeInsets.right = -((imageSize.width + textSize.width) - max (imageSize.width, textSize.width)) / 2.0
218 | case .unset:
219 | break
220 | }
221 |
222 | _contentEdgeInsets.top += extraContentEdgeInsets.top
223 | _contentEdgeInsets.bottom += extraContentEdgeInsets.bottom
224 | _contentEdgeInsets.left += extraContentEdgeInsets.left
225 | _contentEdgeInsets.right += extraContentEdgeInsets.right
226 |
227 | _imageEdgeInsets.top += extraImageEdgeInsets.top
228 | _imageEdgeInsets.bottom += extraImageEdgeInsets.bottom
229 | _imageEdgeInsets.left += extraImageEdgeInsets.left
230 | _imageEdgeInsets.right += extraImageEdgeInsets.right
231 |
232 | _titleEdgeInsets.top += extraTitleEdgeInsets.top
233 | _titleEdgeInsets.bottom += extraTitleEdgeInsets.bottom
234 | _titleEdgeInsets.left += extraTitleEdgeInsets.left
235 | _titleEdgeInsets.right += extraTitleEdgeInsets.right
236 |
237 | super.imageEdgeInsets = _imageEdgeInsets
238 | super.titleEdgeInsets = _titleEdgeInsets
239 | super.contentEdgeInsets = _contentEdgeInsets
240 |
241 | } else {
242 | super.imageEdgeInsets = extraImageEdgeInsets
243 | super.titleEdgeInsets = extraTitleEdgeInsets
244 | super.contentEdgeInsets = extraContentEdgeInsets
245 | }
246 |
247 | super.layoutSubviews()
248 | }
249 | }
250 |
--------------------------------------------------------------------------------
/HHTabBarView/HHTabBarView/Source/HHTabLabel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HHTabLabel.swift
3 | // HHTabBarView
4 | //
5 | // Created by Hemang Shah on 7/26/17.
6 | // Copyright © 2017 Hemang Shah. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | ///This is to show badge inside the HHTabButton (i.e. HHTabBarView's tab). As it's subclassed of UILabel you can configure it as much as iOS supports.
12 | public class HHTabLabel: UILabel {
13 | override init(frame: CGRect) {
14 | super.init(frame: frame)
15 | backgroundColor = .red
16 | layer.cornerRadius = frame.size.width/2.0
17 | layer.masksToBounds = true
18 | textColor = .white
19 | textAlignment = .center
20 | font = UIFont.init(name: "Helvetica-Light", size: 10.0)
21 | adjustsFontSizeToFitWidth = true
22 | }
23 |
24 | required public init?(coder aDecoder: NSCoder) {
25 | fatalError("init(coder:) has not been implemented")
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Hemang Shah
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | A lightweight customized tabbar view.
4 |
5 | [](https://github.com/hemangshah/HHTabBarView/blob/master/LICENSE)
6 | [](https://www.apple.com/in/ios/)
7 | [](https://swift.org/)
8 | [](https://madewithlove.org.in/)
9 | [](https://github.com/matteocrippa/awesome-swift/)
10 |
11 | 1. [Screenshots](#screenshots)
12 | 2. [Features](#features)
13 | 3. [Installation](#installation)
14 | 4. [Setup](#setup)
15 | 5. [ToDos](#todos)
16 | 6. [Credits](#credits)
17 | 7. [Thanks](#thank-you)
18 | 8. [License](#license)
19 |
20 | ## Screenshots
21 |
22 |
23 |
24 |  |
25 |  |
26 |  |
27 |
28 |
29 |  |
30 |  |
31 |  |
32 |
33 |
34 |  |
35 |  |
36 |
37 |
38 |  |
39 |
40 |
41 |
42 | ## Features
43 |
44 | 1. Easily Configurable and Setup. Create tabs with Title, or Image or both.
45 | 2. Dynamic Tabs Configurations.
46 | 3. Detect Taps in a completion block.
47 | 4. Show/Hide Badge Value in individual tabs. Easily Configure as per the needs.
48 | 5. Lock/Unlock particular tabs.
49 | 6. Easily show/hide UINavigationBar and HHTabBarView.
50 | 7. Lightweight with zero dependancies.
51 | 8. Change UI of HHTabBarView (LeftToRight or RightToLeft) as per the needs.
52 | 9. Change HHTabBarView position as per UI requirements. Supports: Top and Bottom (Default).
53 |
54 | ##### Note: I don't recommended displaying HHTabBarView at the top. It's always good at the bottom.
55 |
56 | ## Installation
57 |
58 | 1. **Manually** – Add `HHTabBarView/Source` folder to your Project. And you're good to use `HHTabBarView`.
59 |
60 | 2. **CocoaPods**: – `pod 'HHTabBarView'`
61 |
62 | > You can read the [CHANGELOG](https://github.com/hemangshah/HHTabBarView/blob/master/CHANGELOG.md) file for a particular release.
63 |
64 | ## Setup
65 |
66 | **Important**: Please note that `HHTabBarView` is currently not supports `UIStoryBoard`. Means, you will have to create `HHTabBarView` programmatically. It is advised to setup `HHTabBarView` in `AppDelegate.swift` for your easyness.
67 |
68 | 1. Initialize and keeping reference of `HHTabBarView`. 📌
69 | ````swift
70 | let hhTabBarView = HHTabBarView.shared
71 | ````
72 |
73 | 2. Keeping reference of iOS default `UITabBarController`. 📌
74 | ````swift
75 | let referenceTabBarController = HHTabBarView.shared.referenceUITabBarController
76 | ````
77 |
78 | 3. Setup referenced `UITabBarController` 📌
79 | ````swift
80 | func setupReferenceUITabBarController() -> Void {
81 |
82 | //Creating a storyboard reference
83 | let storyboard = UIStoryboard.init(name: "Main", bundle: Bundle.main)
84 |
85 | //Creating navigation controller for navigation inside the first tab.
86 | let navigationController1: UINavigationController = UINavigationController.init(rootViewController: storyboard.instantiateViewController(withIdentifier: "FirstViewControllerID"))
87 |
88 | //Creating navigation controller for navigation inside the second tab.
89 | let navigationController2: UINavigationController = UINavigationController.init(rootViewController: storyboard.instantiateViewController(withIdentifier: "SecondViewControllerID"))
90 |
91 | //Update referenced TabbarController with your viewcontrollers
92 | referenceTabBarController.setViewControllers([navigationController1, navigationController2], animated: false)
93 | }
94 | ````
95 |
96 | 4. Setup `HHTabBarView` 📌
97 | ````swift
98 | //Update HHTabBarView reference with the tabs requires.
99 | func setupHHTabBarView() -> Void {
100 |
101 | //Default & Selected Background Color
102 | let defaultTabColor = UIColor.white
103 | let selectedTabColor = UIColor.init(red: 234/255, green: 218/255, blue: 195/255, alpha: 1.0)
104 | let tabFont = UIFont.init(name: "Helvetica-Light", size: 14.0)
105 |
106 | //Create Custom Tabs
107 | let t1 = HHTabButton.init(withTitle: "Calendar", tabImage: UIImage.init(named: "Calendar")!, index: 0)
108 | t1.titleLabel?.font = tabFont
109 | t1.titleLabel?.textColor = UIColor.black
110 | t1.setHHTabBackgroundColor(color: defaultTabColor, forState: .normal)
111 | t1.setHHTabBackgroundColor(color: selectedTabColor, forState: .selected)
112 |
113 | let t2 = HHTabButton.init(withTitle: "Refresh", tabImage: UIImage.init(named: "Refresh")!, index: 1)
114 | t2.titleLabel?.font = tabFont
115 | t2.titleLabel?.textColor = UIColor.black
116 | t2.setHHTabBackgroundColor(color: defaultTabColor, forState: .normal)
117 | t2.setHHTabBackgroundColor(color: selectedTabColor, forState: .selected)
118 |
119 | //Note: As HHTabButton are subclassed of UIButton so you can modify it as much as possible.
120 |
121 | //Set Custom Tabs
122 | hhTabBarView.tabBarTabs = [t1, t2]
123 |
124 | //Set Default Index for HHTabBarView.
125 | hhTabBarView.defaultIndex = 1
126 |
127 | //Show Animation on Switching Tabs
128 | hhTabBarView.tabChangeAnimationType = .none
129 |
130 | //Handle Tab Change Event
131 | hhTabBarView.onTabTapped = { (tabIndex) in
132 | print("Selected Tab Index:\(tabIndex)")
133 | }
134 | }
135 | ````
136 |
137 | 5. Setup `window` of your application inside the 📌
138 | ````swift
139 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
140 | // Override point for customization after application launch.
141 |
142 | //Setup HHTabBarView
143 | setupReferenceUITabBarController()
144 | setupHHTabBarView()
145 |
146 | //Setup Application Window
147 | self.window = UIWindow.init(frame: UIScreen.main.bounds)
148 | self.window?.rootViewController = self.referenceTabBarController
149 | self.window?.makeKeyAndVisible()
150 |
151 | return true
152 | }
153 | ````
154 |
155 | 6. Done! ✅
156 |
157 |
158 |
159 | ## ToDo[s]
160 |
161 | - [x] Update README with multiple example usage and screenshots.
162 |
163 | You can [watch](https://github.com/hemangshah/HHTabBarView/subscription) to HHTabBarView to see continuous updates. Stay tuned.
164 |
165 | Have an idea for improvements of this class?
166 | Please open an [issue](https://github.com/hemangshah/HHTabBarView/issues/new).
167 |
168 | ## Credits
169 |
170 | [Hemang Shah](https://about.me/hemang.shah)
171 |
172 | **You can shoot me an [email](http://www.google.com/recaptcha/mailhide/d?k=01IzGihUsyfigse2G9z80rBw==&c=vU7vyAaau8BctOAIJFwHVbKfgtIqQ4QLJaL73yhnB3k=) to contact.**
173 |
174 | ## Thank You!!
175 |
176 | See the [contributions](https://github.com/hemangshah/HHTabBarView/blob/master/CONTRIBUTIONS.md) for details.
177 |
178 | ## License
179 |
180 | The MIT License (MIT)
181 |
182 | > Read the [LICENSE](https://github.com/hemangshah/HHTabBarView/blob/master/LICENSE) file for details.
183 |
--------------------------------------------------------------------------------
/Screenshots/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hemangshah/HHTabBarView/3dc02898857d4d6bba99bd3b368ff7f664968d36/Screenshots/1.png
--------------------------------------------------------------------------------
/Screenshots/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hemangshah/HHTabBarView/3dc02898857d4d6bba99bd3b368ff7f664968d36/Screenshots/2.png
--------------------------------------------------------------------------------
/Screenshots/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hemangshah/HHTabBarView/3dc02898857d4d6bba99bd3b368ff7f664968d36/Screenshots/3.png
--------------------------------------------------------------------------------
/Screenshots/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hemangshah/HHTabBarView/3dc02898857d4d6bba99bd3b368ff7f664968d36/Screenshots/4.png
--------------------------------------------------------------------------------
/Screenshots/5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hemangshah/HHTabBarView/3dc02898857d4d6bba99bd3b368ff7f664968d36/Screenshots/5.png
--------------------------------------------------------------------------------
/Screenshots/6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hemangshah/HHTabBarView/3dc02898857d4d6bba99bd3b368ff7f664968d36/Screenshots/6.png
--------------------------------------------------------------------------------
/Screenshots/7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hemangshah/HHTabBarView/3dc02898857d4d6bba99bd3b368ff7f664968d36/Screenshots/7.png
--------------------------------------------------------------------------------
/Screenshots/8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hemangshah/HHTabBarView/3dc02898857d4d6bba99bd3b368ff7f664968d36/Screenshots/8.png
--------------------------------------------------------------------------------
/Screenshots/HHTabBarFlow.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hemangshah/HHTabBarView/3dc02898857d4d6bba99bd3b368ff7f664968d36/Screenshots/HHTabBarFlow.gif
--------------------------------------------------------------------------------
/logo/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hemangshah/HHTabBarView/3dc02898857d4d6bba99bd3b368ff7f664968d36/logo/favicon.png
--------------------------------------------------------------------------------
/logo/favicon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
21 |
--------------------------------------------------------------------------------
/logo/logotype-a.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hemangshah/HHTabBarView/3dc02898857d4d6bba99bd3b368ff7f664968d36/logo/logotype-a.png
--------------------------------------------------------------------------------
/logo/logotype-a.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
104 |
--------------------------------------------------------------------------------
/logo/logotype-b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hemangshah/HHTabBarView/3dc02898857d4d6bba99bd3b368ff7f664968d36/logo/logotype-b.png
--------------------------------------------------------------------------------
/logo/logotype-b.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
107 |
--------------------------------------------------------------------------------