├── Screenshots
├── Card.png
├── Light.png
├── Special.png
└── SemiCard.png
├── LightCardTabBar
├── Resources
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ ├── AccentColor.colorset
│ │ │ └── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── Info.plist
│ └── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
├── ViewController.swift
├── Controllers
│ ├── CardTabBarController.swift
│ ├── LightTabBarController.swift
│ ├── SemiCardTabBarController.swift
│ ├── SpecialTabBarController.swift
│ └── TabBarController.swift
├── Tab Bar
│ ├── BaseCardTabBar.swift
│ ├── SemiCardTabBar.swift
│ ├── CardTabBar.swift
│ ├── LightTabBar.swift
│ └── SpecialCardTabBar.swift
├── AppDelegate.swift
└── Extensions
│ └── UIView+Additions.swift
├── LightCardTabBar.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── xcuserdata
│ └── hussc.xcuserdatad
│ │ └── xcschemes
│ │ └── xcschememanagement.plist
└── project.pbxproj
├── LightCardTabBarTests
├── Info.plist
└── LightCardTabBarTests.swift
├── LightCardTabBarUITests
├── Info.plist
└── LightCardTabBarUITests.swift
└── README.md
/Screenshots/Card.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hussc/lightCardTabBar/HEAD/Screenshots/Card.png
--------------------------------------------------------------------------------
/Screenshots/Light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hussc/lightCardTabBar/HEAD/Screenshots/Light.png
--------------------------------------------------------------------------------
/Screenshots/Special.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hussc/lightCardTabBar/HEAD/Screenshots/Special.png
--------------------------------------------------------------------------------
/Screenshots/SemiCard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hussc/lightCardTabBar/HEAD/Screenshots/SemiCard.png
--------------------------------------------------------------------------------
/LightCardTabBar/Resources/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/LightCardTabBar.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/LightCardTabBar/Resources/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/LightCardTabBar/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // LightCardTabBar
4 | //
5 | // Created by Hussein AlRyalat on 05/06/2021.
6 | //
7 |
8 | import UIKit
9 |
10 | class ViewController: UIViewController {
11 |
12 | }
13 |
14 |
--------------------------------------------------------------------------------
/LightCardTabBar.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/LightCardTabBar/Controllers/CardTabBarController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CardTabBarController.swift
3 | // LightCardTabBar
4 | //
5 | // Created by Hussein AlRyalat on 05/06/2021.
6 | //
7 |
8 | import UIKit
9 |
10 | class CardTabBarController: TabBarController {
11 |
12 | override func makeTabBar() -> BaseCardTabBar {
13 | CardTabBar()
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/LightCardTabBar/Controllers/LightTabBarController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LightTabBarController.swift
3 | // LightCardTabBar
4 | //
5 | // Created by Hussein AlRyalat on 05/06/2021.
6 | //
7 |
8 | import UIKit
9 |
10 | class LightTabBarController: TabBarController {
11 |
12 | override func makeTabBar() -> BaseCardTabBar {
13 | LightTabBar()
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/LightCardTabBar/Controllers/SemiCardTabBarController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SemiCardTabBarController.swift
3 | // LightCardTabBar
4 | //
5 | // Created by Hussein AlRyalat on 05/06/2021.
6 | //
7 |
8 | import UIKit
9 |
10 | class SemiCardTabBarController: TabBarController {
11 |
12 | override func makeTabBar() -> BaseCardTabBar {
13 | SemiCardTabBar()
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/LightCardTabBar/Controllers/SpecialTabBarController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SpecialTabBarController.swift
3 | // LightCardTabBar
4 | //
5 | // Created by Hussein AlRyalat on 05/06/2021.
6 | //
7 |
8 | import UIKit
9 |
10 | class SpecialTabBarController: TabBarController {
11 |
12 |
13 | override func makeTabBar() -> BaseCardTabBar {
14 | SpecialCardTabBar()
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/LightCardTabBar.xcodeproj/xcuserdata/hussc.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | LightCardTabBar.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/LightCardTabBar/Tab Bar/BaseCardTabBar.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BaseCardTabBar.swift
3 | // LightCardTabBar
4 | //
5 | // Created by Hussein AlRyalat on 05/06/2021.
6 | //
7 |
8 | import UIKit
9 |
10 | protocol CardTabBarDelegate: AnyObject {
11 | func cardTabBar(_ sender: BaseCardTabBar, didSelectItemAt index: Int)
12 |
13 | func didUpdateHeight()
14 | }
15 |
16 | class BaseCardTabBar: UIView {
17 |
18 | var preferredTabBarHeight: CGFloat {
19 | 70
20 | }
21 |
22 | var preferredBottomBackground: UIColor {
23 | .clear
24 | }
25 |
26 | weak var delegate: CardTabBarDelegate?
27 |
28 | func select(at index: Int, animated: Bool, notifyDelegate: Bool) {
29 |
30 | }
31 |
32 | func set(items: [UITabBarItem]) {
33 |
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/LightCardTabBarTests/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 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/LightCardTabBarUITests/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 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/LightCardTabBarTests/LightCardTabBarTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LightCardTabBarTests.swift
3 | // LightCardTabBarTests
4 | //
5 | // Created by Hussein AlRyalat on 05/06/2021.
6 | //
7 |
8 | import XCTest
9 | @testable import LightCardTabBar
10 |
11 | class LightCardTabBarTests: XCTestCase {
12 |
13 | override func setUpWithError() throws {
14 | // Put setup code here. This method is called before the invocation of each test method in the class.
15 | }
16 |
17 | override func tearDownWithError() throws {
18 | // Put teardown code here. This method is called after the invocation of each test method in the class.
19 | }
20 |
21 | func testExample() throws {
22 | // This is an example of a functional test case.
23 | // Use XCTAssert and related functions to verify your tests produce the correct results.
24 | }
25 |
26 | func testPerformanceExample() throws {
27 | // This is an example of a performance test case.
28 | self.measure {
29 | // Put the code you want to measure the time of here.
30 | }
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/LightCardTabBarUITests/LightCardTabBarUITests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LightCardTabBarUITests.swift
3 | // LightCardTabBarUITests
4 | //
5 | // Created by Hussein AlRyalat on 05/06/2021.
6 | //
7 |
8 | import XCTest
9 |
10 | class LightCardTabBarUITests: XCTestCase {
11 |
12 | override func setUpWithError() throws {
13 | // Put setup code here. This method is called before the invocation of each test method in the class.
14 |
15 | // In UI tests it is usually best to stop immediately when a failure occurs.
16 | continueAfterFailure = false
17 |
18 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
19 | }
20 |
21 | override func tearDownWithError() throws {
22 | // Put teardown code here. This method is called after the invocation of each test method in the class.
23 | }
24 |
25 | func testExample() throws {
26 | // UI tests must launch the application that they test.
27 | let app = XCUIApplication()
28 | app.launch()
29 |
30 | // Use recording to get started writing UI tests.
31 | // Use XCTAssert and related functions to verify your tests produce the correct results.
32 | }
33 |
34 | func testLaunchPerformance() throws {
35 | if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) {
36 | // This measures how long it takes to launch your application.
37 | measure(metrics: [XCTApplicationLaunchMetric()]) {
38 | XCUIApplication().launch()
39 | }
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/LightCardTabBar/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // LightCardTabBar
4 | //
5 | // Created by Hussein AlRyalat on 05/06/2021.
6 | //
7 |
8 | import UIKit
9 |
10 | @main
11 | class AppDelegate: UIResponder, UIApplicationDelegate {
12 |
13 | var window: UIWindow?
14 |
15 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
16 | // Override point for customization after application launch.
17 | // setupStyleSwizzling()
18 | return true
19 | }
20 |
21 |
22 | // func setupStyleSwizzling(){
23 | // let originalMethod = class_getInstanceMethod(UIView.self, #selector(UIView.didMoveToSuperview))
24 | // let swizzledMethod = class_getInstanceMethod(UIView.self, #selector(UIView.swizzledDidMoveToSuperview))
25 | // method_exchangeImplementations(originalMethod!, swizzledMethod!)
26 | // }
27 |
28 | }
29 |
30 |
31 |
32 | //extension UIView {
33 | // @objc func swizzledDidMoveToSuperview(){
34 | // self.updateStyle()
35 | // }
36 | //}
37 | //
38 | ///**
39 | // A Stylable represents any entity whishes to update it's attributes based on given style
40 | // */
41 | //@objc
42 | //protocol Styleable: NSObjectProtocol {
43 | //
44 | // @objc func updateStyle()
45 | //}
46 | //
47 | //extension UIView: Styleable {
48 | //
49 | // func updateStyle() {
50 | //
51 | // }
52 | //}
53 | //
54 | //extension Styleable where Self: UIView {
55 | // func tellChildrenUpdateStyle(){
56 | // self.subviews.forEach {
57 | // $0.updateStyle()
58 | // $0.tellChildrenUpdateStyle()
59 | // }
60 | // }
61 | //}
62 |
--------------------------------------------------------------------------------
/LightCardTabBar/Resources/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 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSupportsIndirectInputEvents
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 | UIInterfaceOrientationLandscapeLeft
37 | UIInterfaceOrientationLandscapeRight
38 |
39 | UISupportedInterfaceOrientations~ipad
40 |
41 | UIInterfaceOrientationPortrait
42 | UIInterfaceOrientationPortraitUpsideDown
43 | UIInterfaceOrientationLandscapeLeft
44 | UIInterfaceOrientationLandscapeRight
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/LightCardTabBar/Resources/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 |
--------------------------------------------------------------------------------
/LightCardTabBar/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # LightCardTabBar
2 |
3 | An expiremental project exploring different types of custom-tabbar styles, screenshots as below.
4 |
5 | ## Screenshots
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | ## Implementation
15 |
16 | The implementation relies on two main components:
17 | - TabBarController -> which hides the default tabbar and initializes the custom tabbar, and any nesscary components
18 | - BaseCardTabBar -> A base class for any client who wishes to implement custom tab bar, including any actions needed.
19 |
20 |
21 | ## Examples
22 |
23 | The Example Project includes **4 styles** of custom-tabbar, crafted and inspired by well made designs.
24 |
25 | Each type of tabbar has the two main components, it's own **tabbarcontroller** and **tabbar**, all have the same inteface to interact with.
26 |
27 |
28 | ## Your own tabbar!
29 |
30 | The Example project demonstrates different types of tabbar represents a wide range of applications you can use, I hope the examples provide a starting point if you want to implement your own.
31 |
32 | And as always, you can pull request a new style!
33 |
34 | ## License
35 |
36 | Copyright 2021 Hussein AlRyalat
37 |
38 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
39 |
40 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
41 |
42 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
43 |
--------------------------------------------------------------------------------
/LightCardTabBar/Controllers/TabBarController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TabBarController.swift
3 | // tweetly
4 | //
5 | // Created by Hussein Work on 28/11/2020.
6 | //
7 |
8 | import UIKit
9 |
10 | class TabBarController: UITabBarController {
11 |
12 | var tabBarHeight: CGFloat {
13 | customTabBar.preferredTabBarHeight
14 | }
15 |
16 | lazy var customTabBar: BaseCardTabBar = makeTabBar()
17 | lazy var anotherSmallView = UIView()
18 |
19 |
20 | fileprivate var anotherSmallViewBottomConstraint: NSLayoutConstraint?
21 | fileprivate var tabBarHeightConstraint: NSLayoutConstraint?
22 |
23 | override var selectedIndex: Int {
24 | didSet {
25 | customTabBar.select(at: selectedIndex, animated: false, notifyDelegate: false)
26 | }
27 | }
28 |
29 | override var selectedViewController: UIViewController? {
30 | didSet {
31 | customTabBar.select(at: selectedIndex, animated: false, notifyDelegate: false)
32 | }
33 | }
34 |
35 | override func viewDidLoad() {
36 | super.viewDidLoad()
37 |
38 | self.tabBar.isHidden = true
39 |
40 | setupTabBar()
41 | updateTabBarHeightIfNeeded()
42 | }
43 |
44 | override func viewWillAppear(_ animated: Bool) {
45 | super.viewWillAppear(animated)
46 |
47 | customTabBar.set(items: tabBar.items ?? [])
48 | customTabBar.select(at: selectedIndex, animated: false, notifyDelegate: true)
49 | }
50 |
51 |
52 | fileprivate func setupTabBar(){
53 | self.additionalSafeAreaInsets = UIEdgeInsets(top: 0, left: 0, bottom: tabBarHeight, right: 0)
54 |
55 | customTabBar.delegate = self
56 | customTabBar.translatesAutoresizingMaskIntoConstraints = false
57 | self.view.addSubview(customTabBar)
58 |
59 |
60 | anotherSmallView.backgroundColor = customTabBar.preferredBottomBackground
61 | anotherSmallView.translatesAutoresizingMaskIntoConstraints = false
62 | self.view.addSubview(anotherSmallView)
63 |
64 | anotherSmallView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
65 | anotherSmallView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
66 | anotherSmallView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
67 |
68 | customTabBar.bottomAnchor.constraint(equalTo: anotherSmallView.topAnchor).isActive = true
69 | customTabBar.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
70 | customTabBar.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
71 |
72 | self.view.bringSubviewToFront(customTabBar)
73 | self.view.bringSubviewToFront(anotherSmallView)
74 | }
75 |
76 | fileprivate func updateTabBarHeightIfNeeded(){
77 | self.additionalSafeAreaInsets = UIEdgeInsets(top: 0, left: 0, bottom: tabBarHeight, right: 0)
78 |
79 |
80 | tabBarHeightConstraint = customTabBar.heightAnchor.constraint(equalToConstant: tabBarHeight)
81 | tabBarHeightConstraint?.isActive = true
82 |
83 | anotherSmallViewBottomConstraint = anotherSmallView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: tabBarHeight)
84 |
85 |
86 | anotherSmallViewBottomConstraint?.priority = .defaultHigh
87 | anotherSmallViewBottomConstraint?.isActive = true
88 | }
89 |
90 | func setTabBarHidden(_ isHidden: Bool, animated: Bool){
91 | let block = {
92 | self.customTabBar.alpha = isHidden ? 0 : 1
93 | self.additionalSafeAreaInsets = UIEdgeInsets(top: 0, left: 0, bottom: isHidden ? 0 : self.tabBarHeight, right: 0)
94 | }
95 |
96 | if animated {
97 | UIView.animate(withDuration: 0.3, delay: 0, options: .curveEaseIn, animations: block, completion: nil)
98 | } else {
99 | block()
100 | }
101 | }
102 |
103 |
104 | func makeTabBar() -> BaseCardTabBar {
105 | SpecialCardTabBar()
106 | }
107 | }
108 |
109 | extension TabBarController: CardTabBarDelegate {
110 | func cardTabBar(_ sender: BaseCardTabBar, didSelectItemAt index: Int) {
111 | self.selectedIndex = index
112 | }
113 |
114 | func didUpdateHeight() {
115 | self.updateTabBarHeightIfNeeded()
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/LightCardTabBar/Extensions/UIView+Additions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIStackView+Additions.swift
3 | // talabyeh
4 | //
5 | // Created by Hussein Work on 11/11/20.
6 | // Copyright © 2020 Dominate. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension CGPoint {
12 | func distance(to point: CGPoint) -> CGFloat {
13 | return hypot(self.x - point.x, self.y - point.y)
14 | }
15 | }
16 |
17 |
18 | @resultBuilder public struct SubviewsBuilder {
19 | public static func buildBlock(_ content: UIView...) -> [UIView] {
20 | return content
21 | }
22 | }
23 |
24 | /**
25 | Creating a chainable stackview to make life easiere
26 | */
27 |
28 | extension UIStackView {
29 | @discardableResult
30 | func alignment(_ alignment: Alignment) -> UIStackView {
31 | self.alignment = alignment
32 | return self
33 | }
34 |
35 | @discardableResult
36 | func distribution(_ distribution: Distribution) -> UIStackView {
37 | self.distribution = distribution
38 | return self
39 | }
40 |
41 | @discardableResult
42 | func spacing(_ spacing: CGFloat) -> UIStackView {
43 | self.spacing = spacing
44 | return self
45 | }
46 |
47 | @discardableResult
48 | func axis(_ axis: NSLayoutConstraint.Axis) -> UIStackView {
49 | self.axis = axis
50 | return self
51 | }
52 |
53 | @discardableResult
54 | func addingArrangedSubviews(_ arrangedSubviews: [UIView]) -> UIStackView {
55 | arrangedSubviews.forEach {
56 | self.addArrangedSubview($0)
57 | }
58 |
59 | return self
60 | }
61 |
62 | @discardableResult
63 | func preparedForAutolayout() -> UIStackView {
64 | translatesAutoresizingMaskIntoConstraints = false
65 | return self
66 | }
67 |
68 | @discardableResult
69 | func addingArrangedSubviews(@SubviewsBuilder content: () -> [UIView]) -> UIStackView {
70 | for sv in content() {
71 | addArrangedSubview(sv)
72 | sv.translatesAutoresizingMaskIntoConstraints = false
73 | }
74 | return self
75 | }
76 | }
77 |
78 | extension UIView {
79 | func subviewsPreparedAL(@SubviewsBuilder content: () -> [UIView]){
80 | for view in content() {
81 | addSubview(view)
82 | view.translatesAutoresizingMaskIntoConstraints = false
83 | }
84 | }
85 | }
86 |
87 | extension UIView {
88 | func pinToSafeArea(top: CGFloat? = 0, left: CGFloat? = 0, bottom: CGFloat? = 0, right: CGFloat? = 0){
89 | guard let superview = self.superview else { return }
90 |
91 | prepareForAutoLayout()
92 |
93 | var guide: UILayoutGuide
94 | if #available(iOS 11.0, *) {
95 | guide = superview.safeAreaLayoutGuide
96 | } else {
97 | guide = superview.layoutMarginsGuide
98 | }
99 |
100 | if let top = top {
101 | self.topAnchor.constraint(equalTo: guide.topAnchor, constant: top).isActive = true
102 | }
103 |
104 | if let bottom = bottom {
105 | self.bottomAnchor.constraint(equalTo: guide.bottomAnchor, constant: bottom).isActive = true
106 | }
107 |
108 | if let left = left {
109 | self.leadingAnchor.constraint(equalTo: guide.leadingAnchor, constant: left).isActive = true
110 | }
111 |
112 | if let right = right {
113 | self.trailingAnchor.constraint(equalTo: guide.trailingAnchor, constant: right).isActive = true
114 | }
115 | }
116 |
117 | func pinToSuperView(top: CGFloat? = 0, left: CGFloat? = 0, bottom: CGFloat? = 0, right: CGFloat? = 0){
118 | guard let superview = self.superview else { return }
119 |
120 | prepareForAutoLayout()
121 |
122 | if let top = top {
123 | self.topAnchor.constraint(equalTo: superview.topAnchor, constant: top).isActive = true
124 | }
125 |
126 | if let bottom = bottom {
127 | self.bottomAnchor.constraint(equalTo: superview.bottomAnchor, constant: bottom).isActive = true
128 | }
129 |
130 | if let left = left {
131 | self.leadingAnchor.constraint(equalTo: superview.leadingAnchor, constant: left).isActive = true
132 | }
133 |
134 | if let right = right {
135 | self.trailingAnchor.constraint(equalTo: superview.trailingAnchor, constant: right).isActive = true
136 | }
137 | }
138 |
139 | func centerInSuperView(){
140 | guard let superview = self.superview else { return }
141 |
142 | prepareForAutoLayout()
143 |
144 | self.centerXAnchor.constraint(equalTo: superview.centerXAnchor).isActive = true
145 | self.centerYAnchor.constraint(equalTo: superview.centerYAnchor).isActive = true
146 | }
147 |
148 | func constraint(width: CGFloat){
149 | prepareForAutoLayout()
150 | self.widthAnchor.constraint(equalToConstant: width).isActive = true
151 | }
152 |
153 | func constraint(height: CGFloat){
154 | prepareForAutoLayout()
155 | self.heightAnchor.constraint(equalToConstant: height).isActive = true
156 | }
157 |
158 | func makeWidthEqualHeight(){
159 | prepareForAutoLayout()
160 | self.widthAnchor.constraint(equalTo: self.heightAnchor).isActive = true
161 | }
162 |
163 | func prepareForAutoLayout(){
164 | translatesAutoresizingMaskIntoConstraints = false
165 | }
166 | }
167 |
168 |
--------------------------------------------------------------------------------
/LightCardTabBar/Tab Bar/SemiCardTabBar.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CardTabBar.swift
3 | // tweetly
4 | //
5 | // Created by Hussein AlRyalat on 13/05/2021.
6 | //
7 |
8 | import UIKit
9 |
10 |
11 | class SemiCardTabBar: BaseCardTabBar {
12 |
13 | struct TabBarItem: Equatable {
14 | var image: UIImage
15 | }
16 |
17 | override var preferredBottomBackground: UIColor {
18 | .white
19 | }
20 |
21 | private lazy var stackView: UIStackView = {
22 | let stackView = UIStackView(arrangedSubviews: [])
23 | stackView.translatesAutoresizingMaskIntoConstraints = false
24 | stackView.axis = .horizontal
25 | stackView.distribution = .fillEqually
26 | stackView.alignment = .center
27 |
28 | self.addSubview(stackView)
29 |
30 | stackView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
31 | stackView.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
32 | stackView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
33 | stackView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
34 |
35 |
36 | return stackView
37 | }()
38 |
39 | private(set) var items: [TabBarItem] = []
40 | fileprivate(set) var selectedIndex: Int = 0
41 |
42 | override init(frame: CGRect) {
43 | super.init(frame: frame)
44 | setup()
45 | }
46 |
47 | required init?(coder aDecoder: NSCoder) {
48 | super.init(coder: aDecoder)
49 | setup()
50 | }
51 |
52 | deinit {
53 | stackView.arrangedSubviews.forEach {
54 | if let button = $0 as? UIControl {
55 | button.removeTarget(self, action: #selector(buttonTapped(sender:)), for: .touchUpInside)
56 | }
57 | }
58 | }
59 |
60 | private func setup(){
61 |
62 | updateStyle()
63 | }
64 |
65 | func updateStyle() {
66 | self.backgroundColor = .white
67 | self.translatesAutoresizingMaskIntoConstraints = false
68 | self.layer.cornerRadius = 12
69 | self.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
70 | self.layer.shadowColor = UIColor.lightGray.cgColor
71 | self.layer.shadowOffset = CGSize(width: 0, height: -2)
72 | self.layer.shadowRadius = 4
73 | self.layer.shadowOpacity = 0.3
74 |
75 | let selected = self.selectedIndex
76 | self.select(at: selected, animated: false, notifyDelegate: false)
77 | }
78 |
79 | func add(item: TabBarItem){
80 | self.items.append(item)
81 | self.addButton(with: item.image)
82 | }
83 |
84 | func hide(at index: Int){
85 | guard stackView.arrangedSubviews.count > index, index >= 0 else {
86 | return
87 | }
88 |
89 | stackView.arrangedSubviews[index].isHidden = true
90 | }
91 |
92 | func unhide(at index: Int){
93 | guard stackView.arrangedSubviews.count > index, index >= 0 else {
94 | return
95 | }
96 |
97 | stackView.arrangedSubviews[index].isHidden = false
98 | }
99 |
100 | func remove(item: TabBarItem){
101 | if let index = self.items.firstIndex(of: item) {
102 | self.items.remove(at: index)
103 | let view = self.stackView.arrangedSubviews[index]
104 | self.stackView.removeArrangedSubview(view)
105 | }
106 | }
107 |
108 | private func addButton(with image: UIImage){
109 | let button = UIButton()
110 |
111 | button.translatesAutoresizingMaskIntoConstraints = false
112 | button.setImage(image, for: .normal)
113 | button.tintColor = tintColor
114 | button.tag = self.items.count
115 |
116 | button.addTarget(self, action: #selector(buttonTapped(sender:)), for: .touchUpInside)
117 | self.stackView.addArrangedSubview(button)
118 | }
119 |
120 | override func set(items: [UITabBarItem]) {
121 | items.compactMap { $0.image }.forEach {
122 | self.add(item: .init(image: $0))
123 | }
124 | }
125 |
126 | override func select(at index: Int, animated: Bool, notifyDelegate: Bool = true){
127 | selectedIndex = index
128 | for (bIndex, view) in stackView.arrangedSubviews.enumerated() {
129 | if let button = view as? UIButton {
130 | button.tintColor = bIndex == index ? .black : UIColor.black.withAlphaComponent(0.4)
131 | }
132 | }
133 |
134 | if notifyDelegate {
135 | self.delegate?.cardTabBar(self, didSelectItemAt: index)
136 | }
137 | }
138 |
139 | @objc func buttonTapped(sender: UIButton){
140 | if let index = stackView.arrangedSubviews.firstIndex(of: sender){
141 | select(at: index, animated: true)
142 | }
143 | }
144 |
145 | override func touchesEnded(_ touches: Set, with event: UIEvent?) {
146 | guard let position = touches.first?.location(in: self) else {
147 | super.touchesEnded(touches, with: event)
148 | return
149 | }
150 |
151 | let buttons = self.stackView.arrangedSubviews.compactMap { $0 as? UIButton }.filter { !$0.isHidden }
152 | let distances = buttons.map { $0.center.distance(to: position) }
153 |
154 | let buttonsDistances = zip(buttons, distances)
155 |
156 | if let closestButton = buttonsDistances.min(by: { $0.1 < $1.1 }) {
157 | buttonTapped(sender: closestButton.0)
158 | }
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/LightCardTabBar/Tab Bar/CardTabBar.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CardTabBar.swift
3 | // LightCardTabBar
4 | //
5 | // Created by Hussein AlRyalat on 05/06/2021.
6 | //
7 |
8 | import UIKit
9 |
10 | class CardTabBar: BaseCardTabBar {
11 |
12 | override var preferredTabBarHeight: CGFloat {
13 | 75
14 | }
15 |
16 | override var preferredBottomBackground: UIColor {
17 | .clear
18 | }
19 |
20 | lazy var containerView: UIView = UIView()
21 |
22 | lazy var stackView: UIStackView = {
23 | let stackView = UIStackView(arrangedSubviews: [])
24 | stackView.axis = .horizontal
25 | stackView.distribution = .fillEqually
26 | stackView.alignment = .center
27 |
28 | return stackView
29 | }()
30 |
31 |
32 | lazy var indicatorView: PTIndicatorView = {
33 | let view = PTIndicatorView()
34 | view.translatesAutoresizingMaskIntoConstraints = false
35 | view.constraint(width: 4)
36 | view.backgroundColor = .black
37 | view.makeWidthEqualHeight()
38 |
39 | return view
40 | }()
41 |
42 |
43 | private var indicatorViewXConstraint: NSLayoutConstraint!
44 |
45 | override init(frame: CGRect) {
46 | super.init(frame: frame)
47 | setup()
48 | }
49 |
50 | required public init?(coder aDecoder: NSCoder) {
51 | super.init(coder: aDecoder)
52 | setup()
53 | }
54 |
55 | deinit {
56 | stackView.arrangedSubviews.forEach {
57 | if let button = $0 as? UIControl {
58 | button.removeTarget(self, action: #selector(buttonTapped(sender:)), for: .touchUpInside)
59 | }
60 | }
61 | }
62 |
63 | private func setup(){
64 | translatesAutoresizingMaskIntoConstraints = false
65 |
66 | subviewsPreparedAL {
67 | containerView
68 | }
69 |
70 | containerView.subviewsPreparedAL {
71 | stackView
72 | indicatorView
73 | }
74 |
75 | containerView.pinToSuperView(top: 0, left: 20, bottom: -15, right: -20)
76 | stackView.pinToSuperView(top: 0, left: 20, bottom: nil, right: -20)
77 | stackView.centerInSuperView()
78 |
79 | indicatorView.topAnchor.constraint(equalTo: stackView.bottomAnchor, constant: -12).isActive = true
80 |
81 | updateStyle()
82 | }
83 |
84 |
85 | func updateStyle(){
86 | containerView.backgroundColor = .white
87 | containerView.layer.shadowColor = UIColor.black.cgColor
88 | containerView.layer.shadowOffset = CGSize(width: 3, height: 3)
89 | containerView.layer.shadowRadius = 6
90 | containerView.layer.shadowOpacity = 0.15
91 | }
92 |
93 |
94 | override func set(items: [UITabBarItem]) {
95 | for button in (stackView.arrangedSubviews.compactMap { $0 as? PTBarButton }) {
96 | stackView.removeArrangedSubview(button)
97 | button.removeFromSuperview()
98 | button.removeTarget(self, action: nil, for: .touchUpInside)
99 | }
100 |
101 | for item in items {
102 | if let image = item.image {
103 | addButton(with: image)
104 | } else {
105 | addButton(with: UIImage())
106 | }
107 | }
108 |
109 | layoutIfNeeded()
110 | }
111 |
112 | override func select(at index: Int, animated: Bool, notifyDelegate: Bool) {
113 | /* move the indicator view */
114 | if indicatorViewXConstraint != nil {
115 | indicatorViewXConstraint.isActive = false
116 | indicatorViewXConstraint = nil
117 | }
118 |
119 | for (bIndex, button) in buttons().enumerated() {
120 | button.selectedColor = .black
121 | button.isSelected = bIndex == index
122 |
123 | if bIndex == index {
124 | indicatorViewXConstraint = indicatorView.centerXAnchor.constraint(equalTo: button.centerXAnchor)
125 | indicatorViewXConstraint.isActive = true
126 | }
127 | }
128 |
129 | UIView.animate(withDuration: 0.25) {
130 | self.layoutIfNeeded()
131 | }
132 |
133 |
134 | if notifyDelegate {
135 | self.delegate?.cardTabBar(self, didSelectItemAt: index)
136 | }
137 | }
138 |
139 | private func addButton(with image: UIImage){
140 | let button = PTBarButton(image: image)
141 | button.translatesAutoresizingMaskIntoConstraints = false
142 | button.selectedColor = .black
143 |
144 | button.addTarget(self, action: #selector(buttonTapped(sender:)), for: .touchUpInside)
145 | self.stackView.addArrangedSubview(button)
146 | }
147 |
148 | private func buttons() -> [PTBarButton] {
149 | return stackView.arrangedSubviews.compactMap { $0 as? PTBarButton }
150 | }
151 |
152 |
153 | @objc func buttonTapped(sender: PTBarButton){
154 | if let index = stackView.arrangedSubviews.firstIndex(of: sender){
155 | select(at: index, animated: true, notifyDelegate: true)
156 | }
157 | }
158 |
159 | override open func touchesEnded(_ touches: Set, with event: UIEvent?) {
160 | guard let position = touches.first?.location(in: self) else {
161 | super.touchesEnded(touches, with: event)
162 | return
163 | }
164 |
165 | let buttons = self.stackView.arrangedSubviews.compactMap { $0 as? PTBarButton }.filter { !$0.isHidden }
166 | let distances = buttons.map { $0.center.distance(to: position) }
167 |
168 | let buttonsDistances = zip(buttons, distances)
169 |
170 | if let closestButton = buttonsDistances.min(by: { $0.1 < $1.1 }) {
171 | buttonTapped(sender: closestButton.0)
172 | }
173 | }
174 |
175 | override open func layoutSubviews() {
176 | super.layoutSubviews()
177 | containerView.layer.cornerRadius = containerView.bounds.height / 2
178 | }
179 | }
180 |
181 | extension CardTabBar {
182 | open class PTIndicatorView: UIView {
183 | override open func layoutSubviews() {
184 | super.layoutSubviews()
185 | self.backgroundColor = .black
186 | self.layer.cornerRadius = self.bounds.height / 2
187 | }
188 | }
189 |
190 |
191 | public class PTBarButton: UIButton {
192 |
193 | var selectedColor: UIColor = .black {
194 | didSet {
195 | reloadApperance()
196 | }
197 | }
198 |
199 | var unselectedColor: UIColor = .lightGray {
200 | didSet {
201 | reloadApperance()
202 | }
203 | }
204 |
205 | init(forItem item: UITabBarItem) {
206 | super.init(frame: .zero)
207 | setImage(item.image, for: .normal)
208 | }
209 |
210 | init(image: UIImage){
211 | super.init(frame: .zero)
212 | setImage(image, for: .normal)
213 | }
214 |
215 | required init?(coder aDecoder: NSCoder) {
216 | super.init(coder: aDecoder)
217 | }
218 |
219 |
220 | override public var isSelected: Bool {
221 | didSet {
222 | reloadApperance()
223 | }
224 | }
225 |
226 | func reloadApperance(){
227 | self.tintColor = isSelected ? selectedColor : unselectedColor
228 | }
229 | }
230 |
231 | }
232 |
--------------------------------------------------------------------------------
/LightCardTabBar/Tab Bar/LightTabBar.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LightTabBar.swift
3 | // LightCardTabBar
4 | //
5 | // Created by Hussein AlRyalat on 05/06/2021.
6 | //
7 |
8 | import UIKit
9 |
10 | class LightTabBar: BaseCardTabBar {
11 |
12 | override var preferredBottomBackground: UIColor {
13 | .clear
14 | }
15 |
16 | override var preferredTabBarHeight: CGFloat {
17 | 75
18 | }
19 |
20 | let containerView = UIView()
21 | let containerStackView = UIStackView()
22 | let indicatorView = IndicatorView()
23 |
24 | fileprivate var buttons: [BaseButton] = []
25 | var selectedIndex: Int = 0
26 |
27 | fileprivate var indicatorCenterX: NSLayoutConstraint!
28 | fileprivate var indicatorWidth: NSLayoutConstraint!
29 |
30 | override init(frame: CGRect) {
31 | super.init(frame: frame)
32 | setup()
33 | }
34 |
35 | required init?(coder: NSCoder) {
36 | super.init(coder: coder)
37 | setup()
38 | }
39 |
40 | func setup() {
41 | subviewsPreparedAL {
42 | containerView
43 | }
44 |
45 | containerView.subviewsPreparedAL {
46 | containerStackView
47 | indicatorView
48 | }
49 |
50 | containerStackView.distribution = .fillEqually
51 | containerStackView.spacing = 15
52 | containerStackView.axis = .horizontal
53 | containerStackView.alignment = .fill
54 |
55 | indicatorView.topAnchor.constraint(equalTo: containerView.topAnchor).isActive = true
56 | indicatorView.heightAnchor.constraint(equalTo: containerView.heightAnchor).isActive = true
57 |
58 | containerView.pinToSuperView(top: 7.5, left: 20, bottom: -7.5, right: -20)
59 | containerStackView.pinToSuperView(top: 10, left: 10, bottom: -10, right: -10)
60 |
61 | updateStyle()
62 | }
63 |
64 | func updateStyle() {
65 | backgroundColor = .clear
66 |
67 | containerView.backgroundColor = .black
68 |
69 | containerView.translatesAutoresizingMaskIntoConstraints = false
70 | containerView.layer.cornerRadius = 12
71 | containerView.layer.shadowColor = UIColor.lightGray.cgColor
72 | containerView.layer.shadowOffset = CGSize(width: 0, height: -2)
73 | containerView.layer.shadowRadius = 4
74 | containerView.layer.shadowOpacity = 0.3
75 | }
76 |
77 | override func select(at index: Int, animated: Bool, notifyDelegate: Bool) {
78 | guard !buttons.isEmpty else { return }
79 |
80 | self.selectedIndex = index
81 | let selectedButton = buttons[index]
82 |
83 |
84 | indicatorCenterX?.isActive = false
85 | indicatorWidth?.isActive = false
86 |
87 | indicatorCenterX = indicatorView.centerXAnchor.constraint(equalTo: selectedButton.centerXAnchor)
88 | indicatorCenterX.isActive = true
89 |
90 | indicatorWidth = indicatorView.widthAnchor.constraint(equalTo: selectedButton.widthAnchor)
91 | indicatorWidth.isActive = true
92 |
93 | let block = {
94 | self.buttons.forEach {
95 | $0._isSelected = false
96 | }
97 |
98 | selectedButton._isSelected = true
99 |
100 | self.containerView.layoutIfNeeded()
101 | }
102 |
103 | if animated {
104 | UIView.animate(withDuration: 0.3, animations: block)
105 | } else {
106 | block()
107 | }
108 |
109 | if notifyDelegate {
110 | self.delegate?.cardTabBar(self, didSelectItemAt: index)
111 | }
112 | }
113 |
114 | override func set(items: [UITabBarItem]) {
115 | self.buttons = []
116 | self.containerStackView.arrangedSubviews.forEach {
117 | self.containerStackView.removeArrangedSubview($0)
118 | $0.removeFromSuperview()
119 | }
120 |
121 | let buttons: [IconOnlyButton] = items.enumerated().map {
122 | let button = IconOnlyButton(image: $0.element.image, selectedImage: $0.element.selectedImage)
123 | button.tag = $0.offset
124 | return button
125 | }
126 |
127 |
128 | buttons.forEach {
129 | $0.addTarget(self, action: #selector(buttonTapped(sender:)), for: .touchUpInside)
130 | }
131 |
132 | self.buttons = buttons
133 | self.containerStackView.addingArrangedSubviews(buttons)
134 | }
135 |
136 | @objc func buttonTapped(sender: BaseButton){
137 | self.select(at: sender.tag, animated: true, notifyDelegate: true)
138 | }
139 | }
140 |
141 |
142 | extension LightTabBar {
143 | class IndicatorView: UIView {
144 |
145 | let topView = UIView()
146 | let gradientView = GradientView()
147 | let gradientMask = CAShapeLayer()
148 |
149 | let offset: CGFloat = 4
150 |
151 | override init(frame: CGRect) {
152 | super.init(frame: frame)
153 | setup()
154 | }
155 |
156 | required init?(coder: NSCoder) {
157 | super.init(coder: coder)
158 | setup()
159 | }
160 |
161 | func setup() {
162 |
163 | subviewsPreparedAL {
164 | gradientView
165 | topView
166 | }
167 |
168 | gradientView.pinToSuperView()
169 |
170 | topView.pinToSuperView(top: 0, left: offset, bottom: nil, right: -offset)
171 | topView.constraint(height: 3)
172 |
173 |
174 | updateStyle()
175 | }
176 |
177 | func updateStyle() {
178 | gradientView.colors = [.white.withAlphaComponent(0.2), .white.withAlphaComponent(0)]
179 | gradientView.locations = [0, 0.8]
180 | gradientView.isOpaque = false
181 |
182 | topView.backgroundColor = .white
183 | topView.layer.cornerRadius = 1
184 | }
185 |
186 | override func layoutSubviews() {
187 | super.layoutSubviews()
188 |
189 | self.gradientMask.path = pathForMask(in: bounds, offset: offset * 2).cgPath
190 | self.gradientView.layer.mask = gradientMask
191 | }
192 |
193 | func pathForMask(in rect: CGRect, offset: CGFloat) -> UIBezierPath {
194 | let path = UIBezierPath()
195 |
196 | path.move(to: CGPoint(x: offset, y: 0))
197 | path.addLine(to: CGPoint(x: rect.width - offset, y: 0))
198 | path.addLine(to: CGPoint(x: rect.width, y: rect.height))
199 | path.addLine(to: CGPoint(x: 0, y: rect.height))
200 | path.close()
201 |
202 | return path
203 | }
204 | }
205 |
206 | class BaseButton: UIButton {
207 | var _isSelected: Bool = false {
208 | didSet {
209 | updateStyle()
210 | }
211 | }
212 |
213 | func updateStyle() {
214 |
215 | }
216 | }
217 |
218 | class IconOnlyButton: BaseButton {
219 |
220 | let image: UIImage?
221 | let selectedImage: UIImage?
222 |
223 | init(image: UIImage?, selectedImage: UIImage?){
224 | self.image = image
225 | self.selectedImage = selectedImage
226 | super.init(frame: .zero)
227 |
228 |
229 | translatesAutoresizingMaskIntoConstraints = false
230 | }
231 |
232 | required init?(coder: NSCoder) {
233 | fatalError("init(coder:) has not been implemented")
234 | }
235 |
236 | override func updateStyle(){
237 | setImage(_isSelected ? selectedImage : image, for: .normal)
238 | tintColor = _isSelected ? .white : UIColor.white.withAlphaComponent(0.25)
239 | }
240 |
241 | override var intrinsicContentSize: CGSize {
242 | .init(width: 45, height: 45)
243 | }
244 | }
245 |
246 | }
247 |
248 | class GradientView: UIView {
249 |
250 | var colors: [UIColor]? {
251 | didSet {
252 | updateGradient()
253 | }
254 | }
255 |
256 | var locations: [CGFloat]? {
257 | didSet {
258 | updateGradient()
259 | }
260 | }
261 |
262 | override func draw(_ rect: CGRect) {
263 | let context = UIGraphicsGetCurrentContext()
264 | let size = bounds.size
265 |
266 | // Gradient
267 | if let gradient = gradient {
268 | let options: CGGradientDrawingOptions = [.drawsAfterEndLocation]
269 |
270 | let startPoint = CGPoint.zero
271 | let endPoint = CGPoint(x: 0, y: size.height)
272 | context?.drawLinearGradient(gradient, start: startPoint, end: endPoint, options: options)
273 | }
274 | }
275 |
276 |
277 | override func didMoveToWindow() {
278 | super.didMoveToWindow()
279 | contentMode = .redraw
280 | }
281 |
282 | // MARK: - Private
283 | private var gradient: CGGradient?
284 |
285 | private func updateGradient() {
286 | gradient = nil
287 | setNeedsDisplay()
288 |
289 | if let colors = self.colors {
290 | let colorSpace = CGColorSpaceCreateDeviceRGB()
291 | let colorSpaceModel = colorSpace.model
292 |
293 | let gradientColors = colors.map { (color: UIColor) -> AnyObject in
294 | let cgColor = color.cgColor
295 | let cgColorSpace = cgColor.colorSpace ?? colorSpace
296 |
297 | if cgColorSpace.model == colorSpaceModel {
298 | return cgColor as AnyObject
299 | }
300 |
301 | var red: CGFloat = 0
302 | var blue: CGFloat = 0
303 | var green: CGFloat = 0
304 | var alpha: CGFloat = 0
305 | color.getRed(&red, green: &green, blue: &blue, alpha: &alpha)
306 | return UIColor(red: red, green: green, blue: blue, alpha: alpha).cgColor as AnyObject
307 | } as NSArray
308 |
309 | gradient = CGGradient(colorsSpace: colorSpace, colors: gradientColors, locations: locations)
310 | }
311 | }
312 | }
313 |
--------------------------------------------------------------------------------
/LightCardTabBar/Resources/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 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
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 |
--------------------------------------------------------------------------------
/LightCardTabBar/Tab Bar/SpecialCardTabBar.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SpecialCardTabBar.swift
3 | // tweetly
4 | //
5 | // Created by Hussein AlRyalat on 20/05/2021.
6 | //
7 |
8 | import Foundation
9 | import UIKit
10 |
11 | class SpecialCardTabBar: BaseCardTabBar {
12 |
13 | override var preferredBottomBackground: UIColor {
14 | .white
15 | }
16 |
17 | let textCotainerStackView = UIStackView()
18 | let rightButtonsContainerStackView = UIStackView()
19 | let indicatorView = IndicatorView()
20 |
21 | fileprivate(set) var selectedIndex: Int = 0
22 |
23 | fileprivate var buttons: [BaseButton] = []
24 | fileprivate var firstTrigger: Bool = false
25 | fileprivate var indicatorCenterXConstraint: NSLayoutConstraint!
26 |
27 | override init(frame: CGRect) {
28 | super.init(frame: frame)
29 | setup()
30 | }
31 |
32 | required init?(coder: NSCoder) {
33 | super.init(coder: coder)
34 | setup()
35 | }
36 |
37 | func setup() {
38 | subviewsPreparedAL {
39 | textCotainerStackView
40 | rightButtonsContainerStackView
41 | indicatorView
42 | }
43 |
44 | textCotainerStackView.distribution = .fill
45 | textCotainerStackView.alignment = .center
46 | textCotainerStackView.axis = .horizontal
47 | textCotainerStackView.spacing = 15
48 |
49 | rightButtonsContainerStackView.distribution = .fill
50 | rightButtonsContainerStackView.alignment = .center
51 | rightButtonsContainerStackView.axis = .horizontal
52 | rightButtonsContainerStackView.spacing = 15
53 |
54 | textCotainerStackView.pinToSuperView(top: 0, left: 20, bottom: nil, right: nil)
55 | textCotainerStackView.bottomAnchor.constraint(equalTo: indicatorView.topAnchor, constant: 10).isActive = true
56 |
57 | rightButtonsContainerStackView.pinToSuperView(top: 8, left: nil, bottom: nil, right: -20)
58 | rightButtonsContainerStackView.centerYAnchor.constraint(equalTo: textCotainerStackView.centerYAnchor).isActive = true
59 | rightButtonsContainerStackView.leadingAnchor.constraint(greaterThanOrEqualTo: textCotainerStackView.trailingAnchor, constant: 15).isActive = true
60 |
61 |
62 | updateStyle()
63 | }
64 |
65 | func updateStyle() {
66 | self.backgroundColor = .white
67 | self.translatesAutoresizingMaskIntoConstraints = false
68 | self.layer.cornerRadius = 12
69 | self.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
70 | self.layer.shadowColor = UIColor.lightGray.cgColor
71 | self.layer.shadowOffset = CGSize(width: 0, height: -2)
72 | self.layer.shadowRadius = 4
73 | self.layer.shadowOpacity = 0.3
74 |
75 | let selected = self.selectedIndex
76 | self.select(at: selected, notifyDelegate: false)
77 | }
78 |
79 | func select(at index: Int, notifyDelegate: Bool){
80 | self.select(at: index, animated: false, notifyDelegate: notifyDelegate)
81 | }
82 |
83 | override func select(at index: Int, animated: Bool, notifyDelegate: Bool) {
84 | guard textCotainerStackView.arrangedSubviews.count > 0,
85 | rightButtonsContainerStackView.arrangedSubviews.count > 0 else {
86 | return
87 | }
88 |
89 | self.selectedIndex = index
90 |
91 | buttons.forEach {
92 | $0._isSelected = false
93 | }
94 |
95 | switch index {
96 | case 0:
97 | indicatorView.isHidden = false
98 | let button = textCotainerStackView.arrangedSubviews[0] as! BaseButton
99 |
100 | indicatorCenterXConstraint?.isActive = false
101 | indicatorCenterXConstraint = indicatorView.centerXAnchor.constraint(equalTo: button.centerXAnchor)
102 | indicatorCenterXConstraint.isActive = true
103 |
104 | button._isSelected = true
105 | case 1:
106 | let button = textCotainerStackView.arrangedSubviews[1] as! BaseButton
107 |
108 | indicatorView.isHidden = false
109 |
110 | indicatorCenterXConstraint?.isActive = false
111 | indicatorCenterXConstraint = indicatorView.centerXAnchor.constraint(equalTo: button.centerXAnchor)
112 | indicatorCenterXConstraint.isActive = true
113 |
114 | button._isSelected = true
115 | case 2:
116 | let button = rightButtonsContainerStackView.arrangedSubviews[0] as! BaseButton
117 | indicatorView.isHidden = false
118 |
119 | indicatorCenterXConstraint?.isActive = false
120 | indicatorCenterXConstraint = indicatorView.centerXAnchor.constraint(equalTo: button.centerXAnchor)
121 | indicatorCenterXConstraint.isActive = true
122 |
123 | button._isSelected = true
124 | case 3:
125 | let button = rightButtonsContainerStackView.arrangedSubviews[1] as! BaseButton
126 | indicatorView.isHidden = true
127 |
128 | indicatorCenterXConstraint?.isActive = false
129 | indicatorCenterXConstraint = indicatorView.centerXAnchor.constraint(equalTo: button.centerXAnchor)
130 | indicatorCenterXConstraint.isActive = true
131 |
132 | button._isSelected = true
133 | default:
134 | break
135 | }
136 |
137 | if animated {
138 | UIView.animate(withDuration: 0.3) {
139 | self.layoutIfNeeded()
140 | }
141 | }
142 |
143 |
144 | if notifyDelegate {
145 | delegate?.cardTabBar(self, didSelectItemAt: selectedIndex)
146 | }
147 | }
148 |
149 | override func set(items: [UITabBarItem]) {
150 | guard items.count > 4 else {
151 | fatalError("A Special CardTabBar can't be initialized with less than 4 items")
152 | }
153 |
154 | var mutableItems = items
155 |
156 | let firstItem = mutableItems.removeFirst()
157 | let firstTextButton = TextOnlyButton(title: firstItem.title)
158 | firstTextButton.tag = 0
159 |
160 | buttons.append(firstTextButton)
161 | self.textCotainerStackView.addingArrangedSubviews {
162 | firstTextButton
163 | }
164 |
165 | let anotherFirstItem = mutableItems.removeFirst()
166 | let secondTextButton = TextOnlyButton(title: anotherFirstItem.title)
167 | secondTextButton.tag = 1
168 |
169 | buttons.append(secondTextButton)
170 | self.textCotainerStackView.addingArrangedSubviews {
171 | secondTextButton
172 | }
173 |
174 | let anotherLastItem = mutableItems.remove(at: mutableItems.count - 2)
175 | let withImageButton = IconOnlyButton(image: anotherLastItem.image, selectedImage: anotherLastItem.selectedImage)
176 | withImageButton.tag = 2
177 |
178 |
179 | buttons.append(withImageButton)
180 | self.rightButtonsContainerStackView.addingArrangedSubviews {
181 | withImageButton
182 | }
183 |
184 | let lastItem = mutableItems.removeLast()
185 | let specialButton = SpecialButton(image: lastItem.image, selectedImage: lastItem.selectedImage)
186 | specialButton.tag = 3
187 |
188 |
189 | buttons.append(specialButton)
190 | self.rightButtonsContainerStackView.addingArrangedSubviews {
191 | specialButton
192 | }
193 |
194 |
195 | buttons.forEach {
196 | $0.addTarget(self, action: #selector(buttonTapped(sender:)), for: .touchUpInside)
197 | }
198 | }
199 |
200 | @objc func buttonTapped(sender: BaseButton){
201 | self.select(at: sender.tag, animated: true, notifyDelegate: true)
202 | }
203 | }
204 |
205 | extension SpecialCardTabBar {
206 |
207 | class IndicatorView: UIView {
208 |
209 | override func didMoveToSuperview() {
210 | super.didMoveToSuperview()
211 | updateStyle()
212 | }
213 |
214 | func updateStyle() {
215 | layer.cornerRadius = 2
216 | backgroundColor = .black
217 | }
218 |
219 | override var intrinsicContentSize: CGSize {
220 | .init(width: 4, height: 4)
221 | }
222 | }
223 |
224 | class BaseButton: UIButton {
225 | var _isSelected: Bool = false {
226 | didSet {
227 | updateStyle()
228 | }
229 | }
230 |
231 | override func didMoveToSuperview() {
232 | super.didMoveToSuperview()
233 | updateStyle()
234 | }
235 |
236 |
237 | func updateStyle(){
238 |
239 | }
240 | }
241 |
242 | class TextOnlyButton: BaseButton {
243 |
244 | let title: String?
245 |
246 | init(title: String?){
247 | self.title = title
248 | super.init(frame: .zero)
249 | }
250 |
251 | required init?(coder: NSCoder) {
252 | fatalError("init(coder:) has not been implemented")
253 | }
254 |
255 | override func updateStyle() {
256 | setTitle(title, for: .normal)
257 | setTitleColor(_isSelected ? .black : .lightGray, for: .normal)
258 | titleLabel?.font = .systemFont(ofSize: 14, weight: .bold)
259 | }
260 | }
261 |
262 | class IconOnlyButton: BaseButton {
263 |
264 | let image: UIImage?
265 | let selectedImage: UIImage?
266 |
267 | init(image: UIImage?, selectedImage: UIImage?){
268 | self.image = image
269 | self.selectedImage = selectedImage
270 | super.init(frame: .zero)
271 | }
272 |
273 | required init?(coder: NSCoder) {
274 | fatalError("init(coder:) has not been implemented")
275 | }
276 |
277 | override func updateStyle(){
278 | setImage(_isSelected ? selectedImage : image, for: .normal)
279 | tintColor = _isSelected ? .black : .lightGray
280 | }
281 | }
282 |
283 | class SpecialButton: BaseButton {
284 |
285 | let image: UIImage?
286 | let selectedImage: UIImage?
287 |
288 | init(image: UIImage?, selectedImage: UIImage?){
289 | self.image = image
290 | self.selectedImage = selectedImage
291 | super.init(frame: .zero)
292 | }
293 |
294 | required init?(coder: NSCoder) {
295 | fatalError("init(coder:) has not been implemented")
296 | }
297 |
298 | override func updateStyle(){
299 | layer.cornerRadius = 6
300 |
301 | setImage(_isSelected ? selectedImage : image, for: .normal)
302 | tintColor = _isSelected ? .white : .black
303 | backgroundColor = _isSelected ? .black : UIColor(white: 0.93, alpha: 1)
304 | }
305 |
306 | override var intrinsicContentSize: CGSize {
307 | .init(width: 50, height: 50)
308 | }
309 | }
310 | }
311 |
312 |
313 |
314 |
315 |
--------------------------------------------------------------------------------
/LightCardTabBar.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | E403A86F266B5BAA00EFFA93 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E403A86E266B5BAA00EFFA93 /* AppDelegate.swift */; };
11 | E403A873266B5BAA00EFFA93 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E403A872266B5BAA00EFFA93 /* ViewController.swift */; };
12 | E403A876266B5BAA00EFFA93 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E403A874266B5BAA00EFFA93 /* Main.storyboard */; };
13 | E403A878266B5BAB00EFFA93 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E403A877266B5BAB00EFFA93 /* Assets.xcassets */; };
14 | E403A87B266B5BAB00EFFA93 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E403A879266B5BAB00EFFA93 /* LaunchScreen.storyboard */; };
15 | E403A886266B5BAB00EFFA93 /* LightCardTabBarTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E403A885266B5BAB00EFFA93 /* LightCardTabBarTests.swift */; };
16 | E403A891266B5BAB00EFFA93 /* LightCardTabBarUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E403A890266B5BAB00EFFA93 /* LightCardTabBarUITests.swift */; };
17 | E403A8A2266B5BC400EFFA93 /* SemiCardTabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = E403A89F266B5BC400EFFA93 /* SemiCardTabBar.swift */; };
18 | E403A8A3266B5BC400EFFA93 /* TabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E403A8A0266B5BC400EFFA93 /* TabBarController.swift */; };
19 | E403A8A4266B5BC400EFFA93 /* SpecialCardTabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = E403A8A1266B5BC400EFFA93 /* SpecialCardTabBar.swift */; };
20 | E4449646266B5CB600372DAF /* UIView+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4449644266B5CB600372DAF /* UIView+Additions.swift */; };
21 | E444964A266B5E7F00372DAF /* LightTabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4449649266B5E7F00372DAF /* LightTabBar.swift */; };
22 | E444964C266BA51D00372DAF /* BaseCardTabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = E444964B266BA51D00372DAF /* BaseCardTabBar.swift */; };
23 | E4449650266BADBD00372DAF /* CardTabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = E444964F266BADBD00372DAF /* CardTabBar.swift */; };
24 | E4449653266BBE3000372DAF /* SpecialTabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4449652266BBE3000372DAF /* SpecialTabBarController.swift */; };
25 | E4449655266BBE3A00372DAF /* SemiCardTabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4449654266BBE3A00372DAF /* SemiCardTabBarController.swift */; };
26 | E4449657266BBE4200372DAF /* CardTabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4449656266BBE4200372DAF /* CardTabBarController.swift */; };
27 | E4449659266BBE4900372DAF /* LightTabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4449658266BBE4900372DAF /* LightTabBarController.swift */; };
28 | /* End PBXBuildFile section */
29 |
30 | /* Begin PBXContainerItemProxy section */
31 | E403A882266B5BAB00EFFA93 /* PBXContainerItemProxy */ = {
32 | isa = PBXContainerItemProxy;
33 | containerPortal = E403A863266B5BAA00EFFA93 /* Project object */;
34 | proxyType = 1;
35 | remoteGlobalIDString = E403A86A266B5BAA00EFFA93;
36 | remoteInfo = LightCardTabBar;
37 | };
38 | E403A88D266B5BAB00EFFA93 /* PBXContainerItemProxy */ = {
39 | isa = PBXContainerItemProxy;
40 | containerPortal = E403A863266B5BAA00EFFA93 /* Project object */;
41 | proxyType = 1;
42 | remoteGlobalIDString = E403A86A266B5BAA00EFFA93;
43 | remoteInfo = LightCardTabBar;
44 | };
45 | /* End PBXContainerItemProxy section */
46 |
47 | /* Begin PBXFileReference section */
48 | E403A86B266B5BAA00EFFA93 /* LightCardTabBar.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LightCardTabBar.app; sourceTree = BUILT_PRODUCTS_DIR; };
49 | E403A86E266B5BAA00EFFA93 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
50 | E403A872266B5BAA00EFFA93 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
51 | E403A875266B5BAA00EFFA93 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
52 | E403A877266B5BAB00EFFA93 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
53 | E403A87A266B5BAB00EFFA93 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
54 | E403A87C266B5BAB00EFFA93 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
55 | E403A881266B5BAB00EFFA93 /* LightCardTabBarTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LightCardTabBarTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
56 | E403A885266B5BAB00EFFA93 /* LightCardTabBarTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LightCardTabBarTests.swift; sourceTree = ""; };
57 | E403A887266B5BAB00EFFA93 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
58 | E403A88C266B5BAB00EFFA93 /* LightCardTabBarUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LightCardTabBarUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
59 | E403A890266B5BAB00EFFA93 /* LightCardTabBarUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LightCardTabBarUITests.swift; sourceTree = ""; };
60 | E403A892266B5BAB00EFFA93 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
61 | E403A89F266B5BC400EFFA93 /* SemiCardTabBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SemiCardTabBar.swift; sourceTree = ""; };
62 | E403A8A0266B5BC400EFFA93 /* TabBarController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabBarController.swift; sourceTree = ""; };
63 | E403A8A1266B5BC400EFFA93 /* SpecialCardTabBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpecialCardTabBar.swift; sourceTree = ""; };
64 | E4449644266B5CB600372DAF /* UIView+Additions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Additions.swift"; sourceTree = ""; };
65 | E4449649266B5E7F00372DAF /* LightTabBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LightTabBar.swift; sourceTree = ""; };
66 | E444964B266BA51D00372DAF /* BaseCardTabBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseCardTabBar.swift; sourceTree = ""; };
67 | E444964F266BADBD00372DAF /* CardTabBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardTabBar.swift; sourceTree = ""; };
68 | E4449652266BBE3000372DAF /* SpecialTabBarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpecialTabBarController.swift; sourceTree = ""; };
69 | E4449654266BBE3A00372DAF /* SemiCardTabBarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SemiCardTabBarController.swift; sourceTree = ""; };
70 | E4449656266BBE4200372DAF /* CardTabBarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardTabBarController.swift; sourceTree = ""; };
71 | E4449658266BBE4900372DAF /* LightTabBarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LightTabBarController.swift; sourceTree = ""; };
72 | E4A5BE0B2681B6F800865480 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; };
73 | /* End PBXFileReference section */
74 |
75 | /* Begin PBXFrameworksBuildPhase section */
76 | E403A868266B5BAA00EFFA93 /* Frameworks */ = {
77 | isa = PBXFrameworksBuildPhase;
78 | buildActionMask = 2147483647;
79 | files = (
80 | );
81 | runOnlyForDeploymentPostprocessing = 0;
82 | };
83 | E403A87E266B5BAB00EFFA93 /* Frameworks */ = {
84 | isa = PBXFrameworksBuildPhase;
85 | buildActionMask = 2147483647;
86 | files = (
87 | );
88 | runOnlyForDeploymentPostprocessing = 0;
89 | };
90 | E403A889266B5BAB00EFFA93 /* Frameworks */ = {
91 | isa = PBXFrameworksBuildPhase;
92 | buildActionMask = 2147483647;
93 | files = (
94 | );
95 | runOnlyForDeploymentPostprocessing = 0;
96 | };
97 | /* End PBXFrameworksBuildPhase section */
98 |
99 | /* Begin PBXGroup section */
100 | E403A862266B5BAA00EFFA93 = {
101 | isa = PBXGroup;
102 | children = (
103 | E4A5BE0B2681B6F800865480 /* README.md */,
104 | E403A86D266B5BAA00EFFA93 /* LightCardTabBar */,
105 | E403A884266B5BAB00EFFA93 /* LightCardTabBarTests */,
106 | E403A88F266B5BAB00EFFA93 /* LightCardTabBarUITests */,
107 | E403A86C266B5BAA00EFFA93 /* Products */,
108 | );
109 | sourceTree = "";
110 | };
111 | E403A86C266B5BAA00EFFA93 /* Products */ = {
112 | isa = PBXGroup;
113 | children = (
114 | E403A86B266B5BAA00EFFA93 /* LightCardTabBar.app */,
115 | E403A881266B5BAB00EFFA93 /* LightCardTabBarTests.xctest */,
116 | E403A88C266B5BAB00EFFA93 /* LightCardTabBarUITests.xctest */,
117 | );
118 | name = Products;
119 | sourceTree = "";
120 | };
121 | E403A86D266B5BAA00EFFA93 /* LightCardTabBar */ = {
122 | isa = PBXGroup;
123 | children = (
124 | E403A86E266B5BAA00EFFA93 /* AppDelegate.swift */,
125 | E403A872266B5BAA00EFFA93 /* ViewController.swift */,
126 | E444965A266BBE7C00372DAF /* Extensions */,
127 | E4449651266BBE2300372DAF /* Controllers */,
128 | E403A89E266B5BC400EFFA93 /* Tab Bar */,
129 | E444965B266BBF4700372DAF /* Resources */,
130 | );
131 | path = LightCardTabBar;
132 | sourceTree = "";
133 | };
134 | E403A884266B5BAB00EFFA93 /* LightCardTabBarTests */ = {
135 | isa = PBXGroup;
136 | children = (
137 | E403A885266B5BAB00EFFA93 /* LightCardTabBarTests.swift */,
138 | E403A887266B5BAB00EFFA93 /* Info.plist */,
139 | );
140 | path = LightCardTabBarTests;
141 | sourceTree = "";
142 | };
143 | E403A88F266B5BAB00EFFA93 /* LightCardTabBarUITests */ = {
144 | isa = PBXGroup;
145 | children = (
146 | E403A890266B5BAB00EFFA93 /* LightCardTabBarUITests.swift */,
147 | E403A892266B5BAB00EFFA93 /* Info.plist */,
148 | );
149 | path = LightCardTabBarUITests;
150 | sourceTree = "";
151 | };
152 | E403A89E266B5BC400EFFA93 /* Tab Bar */ = {
153 | isa = PBXGroup;
154 | children = (
155 | E444964B266BA51D00372DAF /* BaseCardTabBar.swift */,
156 | E403A8A1266B5BC400EFFA93 /* SpecialCardTabBar.swift */,
157 | E403A89F266B5BC400EFFA93 /* SemiCardTabBar.swift */,
158 | E444964F266BADBD00372DAF /* CardTabBar.swift */,
159 | E4449649266B5E7F00372DAF /* LightTabBar.swift */,
160 | );
161 | path = "Tab Bar";
162 | sourceTree = "";
163 | };
164 | E4449651266BBE2300372DAF /* Controllers */ = {
165 | isa = PBXGroup;
166 | children = (
167 | E403A8A0266B5BC400EFFA93 /* TabBarController.swift */,
168 | E4449652266BBE3000372DAF /* SpecialTabBarController.swift */,
169 | E4449654266BBE3A00372DAF /* SemiCardTabBarController.swift */,
170 | E4449656266BBE4200372DAF /* CardTabBarController.swift */,
171 | E4449658266BBE4900372DAF /* LightTabBarController.swift */,
172 | );
173 | path = Controllers;
174 | sourceTree = "";
175 | };
176 | E444965A266BBE7C00372DAF /* Extensions */ = {
177 | isa = PBXGroup;
178 | children = (
179 | E4449644266B5CB600372DAF /* UIView+Additions.swift */,
180 | );
181 | path = Extensions;
182 | sourceTree = "";
183 | };
184 | E444965B266BBF4700372DAF /* Resources */ = {
185 | isa = PBXGroup;
186 | children = (
187 | E403A874266B5BAA00EFFA93 /* Main.storyboard */,
188 | E403A877266B5BAB00EFFA93 /* Assets.xcassets */,
189 | E403A879266B5BAB00EFFA93 /* LaunchScreen.storyboard */,
190 | E403A87C266B5BAB00EFFA93 /* Info.plist */,
191 | );
192 | path = Resources;
193 | sourceTree = "";
194 | };
195 | /* End PBXGroup section */
196 |
197 | /* Begin PBXNativeTarget section */
198 | E403A86A266B5BAA00EFFA93 /* LightCardTabBar */ = {
199 | isa = PBXNativeTarget;
200 | buildConfigurationList = E403A895266B5BAB00EFFA93 /* Build configuration list for PBXNativeTarget "LightCardTabBar" */;
201 | buildPhases = (
202 | E403A867266B5BAA00EFFA93 /* Sources */,
203 | E403A868266B5BAA00EFFA93 /* Frameworks */,
204 | E403A869266B5BAA00EFFA93 /* Resources */,
205 | );
206 | buildRules = (
207 | );
208 | dependencies = (
209 | );
210 | name = LightCardTabBar;
211 | packageProductDependencies = (
212 | );
213 | productName = LightCardTabBar;
214 | productReference = E403A86B266B5BAA00EFFA93 /* LightCardTabBar.app */;
215 | productType = "com.apple.product-type.application";
216 | };
217 | E403A880266B5BAB00EFFA93 /* LightCardTabBarTests */ = {
218 | isa = PBXNativeTarget;
219 | buildConfigurationList = E403A898266B5BAB00EFFA93 /* Build configuration list for PBXNativeTarget "LightCardTabBarTests" */;
220 | buildPhases = (
221 | E403A87D266B5BAB00EFFA93 /* Sources */,
222 | E403A87E266B5BAB00EFFA93 /* Frameworks */,
223 | E403A87F266B5BAB00EFFA93 /* Resources */,
224 | );
225 | buildRules = (
226 | );
227 | dependencies = (
228 | E403A883266B5BAB00EFFA93 /* PBXTargetDependency */,
229 | );
230 | name = LightCardTabBarTests;
231 | productName = LightCardTabBarTests;
232 | productReference = E403A881266B5BAB00EFFA93 /* LightCardTabBarTests.xctest */;
233 | productType = "com.apple.product-type.bundle.unit-test";
234 | };
235 | E403A88B266B5BAB00EFFA93 /* LightCardTabBarUITests */ = {
236 | isa = PBXNativeTarget;
237 | buildConfigurationList = E403A89B266B5BAB00EFFA93 /* Build configuration list for PBXNativeTarget "LightCardTabBarUITests" */;
238 | buildPhases = (
239 | E403A888266B5BAB00EFFA93 /* Sources */,
240 | E403A889266B5BAB00EFFA93 /* Frameworks */,
241 | E403A88A266B5BAB00EFFA93 /* Resources */,
242 | );
243 | buildRules = (
244 | );
245 | dependencies = (
246 | E403A88E266B5BAB00EFFA93 /* PBXTargetDependency */,
247 | );
248 | name = LightCardTabBarUITests;
249 | productName = LightCardTabBarUITests;
250 | productReference = E403A88C266B5BAB00EFFA93 /* LightCardTabBarUITests.xctest */;
251 | productType = "com.apple.product-type.bundle.ui-testing";
252 | };
253 | /* End PBXNativeTarget section */
254 |
255 | /* Begin PBXProject section */
256 | E403A863266B5BAA00EFFA93 /* Project object */ = {
257 | isa = PBXProject;
258 | attributes = {
259 | LastSwiftUpdateCheck = 1250;
260 | LastUpgradeCheck = 1250;
261 | TargetAttributes = {
262 | E403A86A266B5BAA00EFFA93 = {
263 | CreatedOnToolsVersion = 12.5;
264 | };
265 | E403A880266B5BAB00EFFA93 = {
266 | CreatedOnToolsVersion = 12.5;
267 | TestTargetID = E403A86A266B5BAA00EFFA93;
268 | };
269 | E403A88B266B5BAB00EFFA93 = {
270 | CreatedOnToolsVersion = 12.5;
271 | TestTargetID = E403A86A266B5BAA00EFFA93;
272 | };
273 | };
274 | };
275 | buildConfigurationList = E403A866266B5BAA00EFFA93 /* Build configuration list for PBXProject "LightCardTabBar" */;
276 | compatibilityVersion = "Xcode 9.3";
277 | developmentRegion = en;
278 | hasScannedForEncodings = 0;
279 | knownRegions = (
280 | en,
281 | Base,
282 | );
283 | mainGroup = E403A862266B5BAA00EFFA93;
284 | packageReferences = (
285 | );
286 | productRefGroup = E403A86C266B5BAA00EFFA93 /* Products */;
287 | projectDirPath = "";
288 | projectRoot = "";
289 | targets = (
290 | E403A86A266B5BAA00EFFA93 /* LightCardTabBar */,
291 | E403A880266B5BAB00EFFA93 /* LightCardTabBarTests */,
292 | E403A88B266B5BAB00EFFA93 /* LightCardTabBarUITests */,
293 | );
294 | };
295 | /* End PBXProject section */
296 |
297 | /* Begin PBXResourcesBuildPhase section */
298 | E403A869266B5BAA00EFFA93 /* Resources */ = {
299 | isa = PBXResourcesBuildPhase;
300 | buildActionMask = 2147483647;
301 | files = (
302 | E403A87B266B5BAB00EFFA93 /* LaunchScreen.storyboard in Resources */,
303 | E403A878266B5BAB00EFFA93 /* Assets.xcassets in Resources */,
304 | E403A876266B5BAA00EFFA93 /* Main.storyboard in Resources */,
305 | );
306 | runOnlyForDeploymentPostprocessing = 0;
307 | };
308 | E403A87F266B5BAB00EFFA93 /* Resources */ = {
309 | isa = PBXResourcesBuildPhase;
310 | buildActionMask = 2147483647;
311 | files = (
312 | );
313 | runOnlyForDeploymentPostprocessing = 0;
314 | };
315 | E403A88A266B5BAB00EFFA93 /* Resources */ = {
316 | isa = PBXResourcesBuildPhase;
317 | buildActionMask = 2147483647;
318 | files = (
319 | );
320 | runOnlyForDeploymentPostprocessing = 0;
321 | };
322 | /* End PBXResourcesBuildPhase section */
323 |
324 | /* Begin PBXSourcesBuildPhase section */
325 | E403A867266B5BAA00EFFA93 /* Sources */ = {
326 | isa = PBXSourcesBuildPhase;
327 | buildActionMask = 2147483647;
328 | files = (
329 | E444964C266BA51D00372DAF /* BaseCardTabBar.swift in Sources */,
330 | E403A873266B5BAA00EFFA93 /* ViewController.swift in Sources */,
331 | E403A8A2266B5BC400EFFA93 /* SemiCardTabBar.swift in Sources */,
332 | E4449655266BBE3A00372DAF /* SemiCardTabBarController.swift in Sources */,
333 | E4449653266BBE3000372DAF /* SpecialTabBarController.swift in Sources */,
334 | E4449646266B5CB600372DAF /* UIView+Additions.swift in Sources */,
335 | E4449659266BBE4900372DAF /* LightTabBarController.swift in Sources */,
336 | E444964A266B5E7F00372DAF /* LightTabBar.swift in Sources */,
337 | E403A86F266B5BAA00EFFA93 /* AppDelegate.swift in Sources */,
338 | E403A8A3266B5BC400EFFA93 /* TabBarController.swift in Sources */,
339 | E403A8A4266B5BC400EFFA93 /* SpecialCardTabBar.swift in Sources */,
340 | E4449650266BADBD00372DAF /* CardTabBar.swift in Sources */,
341 | E4449657266BBE4200372DAF /* CardTabBarController.swift in Sources */,
342 | );
343 | runOnlyForDeploymentPostprocessing = 0;
344 | };
345 | E403A87D266B5BAB00EFFA93 /* Sources */ = {
346 | isa = PBXSourcesBuildPhase;
347 | buildActionMask = 2147483647;
348 | files = (
349 | E403A886266B5BAB00EFFA93 /* LightCardTabBarTests.swift in Sources */,
350 | );
351 | runOnlyForDeploymentPostprocessing = 0;
352 | };
353 | E403A888266B5BAB00EFFA93 /* Sources */ = {
354 | isa = PBXSourcesBuildPhase;
355 | buildActionMask = 2147483647;
356 | files = (
357 | E403A891266B5BAB00EFFA93 /* LightCardTabBarUITests.swift in Sources */,
358 | );
359 | runOnlyForDeploymentPostprocessing = 0;
360 | };
361 | /* End PBXSourcesBuildPhase section */
362 |
363 | /* Begin PBXTargetDependency section */
364 | E403A883266B5BAB00EFFA93 /* PBXTargetDependency */ = {
365 | isa = PBXTargetDependency;
366 | target = E403A86A266B5BAA00EFFA93 /* LightCardTabBar */;
367 | targetProxy = E403A882266B5BAB00EFFA93 /* PBXContainerItemProxy */;
368 | };
369 | E403A88E266B5BAB00EFFA93 /* PBXTargetDependency */ = {
370 | isa = PBXTargetDependency;
371 | target = E403A86A266B5BAA00EFFA93 /* LightCardTabBar */;
372 | targetProxy = E403A88D266B5BAB00EFFA93 /* PBXContainerItemProxy */;
373 | };
374 | /* End PBXTargetDependency section */
375 |
376 | /* Begin PBXVariantGroup section */
377 | E403A874266B5BAA00EFFA93 /* Main.storyboard */ = {
378 | isa = PBXVariantGroup;
379 | children = (
380 | E403A875266B5BAA00EFFA93 /* Base */,
381 | );
382 | name = Main.storyboard;
383 | sourceTree = "";
384 | };
385 | E403A879266B5BAB00EFFA93 /* LaunchScreen.storyboard */ = {
386 | isa = PBXVariantGroup;
387 | children = (
388 | E403A87A266B5BAB00EFFA93 /* Base */,
389 | );
390 | name = LaunchScreen.storyboard;
391 | sourceTree = "";
392 | };
393 | /* End PBXVariantGroup section */
394 |
395 | /* Begin XCBuildConfiguration section */
396 | E403A893266B5BAB00EFFA93 /* Debug */ = {
397 | isa = XCBuildConfiguration;
398 | buildSettings = {
399 | ALWAYS_SEARCH_USER_PATHS = NO;
400 | CLANG_ANALYZER_NONNULL = YES;
401 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
402 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
403 | CLANG_CXX_LIBRARY = "libc++";
404 | CLANG_ENABLE_MODULES = YES;
405 | CLANG_ENABLE_OBJC_ARC = YES;
406 | CLANG_ENABLE_OBJC_WEAK = YES;
407 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
408 | CLANG_WARN_BOOL_CONVERSION = YES;
409 | CLANG_WARN_COMMA = YES;
410 | CLANG_WARN_CONSTANT_CONVERSION = YES;
411 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
412 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
413 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
414 | CLANG_WARN_EMPTY_BODY = YES;
415 | CLANG_WARN_ENUM_CONVERSION = YES;
416 | CLANG_WARN_INFINITE_RECURSION = YES;
417 | CLANG_WARN_INT_CONVERSION = YES;
418 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
419 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
420 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
421 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
422 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
423 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
424 | CLANG_WARN_STRICT_PROTOTYPES = YES;
425 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
426 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
427 | CLANG_WARN_UNREACHABLE_CODE = YES;
428 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
429 | COPY_PHASE_STRIP = NO;
430 | DEBUG_INFORMATION_FORMAT = dwarf;
431 | ENABLE_STRICT_OBJC_MSGSEND = YES;
432 | ENABLE_TESTABILITY = YES;
433 | GCC_C_LANGUAGE_STANDARD = gnu11;
434 | GCC_DYNAMIC_NO_PIC = NO;
435 | GCC_NO_COMMON_BLOCKS = YES;
436 | GCC_OPTIMIZATION_LEVEL = 0;
437 | GCC_PREPROCESSOR_DEFINITIONS = (
438 | "DEBUG=1",
439 | "$(inherited)",
440 | );
441 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
442 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
443 | GCC_WARN_UNDECLARED_SELECTOR = YES;
444 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
445 | GCC_WARN_UNUSED_FUNCTION = YES;
446 | GCC_WARN_UNUSED_VARIABLE = YES;
447 | IPHONEOS_DEPLOYMENT_TARGET = 14.5;
448 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
449 | MTL_FAST_MATH = YES;
450 | ONLY_ACTIVE_ARCH = YES;
451 | SDKROOT = iphoneos;
452 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
453 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
454 | };
455 | name = Debug;
456 | };
457 | E403A894266B5BAB00EFFA93 /* Release */ = {
458 | isa = XCBuildConfiguration;
459 | buildSettings = {
460 | ALWAYS_SEARCH_USER_PATHS = NO;
461 | CLANG_ANALYZER_NONNULL = YES;
462 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
463 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
464 | CLANG_CXX_LIBRARY = "libc++";
465 | CLANG_ENABLE_MODULES = YES;
466 | CLANG_ENABLE_OBJC_ARC = YES;
467 | CLANG_ENABLE_OBJC_WEAK = YES;
468 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
469 | CLANG_WARN_BOOL_CONVERSION = YES;
470 | CLANG_WARN_COMMA = YES;
471 | CLANG_WARN_CONSTANT_CONVERSION = YES;
472 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
473 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
474 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
475 | CLANG_WARN_EMPTY_BODY = YES;
476 | CLANG_WARN_ENUM_CONVERSION = YES;
477 | CLANG_WARN_INFINITE_RECURSION = YES;
478 | CLANG_WARN_INT_CONVERSION = YES;
479 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
480 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
481 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
482 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
483 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
484 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
485 | CLANG_WARN_STRICT_PROTOTYPES = YES;
486 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
487 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
488 | CLANG_WARN_UNREACHABLE_CODE = YES;
489 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
490 | COPY_PHASE_STRIP = NO;
491 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
492 | ENABLE_NS_ASSERTIONS = NO;
493 | ENABLE_STRICT_OBJC_MSGSEND = YES;
494 | GCC_C_LANGUAGE_STANDARD = gnu11;
495 | GCC_NO_COMMON_BLOCKS = YES;
496 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
497 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
498 | GCC_WARN_UNDECLARED_SELECTOR = YES;
499 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
500 | GCC_WARN_UNUSED_FUNCTION = YES;
501 | GCC_WARN_UNUSED_VARIABLE = YES;
502 | IPHONEOS_DEPLOYMENT_TARGET = 14.5;
503 | MTL_ENABLE_DEBUG_INFO = NO;
504 | MTL_FAST_MATH = YES;
505 | SDKROOT = iphoneos;
506 | SWIFT_COMPILATION_MODE = wholemodule;
507 | SWIFT_OPTIMIZATION_LEVEL = "-O";
508 | VALIDATE_PRODUCT = YES;
509 | };
510 | name = Release;
511 | };
512 | E403A896266B5BAB00EFFA93 /* Debug */ = {
513 | isa = XCBuildConfiguration;
514 | buildSettings = {
515 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
516 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
517 | CODE_SIGN_STYLE = Automatic;
518 | DEVELOPMENT_TEAM = 6VU6999229;
519 | INFOPLIST_FILE = LightCardTabBar/Resources/Info.plist;
520 | LD_RUNPATH_SEARCH_PATHS = (
521 | "$(inherited)",
522 | "@executable_path/Frameworks",
523 | );
524 | PRODUCT_BUNDLE_IDENTIFIER = me.sketch.LightCardTabBar;
525 | PRODUCT_NAME = "$(TARGET_NAME)";
526 | SWIFT_VERSION = 5.0;
527 | TARGETED_DEVICE_FAMILY = "1,2";
528 | };
529 | name = Debug;
530 | };
531 | E403A897266B5BAB00EFFA93 /* Release */ = {
532 | isa = XCBuildConfiguration;
533 | buildSettings = {
534 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
535 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
536 | CODE_SIGN_STYLE = Automatic;
537 | DEVELOPMENT_TEAM = 6VU6999229;
538 | INFOPLIST_FILE = LightCardTabBar/Resources/Info.plist;
539 | LD_RUNPATH_SEARCH_PATHS = (
540 | "$(inherited)",
541 | "@executable_path/Frameworks",
542 | );
543 | PRODUCT_BUNDLE_IDENTIFIER = me.sketch.LightCardTabBar;
544 | PRODUCT_NAME = "$(TARGET_NAME)";
545 | SWIFT_VERSION = 5.0;
546 | TARGETED_DEVICE_FAMILY = "1,2";
547 | };
548 | name = Release;
549 | };
550 | E403A899266B5BAB00EFFA93 /* Debug */ = {
551 | isa = XCBuildConfiguration;
552 | buildSettings = {
553 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
554 | BUNDLE_LOADER = "$(TEST_HOST)";
555 | CODE_SIGN_STYLE = Automatic;
556 | DEVELOPMENT_TEAM = 6VU6999229;
557 | INFOPLIST_FILE = LightCardTabBarTests/Info.plist;
558 | IPHONEOS_DEPLOYMENT_TARGET = 14.5;
559 | LD_RUNPATH_SEARCH_PATHS = (
560 | "$(inherited)",
561 | "@executable_path/Frameworks",
562 | "@loader_path/Frameworks",
563 | );
564 | PRODUCT_BUNDLE_IDENTIFIER = me.sketch.LightCardTabBarTests;
565 | PRODUCT_NAME = "$(TARGET_NAME)";
566 | SWIFT_VERSION = 5.0;
567 | TARGETED_DEVICE_FAMILY = "1,2";
568 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/LightCardTabBar.app/LightCardTabBar";
569 | };
570 | name = Debug;
571 | };
572 | E403A89A266B5BAB00EFFA93 /* Release */ = {
573 | isa = XCBuildConfiguration;
574 | buildSettings = {
575 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
576 | BUNDLE_LOADER = "$(TEST_HOST)";
577 | CODE_SIGN_STYLE = Automatic;
578 | DEVELOPMENT_TEAM = 6VU6999229;
579 | INFOPLIST_FILE = LightCardTabBarTests/Info.plist;
580 | IPHONEOS_DEPLOYMENT_TARGET = 14.5;
581 | LD_RUNPATH_SEARCH_PATHS = (
582 | "$(inherited)",
583 | "@executable_path/Frameworks",
584 | "@loader_path/Frameworks",
585 | );
586 | PRODUCT_BUNDLE_IDENTIFIER = me.sketch.LightCardTabBarTests;
587 | PRODUCT_NAME = "$(TARGET_NAME)";
588 | SWIFT_VERSION = 5.0;
589 | TARGETED_DEVICE_FAMILY = "1,2";
590 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/LightCardTabBar.app/LightCardTabBar";
591 | };
592 | name = Release;
593 | };
594 | E403A89C266B5BAB00EFFA93 /* Debug */ = {
595 | isa = XCBuildConfiguration;
596 | buildSettings = {
597 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
598 | CODE_SIGN_STYLE = Automatic;
599 | DEVELOPMENT_TEAM = 6VU6999229;
600 | INFOPLIST_FILE = LightCardTabBarUITests/Info.plist;
601 | LD_RUNPATH_SEARCH_PATHS = (
602 | "$(inherited)",
603 | "@executable_path/Frameworks",
604 | "@loader_path/Frameworks",
605 | );
606 | PRODUCT_BUNDLE_IDENTIFIER = me.sketch.LightCardTabBarUITests;
607 | PRODUCT_NAME = "$(TARGET_NAME)";
608 | SWIFT_VERSION = 5.0;
609 | TARGETED_DEVICE_FAMILY = "1,2";
610 | TEST_TARGET_NAME = LightCardTabBar;
611 | };
612 | name = Debug;
613 | };
614 | E403A89D266B5BAB00EFFA93 /* Release */ = {
615 | isa = XCBuildConfiguration;
616 | buildSettings = {
617 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
618 | CODE_SIGN_STYLE = Automatic;
619 | DEVELOPMENT_TEAM = 6VU6999229;
620 | INFOPLIST_FILE = LightCardTabBarUITests/Info.plist;
621 | LD_RUNPATH_SEARCH_PATHS = (
622 | "$(inherited)",
623 | "@executable_path/Frameworks",
624 | "@loader_path/Frameworks",
625 | );
626 | PRODUCT_BUNDLE_IDENTIFIER = me.sketch.LightCardTabBarUITests;
627 | PRODUCT_NAME = "$(TARGET_NAME)";
628 | SWIFT_VERSION = 5.0;
629 | TARGETED_DEVICE_FAMILY = "1,2";
630 | TEST_TARGET_NAME = LightCardTabBar;
631 | };
632 | name = Release;
633 | };
634 | /* End XCBuildConfiguration section */
635 |
636 | /* Begin XCConfigurationList section */
637 | E403A866266B5BAA00EFFA93 /* Build configuration list for PBXProject "LightCardTabBar" */ = {
638 | isa = XCConfigurationList;
639 | buildConfigurations = (
640 | E403A893266B5BAB00EFFA93 /* Debug */,
641 | E403A894266B5BAB00EFFA93 /* Release */,
642 | );
643 | defaultConfigurationIsVisible = 0;
644 | defaultConfigurationName = Release;
645 | };
646 | E403A895266B5BAB00EFFA93 /* Build configuration list for PBXNativeTarget "LightCardTabBar" */ = {
647 | isa = XCConfigurationList;
648 | buildConfigurations = (
649 | E403A896266B5BAB00EFFA93 /* Debug */,
650 | E403A897266B5BAB00EFFA93 /* Release */,
651 | );
652 | defaultConfigurationIsVisible = 0;
653 | defaultConfigurationName = Release;
654 | };
655 | E403A898266B5BAB00EFFA93 /* Build configuration list for PBXNativeTarget "LightCardTabBarTests" */ = {
656 | isa = XCConfigurationList;
657 | buildConfigurations = (
658 | E403A899266B5BAB00EFFA93 /* Debug */,
659 | E403A89A266B5BAB00EFFA93 /* Release */,
660 | );
661 | defaultConfigurationIsVisible = 0;
662 | defaultConfigurationName = Release;
663 | };
664 | E403A89B266B5BAB00EFFA93 /* Build configuration list for PBXNativeTarget "LightCardTabBarUITests" */ = {
665 | isa = XCConfigurationList;
666 | buildConfigurations = (
667 | E403A89C266B5BAB00EFFA93 /* Debug */,
668 | E403A89D266B5BAB00EFFA93 /* Release */,
669 | );
670 | defaultConfigurationIsVisible = 0;
671 | defaultConfigurationName = Release;
672 | };
673 | /* End XCConfigurationList section */
674 | };
675 | rootObject = E403A863266B5BAA00EFFA93 /* Project object */;
676 | }
677 |
--------------------------------------------------------------------------------