├── .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 | ![HHTabBarView](https://github.com/Tobaloidee/HHTabBarView/blob/master/logo/logotype-a.png) 2 | 3 | A lightweight customized tabbar view. 4 | 5 | [![License](https://img.shields.io/badge/License-MIT-lightgrey.svg)](https://github.com/hemangshah/HHTabBarView/blob/master/LICENSE) 6 | [![Platform](https://img.shields.io/badge/Platforms-iOS-red.svg)](https://www.apple.com/in/ios/) 7 | [![Swift 4.x](https://img.shields.io/badge/Swift-4.x-blue.svg)](https://swift.org/) 8 | [![MadeWithLove](https://img.shields.io/badge/Made%20with%20%E2%9D%A4-India-green.svg)](https://madewithlove.org.in/) 9 | [![Awesome-Swift](https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg)](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 |
Only IconIcon (top) with title (bottom)Only Title
Icon (left) with title (right)Icon (right) with title (left)Icon (bottom) with title (top)
HHTabBarView top positionHHTabBarView top position (iPhoneX)
Usage
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 | 6 | 7 | 10 | 11 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /logo/logotype-a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hemangshah/HHTabBarView/3dc02898857d4d6bba99bd3b368ff7f664968d36/logo/logotype-a.png -------------------------------------------------------------------------------- /logo/logotype-a.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 11 | 12 | 19 | 20 | 21 | 27 | 33 | 38 | 45 | 52 | 61 | 68 | 73 | 78 | 81 | 84 | 92 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /logo/logotype-b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hemangshah/HHTabBarView/3dc02898857d4d6bba99bd3b368ff7f664968d36/logo/logotype-b.png -------------------------------------------------------------------------------- /logo/logotype-b.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 11 | 12 | 20 | 21 | 22 | 28 | 34 | 39 | 46 | 53 | 62 | 69 | 74 | 79 | 82 | 86 | 95 | 104 | 105 | 106 | 107 | --------------------------------------------------------------------------------