├── .DS_Store
├── TestMenu
├── .DS_Store
├── Assets.xcassets
│ ├── Contents.json
│ ├── dropdown_menu_triangle.imageset
│ │ ├── triangle.png
│ │ └── Contents.json
│ ├── discovery_icon_investor.imageset
│ │ ├── discovery_icon_investor@2x.png
│ │ ├── discovery_icon_investor@3x.png
│ │ └── Contents.json
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── Supporting Files
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── AppDelegate.swift
│ ├── Info.plist
│ └── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
├── DropdownMenu
│ ├── Resource
│ │ └── DropdownMenu.xcassets
│ │ │ ├── Contents.json
│ │ │ ├── .DS_Store
│ │ │ └── dropdown_menu_triangle.imageset
│ │ │ ├── common_filter_arrow_down@2x.png
│ │ │ ├── common_filter_arrow_down@3x.png
│ │ │ └── Contents.json
│ ├── Views
│ │ ├── DropdownSubmenu.swift
│ │ ├── DorpdownMainMenu.swift
│ │ ├── DropdownSubmenuTableView.swift
│ │ └── DropdownSubmenuCollectionView.swift
│ ├── Utils
│ │ ├── FontManager.swift
│ │ ├── ColorManager.swift
│ │ ├── AppColor+Utils.swift
│ │ ├── UIView+Utils.swift
│ │ └── UIView+AutoLayout.swift
│ ├── DropdownMenu+Types.swift
│ ├── DropdownMenuConfiguration.swift
│ ├── DropdownMenuViewController+TableView.swift
│ ├── DropdownMenuViewController+CollectionView.swift
│ └── DropdownMenuViewController.swift
├── ViewController.swift
└── DemoDropdownMenuManager.swift
├── screenshots
└── screenshoot.gif
├── TestMenu.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcuserdata
│ │ └── inatu.xcuserdatad
│ │ └── UserInterfaceState.xcuserstate
├── xcuserdata
│ └── inatu.xcuserdatad
│ │ ├── xcschemes
│ │ ├── xcschememanagement.plist
│ │ └── TestMenu.xcscheme
│ │ └── xcdebugger
│ │ └── Breakpoints_v2.xcbkptlist
└── project.pbxproj
├── TestMenuTests
├── Info.plist
└── TestMenuTests.swift
└── README.md
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shannon-s-Dreamland/DropdownMenu/HEAD/.DS_Store
--------------------------------------------------------------------------------
/TestMenu/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shannon-s-Dreamland/DropdownMenu/HEAD/TestMenu/.DS_Store
--------------------------------------------------------------------------------
/TestMenu/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/screenshots/screenshoot.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shannon-s-Dreamland/DropdownMenu/HEAD/screenshots/screenshoot.gif
--------------------------------------------------------------------------------
/TestMenu/Supporting Files/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/TestMenu/DropdownMenu/Resource/DropdownMenu.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/TestMenu/DropdownMenu/Resource/DropdownMenu.xcassets/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shannon-s-Dreamland/DropdownMenu/HEAD/TestMenu/DropdownMenu/Resource/DropdownMenu.xcassets/.DS_Store
--------------------------------------------------------------------------------
/TestMenu/Assets.xcassets/dropdown_menu_triangle.imageset/triangle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shannon-s-Dreamland/DropdownMenu/HEAD/TestMenu/Assets.xcassets/dropdown_menu_triangle.imageset/triangle.png
--------------------------------------------------------------------------------
/TestMenu.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/TestMenu/Assets.xcassets/discovery_icon_investor.imageset/discovery_icon_investor@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shannon-s-Dreamland/DropdownMenu/HEAD/TestMenu/Assets.xcassets/discovery_icon_investor.imageset/discovery_icon_investor@2x.png
--------------------------------------------------------------------------------
/TestMenu/Assets.xcassets/discovery_icon_investor.imageset/discovery_icon_investor@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shannon-s-Dreamland/DropdownMenu/HEAD/TestMenu/Assets.xcassets/discovery_icon_investor.imageset/discovery_icon_investor@3x.png
--------------------------------------------------------------------------------
/TestMenu.xcodeproj/project.xcworkspace/xcuserdata/inatu.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shannon-s-Dreamland/DropdownMenu/HEAD/TestMenu.xcodeproj/project.xcworkspace/xcuserdata/inatu.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/TestMenu/DropdownMenu/Resource/DropdownMenu.xcassets/dropdown_menu_triangle.imageset/common_filter_arrow_down@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shannon-s-Dreamland/DropdownMenu/HEAD/TestMenu/DropdownMenu/Resource/DropdownMenu.xcassets/dropdown_menu_triangle.imageset/common_filter_arrow_down@2x.png
--------------------------------------------------------------------------------
/TestMenu/DropdownMenu/Resource/DropdownMenu.xcassets/dropdown_menu_triangle.imageset/common_filter_arrow_down@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Shannon-s-Dreamland/DropdownMenu/HEAD/TestMenu/DropdownMenu/Resource/DropdownMenu.xcassets/dropdown_menu_triangle.imageset/common_filter_arrow_down@3x.png
--------------------------------------------------------------------------------
/TestMenu/Supporting Files/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // TestMenu
4 | //
5 | // Created by Shannon Wu on 12/18/15.
6 | // Copyright © 2015 Shannon's Dreamland. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 | }
17 |
18 |
--------------------------------------------------------------------------------
/TestMenu/Assets.xcassets/dropdown_menu_triangle.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "triangle.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestMenu/DropdownMenu/Views/DropdownSubmenu.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DropdownSubmenu.swift
3 | // Client
4 | //
5 | // Created by Shannon Wu on 12/22/15.
6 | // Copyright © 2015 36Kr. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | // MARK: - Submenu
12 | protocol DropdownSubmenu: class {
13 | var title: String? { get }
14 |
15 | func reload(includeMainMenu: Bool)
16 | func removeFromSuperview()
17 | func selectItemAtIndex(index: DropdownSubmenuIndex)
18 | }
19 |
--------------------------------------------------------------------------------
/TestMenu/Assets.xcassets/discovery_icon_investor.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "discovery_icon_investor@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "discovery_icon_investor@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/TestMenu/DropdownMenu/Resource/DropdownMenu.xcassets/dropdown_menu_triangle.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "common_filter_arrow_down@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "common_filter_arrow_down@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/TestMenu/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // TestMenu
4 | //
5 | // Created by Shannon Wu on 12/18/15.
6 | // Copyright © 2015 Shannon's Dreamland. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ViewController: UIViewController {
12 |
13 | let menuViewController = DropdownMenuViewController()
14 | let menuManager = DemoDropdownMenuManager()
15 |
16 | override func viewDidLoad() {
17 | menuViewController.menuManager = menuManager
18 | menuManager.menuVC = menuViewController
19 |
20 | view.addSubview(menuViewController.view)
21 | }
22 | }
23 |
24 |
--------------------------------------------------------------------------------
/TestMenu.xcodeproj/xcuserdata/inatu.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | TestMenu.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | 6162CD1F1C2407F90094A00B
16 |
17 | primary
18 |
19 |
20 | 6162CD331C2407F90094A00B
21 |
22 | primary
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/TestMenuTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/TestMenu.xcodeproj/xcuserdata/inatu.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
8 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/TestMenuTests/TestMenuTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TestMenuTests.swift
3 | // TestMenuTests
4 | //
5 | // Created by Shannon Wu on 12/18/15.
6 | // Copyright © 2015 Shannon's Dreamland. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import TestMenu
11 |
12 | class TestMenuTests: XCTestCase {
13 |
14 | override func setUp() {
15 | super.setUp()
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 | }
18 |
19 | override func tearDown() {
20 | // Put teardown code here. This method is called after the invocation of each test method in the class.
21 | super.tearDown()
22 | }
23 |
24 | func testExample() {
25 | // This is an example of a functional test case.
26 | // Use XCTAssert and related functions to verify your tests produce the correct results.
27 | }
28 |
29 | func testPerformanceExample() {
30 | // This is an example of a performance test case.
31 | self.measureBlock {
32 | // Put the code you want to measure the time of here.
33 | }
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/TestMenu/DropdownMenu/Utils/FontManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FontManager.swift
3 | // Client
4 | //
5 | // Created by Shannon Wu on 10/26/15.
6 | // Copyright © 2015 36Kr. All rights reserved.
7 | //
8 |
9 | #if os(iOS) || os(watchOS)
10 | import UIKit
11 | #elseif os(OSX)
12 | import Cocoa
13 | #endif
14 |
15 | #if os(iOS) || os(watchOS)
16 | typealias AppFont = UIFont
17 | #elseif os(OSX)
18 | typealias AppFont = NSFont
19 | #endif
20 |
21 | struct FontManager {
22 |
23 | static var headline: AppFont {
24 | return AppFont.systemFontOfSize(18)
25 | }
26 |
27 | static var subheadline: AppFont {
28 | return AppFont.systemFontOfSize(17)
29 | }
30 |
31 | static var boldSubheadline: AppFont {
32 | return AppFont.boldSystemFontOfSize(17)
33 | }
34 |
35 | static var caption1: AppFont {
36 | return AppFont.systemFontOfSize(15)
37 | }
38 |
39 | static var body: AppFont {
40 | return AppFont.systemFontOfSize(14)
41 | }
42 |
43 | static var caption2: AppFont {
44 | return AppFont.systemFontOfSize(13)
45 | }
46 |
47 | static var footnote: AppFont {
48 | return AppFont.systemFontOfSize(11)
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/TestMenu/DropdownMenu/DropdownMenu+Types.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DropdownMenuManager.swift
3 | // Client
4 | //
5 | // Created by Shannon Wu on 12/23/15.
6 | // Copyright © 2015 36Kr. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | // MARK: - Menu Manager
12 |
13 | protocol DropdownMenuManager: DropdownMenuDelegate {
14 |
15 | // Main Menu
16 | func intialTitlesForMainMenu() -> [String]
17 |
18 | // Submenu
19 | func numberOfSectionsInSubmenu(isMainSubmenu: Bool) -> Int
20 | func titleForSectionInSubmenu(section: Int) -> String?
21 |
22 | func numberOfRowsInSection(section: Int, isMainSubmenu: Bool) -> Int
23 | func titleForDropdownSubmenuIndex(index: DropdownSubmenuIndex) -> String?
24 |
25 | func didSelectSubmenuAtIndex(index: DropdownSubmenuIndex)
26 |
27 | var shrinkStateItemCount: Int { get }
28 |
29 | // Reload Data
30 | func reloadData()
31 |
32 | // Toggle Open
33 | func toggleOpenState(state: Bool)
34 |
35 | // Reset state
36 | func resetSelectionState()
37 | }
38 |
39 | // MARK: - Submenu Index
40 |
41 | struct DropdownSubmenuIndex {
42 | var main: Int?
43 | var secondary: Int?
44 |
45 | init(main: Int?, secondary: Int?) {
46 | self.main = main
47 | self.secondary = secondary
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # 说明
3 |
4 | 
5 |
6 | 这是一个用面向对象写的二级下拉菜单的示例. 上面的图使我们即将发布的4.0版本的截图, 它只是用来演示这个 demo 能达到什么效果, 代码中不包含这一块业务的实现!
7 |
8 | 我现在正计划写 iOS 开发的两个专题, 分别是关于36氪4.0版本的程序架构和用面向对象的方法做UI开发, 这个示例属于后者, 你可以在[这个网址](http://www.jianshu.com/users/61cd67a3e447/latest_articles)找到所有的文章, 很遗憾, 因为我们4.0的开发任务比较繁重,尽管我最近经常晚上写代码到凌晨, 但是还是 一直没有时间总结这些东西, 我是计划春节后将这两个专题的文章都完成, 算是在36氪工作半年来的一个总结. 希望回家后我的小侄子不会缠着我吧!
9 |
10 | 你可以随时关注上面的博客地址来获取最新的更新.
11 |
12 | ## 关于这个示例
13 |
14 | 示例的很多代码, 除了`DemoDropdownMenuManager`这个是自己编造的之外, 其它都是用在了我们的程序开发中的生产代码, 虽然都是自己的劳动成果, 但是所有权属于 36氪.
15 |
16 | ## 示例的局限性
17 |
18 | 1. 里面的`DropdownMenuConfiguration`文件比较杂乱, 没有办法, 按照我们 UI 的说法, 他们追求1像素的精度, 尽管我觉得 title 的字体应该一样, 但是说服不了他们, 为了方便调节面, 所以分的很细. 他们应该不会看到这句话!
19 |
20 | 2. `UIView+AutoLayout`的代码会需要重构, 其实它的作用和[SnapKit](https://github.com/SnapKit/SnapKit)挺类似, 但是我不喜欢它的前缀语法, 觉得 Swift 的 Extension 特性已经能写出更自然的语法, 但是我对自动布局的认识还不全面, 打算研究苹果的文档和 [SnapKit](https://github.com/SnapKit/SnapKit) 后自己写一个布局的 Library.
21 |
22 | 3. 这个界面只是整个工程很小的一部分, 其实上面的数据交互, 包括具体的 MenuManager的实现, 网络请求的管理, 缓存数据等是更复杂的交互逻辑, 这些东西我是打算放在以后关于架构的文章中介绍.这个 Menu 的作用只是提供一个可扩展的 Menu 界面, 也就是它并没有任何的逻辑在里面.
23 |
24 | 4. Menu 做的比较基础, 但是已经留出了很充足的接口进行扩展,我觉得你可以轻松的扩展, 比如想做出现的动画, 就可以在 `DropdownMenuViewController`的`animateHideSubmenu()`和`animateShowSubmenu()`中自己实现动画, 或者使用第三方的[pop](https://github.com/facebook/pop)或者其它动画库.
25 |
--------------------------------------------------------------------------------
/TestMenu/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "ipad",
35 | "size" : "29x29",
36 | "scale" : "1x"
37 | },
38 | {
39 | "idiom" : "ipad",
40 | "size" : "29x29",
41 | "scale" : "2x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "40x40",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "40x40",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "76x76",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "76x76",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "83.5x83.5",
66 | "scale" : "2x"
67 | }
68 | ],
69 | "info" : {
70 | "version" : 1,
71 | "author" : "xcode"
72 | }
73 | }
--------------------------------------------------------------------------------
/TestMenu/Supporting Files/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "ipad",
35 | "size" : "29x29",
36 | "scale" : "1x"
37 | },
38 | {
39 | "idiom" : "ipad",
40 | "size" : "29x29",
41 | "scale" : "2x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "40x40",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "40x40",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "76x76",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "76x76",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "83.5x83.5",
66 | "scale" : "2x"
67 | }
68 | ],
69 | "info" : {
70 | "version" : 1,
71 | "author" : "xcode"
72 | }
73 | }
--------------------------------------------------------------------------------
/TestMenu/DropdownMenu/Utils/ColorManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ColorManager.swift
3 | // Client
4 | //
5 | // Created by Shannon Wu on 10/22/15.
6 | // Copyright © 2015 36Kr. All rights reserved.
7 | //
8 |
9 | #if os(iOS) || os(watchOS)
10 | import UIKit
11 | #elseif os(OSX)
12 | import Cocoa
13 | #endif
14 |
15 | struct ColorManager {
16 |
17 | static var title: AppColor {
18 | return AppColor(hex: 0x222c38)
19 | }
20 |
21 | static var content: AppColor {
22 | return AppColor(hex: 0x5a626d)
23 | }
24 |
25 | static var prompt: AppColor {
26 | return AppColor(hex: 0x969fa9)
27 | }
28 |
29 | static var divider: AppColor {
30 | return AppColor(hex: 0xe7e7e7)
31 | }
32 |
33 | static var background: AppColor {
34 | return AppColor(hex: 0xf9f9f9)
35 | }
36 |
37 | static var theme: AppColor {
38 | return AppColor(hex: 0x4285f4)
39 | }
40 |
41 | static var auxiliary: AppColor {
42 | return AppColor(hex: 0xff6e0e)
43 | }
44 |
45 | static var success: AppColor {
46 | return AppColor(hex: 0x31c27c)
47 | }
48 |
49 | static var failure: AppColor {
50 | return AppColor(hex: 0xf0633d)
51 | }
52 |
53 | static var empty: AppColor {
54 | return AppColor(hex: 0xcccccc)
55 | }
56 |
57 | static var lightBackground: AppColor {
58 | return AppColor(hex: 0xfafafa)
59 | }
60 |
61 | static var greenHighlight: AppColor {
62 | return AppColor(hex: 0x3da300)
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/TestMenu/Supporting Files/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
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 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
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 |
--------------------------------------------------------------------------------
/TestMenu/Supporting Files/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 |
--------------------------------------------------------------------------------
/TestMenu/Supporting Files/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 |
--------------------------------------------------------------------------------
/TestMenu/DemoDropdownMenuManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DemoDropdownMenuManager.swift
3 | // TestMenu
4 | //
5 | // Created by Shannon Wu on 12/19/15.
6 | // Copyright © 2015 Shannon's Dreamland. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class DemoDropdownMenuManager: DropdownMenuManager {
12 |
13 | weak var menuVC: DropdownMenuViewController?
14 |
15 | private var currentlySelectedIndex: Int?
16 |
17 | var shrinkStateItemCount: Int {
18 | return 12
19 | }
20 |
21 | func intialTitlesForMainMenu() -> [String] {
22 | return ["你好", "我不好", "你好不好", "好!"]
23 | }
24 |
25 | func mainMenuItemAtIndexSelected(index: Int) {
26 | if index == currentlySelectedIndex {
27 | menuVC?.animateHideSubmenu()
28 | resetSelectionState()
29 | return
30 | }
31 | currentlySelectedIndex = index
32 | if index == 0 {
33 | menuVC?.submenuType = .TableViewSingleView
34 | }
35 | else if index == 1 {
36 | menuVC?.submenuType = .TableViewDoubleView
37 | } else if index == 2{
38 | menuVC?.submenuType = .CollectionView
39 | } else {
40 | menuVC?.submenuType = .TableViewSingleView
41 | }
42 | }
43 |
44 | func resetSelectionState() {
45 | currentlySelectedIndex = nil
46 | }
47 |
48 | func didSelectSubmenuAtIndex(index: DropdownSubmenuIndex) {
49 | print("\(index.main) \(index.secondary)")
50 | }
51 |
52 | func numberOfSectionsInSubmenu(isMainSubmenu: Bool) -> Int {
53 | return 2
54 | }
55 |
56 | func numberOfRowsInSection(section: Int, isMainSubmenu: Bool) -> Int {
57 | return 5
58 | }
59 |
60 | func titleForDropdownSubmenuIndex(index: DropdownSubmenuIndex) -> String? {
61 | return "现在好点了"
62 | }
63 |
64 | func titleForSectionInSubmenu(section: Int) -> String? {
65 | return "好多了@"
66 | }
67 |
68 | func toggleOpenState(state: Bool) {}
69 |
70 | func reloadData() {}
71 | }
72 |
--------------------------------------------------------------------------------
/TestMenu/DropdownMenu/Utils/AppColor+Utils.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppColor+Utils.swift
3 | // Client
4 | //
5 | // Created by Shannon Wu on 10/21/15.
6 | // Copyright © 2015 36Kr. All rights reserved.
7 | //
8 |
9 | #if os(iOS) || os(watchOS)
10 | import UIKit
11 | #elseif os(OSX)
12 | import Cocoa
13 | #endif
14 |
15 | #if os(iOS) || os(watchOS)
16 | /// AppColor 是 UIColor 的别名.
17 | typealias AppColor = UIColor
18 | #elseif os(OSX)
19 | /// AppColor 是 NSColor 的别名.
20 | typealias AppColor = NSColor
21 | #endif
22 |
23 | // MARK: - 扩展 UIColor 或者 NSColor, 包含一些常量和初始化方法.
24 | extension AppColor {
25 |
26 | /// 返回一个随机的 UIColor 或者 NSColor.
27 | static var randomColor: AppColor {
28 | let r = CGFloat(drand48())
29 | let g = CGFloat(drand48())
30 | let b = CGFloat(drand48())
31 |
32 | return AppColor(red: r, green: g, blue: b, alpha: 1.0)
33 | }
34 |
35 | /**
36 | 通过颜色值的 Hex 字符串和 默认为1.0的 Alpha 值来初始化一个 UIColor 或者 NSColor.
37 |
38 | - parameter hexString: 颜色值的 Hex 字符串, 传入的字符串可以为 `FFFFFF`
39 | 或者 `#FFFFFF` 的形式.
40 | - parameter alpha: 颜色值的 alpha 值, 默认为 1.0
41 |
42 | - returns: 如果传入的 Hex 字符串有效, 则返回一个初始化成功的UIColor 或者 NSColor;
43 | 如果传入的 Hex 字符串无效, 则返回 nil.
44 | */
45 | convenience init?(hexString: String, alpha: CGFloat = 1.0){
46 | var result: UInt32 = 0
47 |
48 | let scanner = NSScanner(string: hexString)
49 | if hexString.characters.first == "#" {
50 | scanner.scanLocation = 1
51 | } else {
52 | scanner.scanLocation = 0
53 | }
54 |
55 | if !scanner.scanHexInt(&result) { return nil }
56 |
57 | self.init(hex: result, alpha: alpha)
58 | }
59 |
60 | /**
61 | 通过颜色值的 Hex 值和默认为1.0的 Alpha 值来初始化一个 UIColor 或者 NSColor.
62 |
63 | - parameter hex: 颜色值的 Hex值, 传入 UInt32类型的值.
64 | - parameter alpha: 颜色值的 alpha 值, 默认为 1.0
65 |
66 | - returns: 返回一个初始化成功的UIColor 或者 NSColor
67 | */
68 | convenience init(hex: UInt32, alpha: CGFloat = 1.0) {
69 | let r = CGFloat(((hex & 0xFF0000) >> 16)) / 255.0
70 | let g = CGFloat(((hex & 0xFF00) >> 8)) / 255.0
71 | let b = CGFloat(((hex & 0xFF))) / 255.0
72 |
73 | self.init(red: r, green: g, blue: b, alpha: alpha)
74 | }
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/TestMenu/DropdownMenu/Utils/UIView+Utils.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+Utils.swift
3 | // TestMenu
4 | //
5 | // Created by Shannon Wu on 12/24/15.
6 | // Copyright © 2015 Shannon's Dreamland. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension UIRectEdge: Hashable {
12 | public var hashValue: Int {
13 | return Int(self.rawValue)
14 | }
15 | }
16 |
17 | extension UIView {
18 | func addBorder(edges edges: UIRectEdge, colour: UIColor = UIColor.whiteColor(), thickness: CGFloat = 1) -> [UIRectEdge: UIView] {
19 | var borders = [UIRectEdge: UIView]()
20 |
21 | func border() -> UIView {
22 | let border = UIView(frame: CGRectZero)
23 | border.backgroundColor = colour
24 | border.translatesAutoresizingMaskIntoConstraints = false
25 | return border
26 | }
27 |
28 | if edges.contains(.Top) || edges.contains(.All) {
29 | let top = border()
30 | addSubview(top)
31 | borders[.Top] = top
32 | top.addDimentionConstraints(.Height, constant: thickness)
33 | top.pinToSuperView(.Top, inset: 0, relation: .Equal)
34 | }
35 |
36 | if edges.contains(.Left) || edges.contains(.All) {
37 | let left = border()
38 | addSubview(left)
39 | borders[.Left] = left
40 | left.addDimentionConstraints(.Width, constant: thickness)
41 | left.pinToSuperView(.Leading, inset: 0, relation: .Equal)
42 | }
43 |
44 | if edges.contains(.Right) || edges.contains(.All) {
45 | let right = border()
46 | addSubview(right)
47 | borders[.Right] = right
48 | right.addDimentionConstraints(.Width, constant: thickness)
49 | right.pinToSuperView(.Trailing, inset: 0, relation: .Equal)
50 | }
51 |
52 | if edges.contains(.Bottom) || edges.contains(.All) {
53 | let bottom = border()
54 | addSubview(bottom)
55 | borders[.Bottom] = bottom
56 | bottom.addDimentionConstraints(.Height, constant: thickness)
57 | bottom.pinToSuperView(.Bottom, inset: 0, relation: .Equal)
58 | }
59 |
60 | return borders
61 | }
62 | }
--------------------------------------------------------------------------------
/TestMenu/DropdownMenu/DropdownMenuConfiguration.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DropdownMenuConfiguration.swift
3 | // TestMenu
4 | //
5 | // Created by Shannon Wu on 12/20/15.
6 | // Copyright © 2015 Shannon's Dreamland. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | // MARK: - Menu Item
12 |
13 | struct DropdownMenuConfiguration {
14 | // MARK: Main Menu
15 | static let mainMenuFrame = CGRect(x: 0, y: 64.0, width: UIScreen.mainScreen().bounds.width, height: 50.0)
16 | static let mainMenuHeight: CGFloat = 50.0
17 | static let mainMenuBackgoundColor = UIColor.whiteColor()
18 | static let mainMenuBorderWidth: CGFloat = 1.0
19 | static let mainMenuBorderColor = ColorManager.divider
20 | static let mainMenuFont = FontManager.caption2
21 | static let mainMenuTopOffset: CGFloat = 64.0
22 |
23 | // MARK: Submenu
24 | static let mainSubmenuBackgroundColor = ColorManager.lightBackground
25 |
26 | // MARK: TableViewSubmenu
27 | static let tableViewMainSubMenuLeftOffSet: CGFloat = 44.0
28 | static let tableViewSecondarySubMenuLeftOffSet: CGFloat = 30.0
29 |
30 | // MARK: CollectionViewSubmenu
31 | static let collectionViewSubmenuBodyFont = FontManager.body
32 | static let collectionViewSubmenuHeaderFont = FontManager.caption1
33 | static let collectionViewSubmenuSideMargin: CGFloat = 15.0
34 | static let collectionViewSubmenuTopMargin: CGFloat = 13.0
35 | static let collectionViewSubmenuFinishButtonFont = FontManager.caption1
36 | static let collectionViewSubmenuHeaderReferenceSize = CGSize(width: 0, height: 45.0)
37 | static let collectionViewSubmenuEdgeInsets = UIEdgeInsets(top: 0.0, left: 15.0, bottom: 0.0, right: 15.0)
38 | static let collectionViewSubmenuItemSize = CGSize(width: 80.0, height: 33.0)
39 | static let collectionViewSubmenuMinimumInteritemSpacing: CGFloat = 12.0
40 | static let collectionViewSubmenuMinimumLineSpacing: CGFloat = 15.0
41 | static let collectionViewSubmenuFirstSectionSize = CGSize(width: 0, height: 15.0)
42 | static let collectionViewSubmenuSecondSectionSize = CGSize(width: 0, height: 108.0)
43 |
44 | // MARK: Identifier
45 | static let cellIdentifier = "Cell"
46 | static let headerIdentifier = "Header"
47 | static let decorationFooterIdentifier = "DecorationFooter"
48 | static let doneFooterIdentifier = "DoneIdentifier"
49 |
50 | // MARK: Overall
51 | static let normalColor = ColorManager.content
52 | static let highlightColor = ColorManager.theme
53 | static let separatorColor = ColorManager.divider
54 | static let headerFont = FontManager.caption1
55 | static let triangleImage = UIImage(named: "dropdown_menu_triangle")
56 |
57 | static let secondarySubmenuBackgroundColor = UIColor.whiteColor()
58 | static let space: CGFloat = 3.0
59 | static let tableViewCellHeight: CGFloat = 50.0
60 |
61 | // MARK: Background
62 | static let backgroundViewColor = UIColor.blackColor()
63 | static let backgroundViewAlpha: CGFloat = 0.3
64 | static let backgroundViewMinimumHeight: CGFloat = 120.0
65 | }
66 |
--------------------------------------------------------------------------------
/TestMenu.xcodeproj/xcuserdata/inatu.xcuserdatad/xcschemes/TestMenu.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
49 |
50 |
51 |
52 |
53 |
54 |
64 |
66 |
72 |
73 |
74 |
75 |
76 |
77 |
83 |
85 |
91 |
92 |
93 |
94 |
96 |
97 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/TestMenu/DropdownMenu/Views/DorpdownMainMenu.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DorpdownMenuMainMenu.swift
3 | // TestMenu
4 | //
5 | // Created by Shannon Wu on 12/20/15.
6 | // Copyright © 2015 Shannon's Dreamland. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | // MARK: - Main Menu Item
12 |
13 | class DropdownMenuItem: UIView {
14 | // MARK: Properties
15 |
16 | private var triangleImageView: UIImageView = {
17 | let image = UIImage(named: "dropdown_menu_triangle")?.imageWithRenderingMode(.AlwaysTemplate)
18 | let imageView = UIImageView(image: image)
19 | imageView.tintColor = DropdownMenuConfiguration.normalColor
20 | imageView.layer.anchorPoint = CGPoint(x: 0.5, y: 0.5)
21 | imageView.translatesAutoresizingMaskIntoConstraints = false
22 | return imageView
23 | }()
24 |
25 | private var titleLabel: UILabel = {
26 | let label = UILabel()
27 | label.font = DropdownMenuConfiguration.mainMenuFont
28 | label.translatesAutoresizingMaskIntoConstraints = false
29 | return label
30 | }()
31 |
32 | private var selected: Bool = false {
33 | didSet {
34 | if selected {
35 | titleLabel.textColor = DropdownMenuConfiguration.highlightColor
36 | triangleImageView.tintColor = DropdownMenuConfiguration.highlightColor
37 | triangleImageView.transform = CGAffineTransformMakeRotation(CGFloat(M_PI))
38 | }
39 | else {
40 | titleLabel.textColor = DropdownMenuConfiguration.normalColor
41 | triangleImageView.tintColor = DropdownMenuConfiguration.normalColor
42 | triangleImageView.transform = CGAffineTransformMakeRotation(0)
43 | }
44 | }
45 | }
46 |
47 | // MARK: Initializers
48 |
49 | init(title: String) {
50 | super.init(frame: CGRect.zero)
51 |
52 | titleLabel.text = title
53 | commonInit()
54 | }
55 |
56 | required init?(coder aDecoder: NSCoder) {
57 | fatalError("init(coder:) has not been implemented")
58 | }
59 |
60 | func commonInit() {
61 |
62 | addSubview(triangleImageView)
63 | addSubview(titleLabel)
64 |
65 | titleLabel.positionToSuperView(horizontal: .Center, hOffset: 0, vertical: .Center, vOffset: 0)
66 | triangleImageView.positionRelativeToView(titleLabel, direction: .Trailing, space: DropdownMenuConfiguration.space)
67 | }
68 |
69 | }
70 |
71 | // MARK: - Main Menu Delegate
72 |
73 | protocol DropdownMenuDelegate: class {
74 | func mainMenuItemAtIndexSelected(index: Int)
75 | }
76 |
77 | // MARK: - Main Menu
78 |
79 | class DropdownMenu: UIView {
80 | // MARK: Properties
81 |
82 | private let menuItems: [DropdownMenuItem]
83 | private var selectedItem: DropdownMenuItem?
84 |
85 | weak var delegate: DropdownMenuDelegate?
86 |
87 | // MARK: Initializers
88 |
89 | init(items: [String], delegate: DropdownMenuDelegate) {
90 | self.delegate = delegate
91 |
92 | var menuItems = [DropdownMenuItem]()
93 | for (index, title) in items.enumerate() {
94 | let item = DropdownMenuItem(title: title)
95 | item.tag = index
96 | item.translatesAutoresizingMaskIntoConstraints = false
97 | menuItems.append(item)
98 | }
99 | self.menuItems = menuItems
100 |
101 | super.init(frame: CGRect.zero)
102 |
103 | commonInit()
104 | }
105 |
106 | required init?(coder aDecoder: NSCoder) {
107 | fatalError("init(coder:) has not been implemented")
108 | }
109 |
110 | func commonInit() {
111 |
112 | backgroundColor = DropdownMenuConfiguration.mainMenuBackgoundColor
113 | layer.borderWidth = DropdownMenuConfiguration.mainMenuBorderWidth
114 | layer.borderColor = DropdownMenuConfiguration.mainMenuBorderColor.CGColor
115 |
116 | menuItems.forEach { item in
117 | addSubview(item)
118 | }
119 |
120 | if menuItems.count != 0 {
121 | let menuItemsTuple: [ViewTuple] = menuItems.map { item in
122 | return (item, 1.0)
123 | }
124 | LayoutKit.arrangeViews(.Horizontal, viewsTuple: menuItemsTuple)
125 | }
126 | }
127 |
128 | // MARK: Methods
129 |
130 | override func touchesBegan(touches: Set, withEvent event: UIEvent?) {
131 | guard let touch = touches.first else { return }
132 |
133 | let position = touch.locationInView(self)
134 |
135 | guard let touchedView = hitTest(position, withEvent: event) as? DropdownMenuItem else { return }
136 |
137 | touchedView.selected = true
138 | if selectedItem != touchedView {
139 | selectedItem?.selected = false
140 | }
141 | selectedItem = touchedView
142 |
143 | delegate?.mainMenuItemAtIndexSelected(touchedView.tag)
144 | }
145 |
146 | func setTitleForSelectedItem(title: String?) {
147 | if let title = title {
148 | selectedItem?.titleLabel.text = title
149 | }
150 | selectedItem?.selected = false
151 | }
152 |
153 | }
154 |
--------------------------------------------------------------------------------
/TestMenu/DropdownMenu/DropdownMenuViewController+TableView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DropdownMenuViewController+TableView.swift
3 | // TestMenu
4 | //
5 | // Created by Shannon Wu on 12/20/15.
6 | // Copyright © 2015 Shannon's Dreamland. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | // MARK: DropdownMenu + UITableViewDelegate
12 |
13 | extension DropdownMenuViewController: UITableViewDelegate {
14 | func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
15 | return DropdownMenuConfiguration.tableViewCellHeight
16 | }
17 |
18 | func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
19 | guard let submenuType = submenuType else {
20 | assertionFailure("在没有设置 SubMenu 的时候, 不应该调到这个方法")
21 | return
22 | }
23 |
24 | switch submenuType {
25 | case .TableViewSingleView:
26 | menuManager?.didSelectSubmenuAtIndex(DropdownSubmenuIndex(main: indexPath.row, secondary: nil))
27 | animateHideSubmenu()
28 | case .TableViewDoubleView:
29 | if let type = DropdownTableViewSubmenuDoubleViewType(rawValue: tableView.tag) {
30 | switch type {
31 | case .Main:
32 | menuManager?.didSelectSubmenuAtIndex(DropdownSubmenuIndex(main: indexPath.row, secondary: nil))
33 | case .Secondary:
34 | menuManager?.didSelectSubmenuAtIndex(DropdownSubmenuIndex(main: nil, secondary: indexPath.row))
35 | animateHideSubmenu()
36 | }
37 | }
38 | case .CollectionView:
39 | assertionFailure("不应该请求到 CollectionView")
40 | }
41 | }
42 | }
43 |
44 | // MARK: DropdownMenu + UITableViewDataSource
45 |
46 | extension DropdownMenuViewController: UITableViewDataSource {
47 | func numberOfSectionsInTableView(tableView: UITableView) -> Int {
48 | guard let submenuType = submenuType else {
49 | assertionFailure("在没有设置 SubMenu 的时候, 不应该调到这个方法")
50 | return 0
51 | }
52 |
53 | switch submenuType {
54 | case .TableViewSingleView:
55 | return menuManager?.numberOfSectionsInSubmenu(true) ?? 0
56 | case .TableViewDoubleView:
57 | if let type = DropdownTableViewSubmenuDoubleViewType(rawValue: tableView.tag) {
58 | switch type {
59 | case .Main:
60 | return menuManager?.numberOfSectionsInSubmenu(true) ?? 0
61 | case .Secondary:
62 | return menuManager?.numberOfSectionsInSubmenu(false) ?? 0
63 | }
64 | }
65 | assertionFailure("必须要获取到 Type")
66 | return 0
67 | case .CollectionView:
68 | assertionFailure("不应该请求到 CollectionView")
69 | return 0
70 | }
71 | }
72 |
73 | func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
74 | guard let submenuType = submenuType else {
75 | assertionFailure("在没有设置 SubMenu 的时候, 不应该调到这个方法")
76 | return 0
77 | }
78 | switch submenuType {
79 | case .TableViewSingleView:
80 | return menuManager?.numberOfRowsInSection(section, isMainSubmenu: true) ?? 0
81 | case .TableViewDoubleView:
82 | if let type = DropdownTableViewSubmenuDoubleViewType(rawValue: tableView.tag) {
83 | switch type {
84 | case .Main:
85 | return menuManager?.numberOfRowsInSection(section, isMainSubmenu: true) ?? 0
86 | case .Secondary:
87 | return menuManager?.numberOfRowsInSection(section, isMainSubmenu: false) ?? 0
88 | }
89 | }
90 | assertionFailure("必须要获取到 Type")
91 | return 0
92 | default:
93 | assertionFailure("不应该请求到 CollectionView")
94 | return 0
95 | }
96 | }
97 |
98 | func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
99 | guard let submenuType = submenuType else {
100 | assertionFailure("在没有设置 SubMenu 的时候, 不应该调到这个方法")
101 | return UITableViewCell()
102 | }
103 | switch submenuType {
104 | case .TableViewSingleView:
105 | if let cell = tableView.dequeueReusableCellWithIdentifier(DropdownMenuConfiguration.cellIdentifier) as? DropdownTableViewSubmenuSinlgeViewCell {
106 | cell.titleLabel.text = menuManager?.titleForDropdownSubmenuIndex(DropdownSubmenuIndex(main: indexPath.row, secondary: nil))
107 | return cell
108 | }
109 | case .TableViewDoubleView:
110 | if let type = DropdownTableViewSubmenuDoubleViewType(rawValue: tableView.tag) {
111 | switch type {
112 | case .Main:
113 | if let cell = tableView.dequeueReusableCellWithIdentifier(DropdownMenuConfiguration.cellIdentifier) as? DropdownSubmenuMainViewCell {
114 | cell.titleLabel.text = menuManager?.titleForDropdownSubmenuIndex(DropdownSubmenuIndex(main: indexPath.row, secondary: nil))
115 | return cell
116 | }
117 | case .Secondary:
118 | if let cell = tableView.dequeueReusableCellWithIdentifier(DropdownMenuConfiguration.cellIdentifier) as? DropdownSubmenuSecondaryViewCell {
119 | cell.titleLabel.text = menuManager?.titleForDropdownSubmenuIndex(DropdownSubmenuIndex(main: nil, secondary: indexPath.row))
120 | return cell
121 | }
122 | }
123 | } else {
124 | assertionFailure("必须要获取到 Type")
125 | }
126 | case .CollectionView:
127 | assertionFailure("不应该请求到 CollectionView")
128 | }
129 | assertionFailure("没有获取到正确的 Cell")
130 | return UITableViewCell()
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/TestMenu/DropdownMenu/DropdownMenuViewController+CollectionView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DropdownMenuViewController+CollectionView.swift
3 | // TestMenu
4 | //
5 | // Created by Shannon Wu on 12/20/15.
6 | // Copyright © 2015 Shannon's Dreamland. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | // MARK: DropdownMenu + CollectionViewSectionHeaderDelegate
12 |
13 | extension DropdownMenuViewController: DropdownCollectionViewSectionHeaderDelegate {
14 | func toggleSectionContentHiddenState(state: Bool) {
15 | menuManager?.toggleOpenState(state)
16 | }
17 | }
18 |
19 | // MARK: DropdownMenu + UICollectionViewDelegate
20 |
21 | extension DropdownMenuViewController: UICollectionViewDelegate {
22 | func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
23 | if let indexPaths = collectionView.indexPathsForSelectedItems() {
24 | for oldIndexPath in indexPaths {
25 | if oldIndexPath.section == indexPath.section && oldIndexPath.row != indexPath.row {
26 | collectionView.deselectItemAtIndexPath(oldIndexPath, animated: true)
27 | }
28 | }
29 | }
30 |
31 | if indexPath.section == 0 {
32 | menuManager?.didSelectSubmenuAtIndex(DropdownSubmenuIndex(main: indexPath.row, secondary: nil))
33 | }
34 | else if indexPath.section == 1 {
35 | menuManager?.didSelectSubmenuAtIndex(DropdownSubmenuIndex(main: nil, secondary: indexPath.row))
36 | }
37 | }
38 | }
39 |
40 | // MARK: DropdownMenu + UICollectionViewDataSource
41 |
42 | extension DropdownMenuViewController: UICollectionViewDataSource {
43 | func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
44 | return menuManager?.numberOfSectionsInSubmenu(true) ?? 0
45 | }
46 |
47 | func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
48 | return menuManager?.numberOfRowsInSection(section, isMainSubmenu: true) ?? 0
49 | }
50 |
51 | func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
52 | if let cell = collectionView.dequeueReusableCellWithReuseIdentifier(DropdownMenuConfiguration.cellIdentifier, forIndexPath: indexPath) as? DropdownCollectionViewCell {
53 | if indexPath.section == 0 {
54 | cell.titleLabel.text = menuManager?.titleForDropdownSubmenuIndex(DropdownSubmenuIndex(main: indexPath.row, secondary: nil))
55 | } else {
56 | cell.titleLabel.text = menuManager?.titleForDropdownSubmenuIndex(DropdownSubmenuIndex(main: nil, secondary: indexPath.row))
57 | }
58 | return cell
59 | } else {
60 | assertionFailure("初始化 Collection View Cell 失败")
61 | return UICollectionViewCell()
62 | }
63 | }
64 |
65 | func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView {
66 | if kind == UICollectionElementKindSectionHeader {
67 | if let header = collectionView.dequeueReusableSupplementaryViewOfKind(UICollectionElementKindSectionHeader, withReuseIdentifier: DropdownMenuConfiguration.headerIdentifier, forIndexPath: indexPath) as? DropdownCollectionViewSectionHeader {
68 | header.titleLabel.text = menuManager?.titleForSectionInSubmenu(indexPath.section)
69 |
70 | if indexPath.section == 0 {
71 | collectionViewHeaders = []
72 | }
73 | collectionViewHeaders.append(header)
74 |
75 | return header
76 | }
77 | }
78 | else if kind == UICollectionElementKindSectionFooter {
79 | if indexPath.section == 0 {
80 | if let footer = collectionView.dequeueReusableSupplementaryViewOfKind(UICollectionElementKindSectionFooter, withReuseIdentifier: DropdownMenuConfiguration.decorationFooterIdentifier, forIndexPath: indexPath) as? DropdownCollectionViewSectionDecorationFooter {
81 | return footer
82 | }
83 | }
84 | else if indexPath.section == 1 {
85 | if let footer = collectionView.dequeueReusableSupplementaryViewOfKind(UICollectionElementKindSectionFooter, withReuseIdentifier: DropdownMenuConfiguration.doneFooterIdentifier, forIndexPath: indexPath) as? DropdownCollectionViewSectionDoneFooter {
86 | footer.delegate = self
87 | return footer
88 | }
89 | }
90 | }
91 | assertionFailure("初始化 Collection View Footer 或者 Header 失败")
92 | return UICollectionReusableView()
93 | }
94 |
95 | func collectionView(collectionView: UICollectionView, willDisplaySupplementaryView view: UICollectionReusableView, forElementKind elementKind: String, atIndexPath indexPath: NSIndexPath) {
96 | if elementKind == UICollectionElementKindSectionHeader {
97 | let itemCount = collectionView.numberOfItemsInSection(indexPath.section)
98 | if let shrinkItemCount = menuManager?.shrinkStateItemCount {
99 | toggleExpendButtonState(itemCount < shrinkItemCount ? true : false, atSection: indexPath.section)
100 | }
101 | }
102 | }
103 | }
104 |
105 | // MARK: DropdownMenu + DropdownCollectionViewSectionDoneFooterDelegate
106 |
107 | extension DropdownMenuViewController: DropdownCollectionViewSectionDoneFooterDelegate {
108 | func submenuSelectionFinished() {
109 | animateHideSubmenu()
110 | }
111 | }
112 |
113 | // MARK: DropdownMenu + UICollectionViewDelegateFlowLayout
114 |
115 | extension DropdownMenuViewController: UICollectionViewDelegateFlowLayout {
116 | func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
117 | if section == 0 {
118 | return DropdownMenuConfiguration.collectionViewSubmenuFirstSectionSize
119 | }
120 | else if section == 1 {
121 | return DropdownMenuConfiguration.collectionViewSubmenuSecondSectionSize
122 | }
123 | assertionFailure("不应该请求到这个地方")
124 | return CGSize.zero
125 | }
126 | }
127 |
128 | // MARK: DropdownMenu + Header
129 | extension DropdownMenuViewController {
130 | func toggleExpendButtonState(state: Bool, atSection section: Int) {
131 | guard section < collectionViewHeaders.count || section > 0 else {
132 | assertionFailure("请求不太合法")
133 | return
134 | }
135 |
136 | let header = collectionViewHeaders[section]
137 | header.expandButton.hidden = state
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/TestMenu/DropdownMenu/DropdownMenuViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DiscoveryMenuViewController.swift
3 | // TestMenu
4 | //
5 | // Created by Shannon Wu on 12/18/15.
6 | // Copyright © 2015 Shannon's Dreamland. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | // MARK: - Menu View Controller
12 |
13 | class DropdownMenuViewController: UIViewController {
14 | // MARK: Types
15 |
16 | enum SubmenuType {
17 | case TableViewSingleView
18 | case TableViewDoubleView
19 | case CollectionView
20 | }
21 |
22 | // MARK: Properties
23 |
24 | weak var menuManager: DropdownMenuManager?
25 | var currentlySelectedSubmenu: DropdownSubmenu?
26 | var mainMenu: DropdownMenu!
27 | var backgroundView: UIView?
28 | var collectionViewHeaders = [DropdownCollectionViewSectionHeader]()
29 |
30 | var submenuType: SubmenuType? {
31 | willSet {
32 | if let submenuType = submenuType {
33 | switch submenuType {
34 | case .TableViewSingleView:
35 | tableViewSubmenuSinlgeView.removeFromSuperview()
36 | case .TableViewDoubleView:
37 | tableViewSubmenuDoubleView.removeFromSuperview()
38 | case .CollectionView:
39 | collectionViewSubmenuView.removeFromSuperview()
40 | }
41 | }
42 | }
43 |
44 | didSet {
45 | if let submenuType = submenuType {
46 | switch submenuType {
47 | case .TableViewSingleView:
48 | view.addSubview(tableViewSubmenuSinlgeView)
49 | currentlySelectedSubmenu = tableViewSubmenuSinlgeView
50 | tableViewSubmenuSinlgeView.reload()
51 | case .TableViewDoubleView:
52 | view.addSubview(tableViewSubmenuDoubleView)
53 | currentlySelectedSubmenu = tableViewSubmenuDoubleView
54 | tableViewSubmenuDoubleView.reload()
55 | case .CollectionView:
56 | view.addSubview(collectionViewSubmenuView)
57 | currentlySelectedSubmenu = collectionViewSubmenuView
58 | collectionViewSubmenuView.reload()
59 | }
60 | }
61 | animateShowSubmenu()
62 | }
63 | }
64 |
65 | lazy var tableViewSubmenuSinlgeView: DropdownTableViewSubmenuSinlgeView = {
66 | let submenu = DropdownTableViewSubmenuSinlgeView()
67 | submenu.delegate = self
68 | submenu.dataSource = self
69 | return submenu
70 | }()
71 |
72 | lazy var tableViewSubmenuDoubleView: DropdownTableViewSubmenuDoubleView = {
73 | let submenu = DropdownTableViewSubmenuDoubleView()
74 | submenu.delegate = self
75 | submenu.dataSource = self
76 | return submenu
77 | }()
78 |
79 | lazy var collectionViewSubmenuView: DropdownCollectionViewSubmenu = {
80 | let layout = UICollectionViewFlowLayout()
81 | layout.scrollDirection = .Vertical
82 | layout.minimumLineSpacing = DropdownMenuConfiguration.collectionViewSubmenuMinimumLineSpacing
83 | layout.minimumInteritemSpacing = DropdownMenuConfiguration.collectionViewSubmenuMinimumInteritemSpacing
84 | layout.itemSize = DropdownMenuConfiguration.collectionViewSubmenuItemSize
85 | layout.sectionInset = DropdownMenuConfiguration.collectionViewSubmenuEdgeInsets
86 | layout.headerReferenceSize = DropdownMenuConfiguration.collectionViewSubmenuHeaderReferenceSize
87 | let submenu = DropdownCollectionViewSubmenu(frame: CGRect.zero, collectionViewLayout: layout)
88 | submenu.allowsMultipleSelection = true
89 | submenu.delegate = self
90 | submenu.dataSource = self
91 | return submenu
92 | }()
93 |
94 |
95 | //MARK: View Life Cycle
96 | override func viewDidLoad() {
97 | super.viewDidLoad()
98 |
99 | // Configure background view
100 | backgroundView = UIView()
101 | backgroundView!.translatesAutoresizingMaskIntoConstraints = false
102 | backgroundView!.backgroundColor = DropdownMenuConfiguration.backgroundViewColor
103 | backgroundView!.alpha = DropdownMenuConfiguration.backgroundViewAlpha
104 | view.addSubview(backgroundView!)
105 |
106 | let tapGesture = UITapGestureRecognizer(target: self, action: "animateHideSubmenu")
107 | backgroundView?.addGestureRecognizer(tapGesture)
108 |
109 | backgroundView!.fillSuperView(.Both)
110 |
111 | // Configure menu manager
112 | guard let menuManager = menuManager else { return }
113 | mainMenu = DropdownMenu(items: menuManager.intialTitlesForMainMenu(), delegate: menuManager)
114 | mainMenu.translatesAutoresizingMaskIntoConstraints = false
115 | view.addSubview(mainMenu)
116 |
117 | mainMenu.addDimentionConstraints(.Height, constant: DropdownMenuConfiguration.mainMenuHeight)
118 | mainMenu.pinToSuperView(.Top, inset: 0, relation: .Equal)
119 |
120 | // Configure view
121 | view.frame = DropdownMenuConfiguration.mainMenuFrame
122 | }
123 |
124 | //MARK: Convenience + Menu Frame
125 |
126 | func animateShowSubmenu() {
127 | guard let submenuType = submenuType else {
128 | assertionFailure("在没有设置 Submenu 的时候调用到这里")
129 | return
130 | }
131 |
132 | let submenu: UIView
133 | switch submenuType {
134 | case .TableViewSingleView:
135 | submenu = tableViewSubmenuSinlgeView
136 | case .TableViewDoubleView:
137 | submenu = tableViewSubmenuDoubleView
138 | case .CollectionView:
139 | submenu = collectionViewSubmenuView
140 | }
141 |
142 | if let superView = view.superview {
143 | view.frame.size = CGSize(width: superView.bounds.width, height: superView.bounds.height - DropdownMenuConfiguration.mainMenuTopOffset)
144 | }
145 |
146 | submenu.positionRelativeToView(mainMenu, direction: .Bottom, space: 0.0)
147 | submenu.pinToSuperView(.Bottom, inset: DropdownMenuConfiguration.backgroundViewMinimumHeight, relation: .GreaterThanOrEqual)
148 | }
149 |
150 | func animateHideSubmenu() {
151 | currentlySelectedSubmenu?.removeFromSuperview()
152 | view.frame = DropdownMenuConfiguration.mainMenuFrame
153 |
154 | mainMenu.setTitleForSelectedItem(currentlySelectedSubmenu?.title)
155 | menuManager?.resetSelectionState()
156 | menuManager?.reloadData()
157 | }
158 |
159 | //MARK: Convenience + Menu State
160 |
161 | func reloadSubmenu(includeMainMenu: Bool = false) {
162 | if let submenuType = submenuType {
163 | switch submenuType {
164 | case .TableViewSingleView:
165 | tableViewSubmenuSinlgeView.reload(includeMainMenu)
166 | case .TableViewDoubleView:
167 | tableViewSubmenuDoubleView.reload(includeMainMenu)
168 | case .CollectionView:
169 | collectionViewSubmenuView.reload(includeMainMenu)
170 | }
171 | }
172 | }
173 |
174 | func setTitleForMainMenu(title: String) {
175 | mainMenu.setTitleForSelectedItem(title)
176 | }
177 |
178 | func selectItemAtIndex(index: DropdownSubmenuIndex) {
179 | currentlySelectedSubmenu?.selectItemAtIndex(index)
180 | }
181 |
182 | }
183 |
--------------------------------------------------------------------------------
/TestMenu/DropdownMenu/Views/DropdownSubmenuTableView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DropdownSubmenuTableView.swift
3 | // TestMenu
4 | //
5 | // Created by Shannon Wu on 12/20/15.
6 | // Copyright © 2015 Shannon's Dreamland. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | // MARK: - Base Cell
12 | class DropdownSubmenuBaseCell: UITableViewCell {
13 | // MARK: Properties
14 |
15 | let titleLabel: UILabel = {
16 | let label = UILabel(frame: CGRect.zero)
17 | label.font = DropdownMenuConfiguration.headerFont
18 | label.translatesAutoresizingMaskIntoConstraints = false
19 | return label
20 | }()
21 |
22 | // MARK: Initializers
23 |
24 | override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
25 | super.init(style: style, reuseIdentifier: reuseIdentifier)
26 |
27 | commonInit()
28 | }
29 |
30 | required init?(coder aDecoder: NSCoder) {
31 | fatalError("init(coder:) has not been implemented")
32 | }
33 |
34 | func commonInit() {
35 | selectionStyle = .None
36 | }
37 | }
38 |
39 | // MARK: - Main View Cell
40 |
41 | class DropdownSubmenuMainViewCell: DropdownSubmenuBaseCell {
42 | // MARK: Initializers
43 |
44 | override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
45 | super.init(style: style, reuseIdentifier: reuseIdentifier)
46 |
47 | commonInit()
48 | }
49 |
50 | required init?(coder aDecoder: NSCoder) {
51 | fatalError("init(coder:) has not been implemented")
52 | }
53 |
54 | override func commonInit() {
55 | super.commonInit()
56 |
57 | addSubview(titleLabel)
58 | titleLabel.positionToSuperView(horizontal: .Left, hOffset: DropdownMenuConfiguration.tableViewMainSubMenuLeftOffSet, vertical: .Center, vOffset: 0.0)
59 |
60 | borders = addBorder(edges: [.Right, .Bottom], colour: DropdownMenuConfiguration.separatorColor, thickness: 1.0)
61 | backgroundColor = DropdownMenuConfiguration.mainSubmenuBackgroundColor
62 |
63 | }
64 |
65 | // MARK: Properties
66 | var borders: [UIRectEdge: UIView]?
67 |
68 | // MARK: Conviences
69 |
70 | override func setSelected(selected: Bool, animated: Bool) {
71 | if selected {
72 | if let border = borders?[.Right] {
73 | border.backgroundColor = UIColor.whiteColor()
74 | border.setNeedsDisplay()
75 | }
76 | backgroundColor = UIColor.whiteColor()
77 | titleLabel.textColor = DropdownMenuConfiguration.highlightColor
78 | } else {
79 | if let border = borders?[.Right] {
80 | border.backgroundColor = DropdownMenuConfiguration.separatorColor
81 | border.setNeedsDisplay()
82 | }
83 | backgroundColor = DropdownMenuConfiguration.mainSubmenuBackgroundColor
84 | titleLabel.textColor = DropdownMenuConfiguration.normalColor
85 | }
86 | }
87 |
88 | }
89 |
90 |
91 | // MARK: - Secondary View Cell + Single View Cell
92 |
93 | typealias DropdownTableViewSubmenuSinlgeViewCell = DropdownSubmenuSecondaryViewCell
94 |
95 | class DropdownSubmenuSecondaryViewCell: DropdownSubmenuBaseCell {
96 | // MARK: Initializers
97 |
98 | override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
99 | super.init(style: style, reuseIdentifier: reuseIdentifier)
100 |
101 | commonInit()
102 | }
103 |
104 | required init?(coder aDecoder: NSCoder) {
105 | fatalError("init(coder:) has not been implemented")
106 | }
107 |
108 | override func commonInit() {
109 | super.commonInit()
110 |
111 | addSubview(titleLabel)
112 |
113 | titleLabel.positionToSuperView(horizontal: .Left, hOffset: DropdownMenuConfiguration.tableViewSecondarySubMenuLeftOffSet, vertical: .Center, vOffset: 0.0)
114 |
115 | backgroundColor = UIColor.whiteColor()
116 | }
117 |
118 | // MARK: Properties
119 |
120 | override func setSelected(selected: Bool, animated: Bool) {
121 | if selected {
122 | titleLabel.textColor = DropdownMenuConfiguration.highlightColor
123 | } else {
124 | titleLabel.textColor = DropdownMenuConfiguration.normalColor
125 | }
126 | }
127 | }
128 |
129 | // MARK: - Submenu Base View
130 |
131 | class DropdownTableSubmenuBaseView: UITableView {
132 | // MARK: Initializers
133 |
134 | init() {
135 | super.init(frame: CGRect.zero, style: .Plain)
136 | translatesAutoresizingMaskIntoConstraints = false
137 |
138 | let footer = UIView()
139 | tableFooterView = footer
140 | }
141 |
142 | required init?(coder aDecoder: NSCoder) {
143 | fatalError("init(coder:) has not been implemented")
144 | }
145 | }
146 |
147 | // MARK: - Submenu Main View
148 |
149 | class DropdownTableSubmenuMainView: DropdownTableSubmenuBaseView {
150 | // MARK: Initializers
151 |
152 | override init() {
153 | super.init()
154 |
155 | registerClass(DropdownSubmenuMainViewCell.self, forCellReuseIdentifier: DropdownMenuConfiguration.cellIdentifier)
156 | }
157 |
158 | required init?(coder aDecoder: NSCoder) {
159 | fatalError("init(coder:) has not been implemented")
160 | }
161 | }
162 |
163 | class DropdownTableSubmenuSecondaryView: DropdownTableSubmenuBaseView {
164 | // MARK: Initializers
165 |
166 | override init() {
167 | super.init()
168 |
169 | separatorStyle = .None
170 | registerClass(DropdownSubmenuSecondaryViewCell.self, forCellReuseIdentifier: DropdownMenuConfiguration.cellIdentifier)
171 | }
172 |
173 | required init?(coder aDecoder: NSCoder) {
174 | fatalError("init(coder:) has not been implemented")
175 | }
176 | }
177 |
178 | // MARK: - Submenu Single View + Single View
179 |
180 | typealias DropdownTableViewSubmenuSinlgeView = DropdownTableSubmenuSecondaryView
181 |
182 | // MARK: SubmenuSinlgeView+DropdownSubmenu
183 |
184 | extension DropdownTableViewSubmenuSinlgeView: DropdownSubmenu {
185 | var title: String? {
186 | if let indexPath = indexPathForSelectedRow,
187 | cell = cellForRowAtIndexPath(indexPath) as? DropdownSubmenuBaseCell {
188 | return cell.titleLabel.text
189 | }
190 | return nil
191 | }
192 |
193 | override func intrinsicContentSize() -> CGSize {
194 | return contentSize
195 | }
196 |
197 | func reload(includeMainMenu: Bool = true) {
198 | reloadData()
199 | }
200 |
201 | func selectItemAtIndex(index: DropdownSubmenuIndex) {
202 | if let mainIndex = index.main {
203 | selectRowAtIndexPath(NSIndexPath(forRow: mainIndex, inSection: 0), animated: false, scrollPosition: .Top)
204 | }
205 | }
206 | }
207 |
208 | // MARK: - SubmenuDoubleView
209 |
210 | enum DropdownTableViewSubmenuDoubleViewType: Int {
211 | case Main = 0
212 | case Secondary = 1
213 | }
214 |
215 | class DropdownTableViewSubmenuDoubleView: UIView{
216 | // MARK: Properties
217 |
218 | let mainView: DropdownTableSubmenuMainView = {
219 | let mainView = DropdownTableSubmenuMainView()
220 | return mainView
221 | }()
222 |
223 | let secondaryView: DropdownTableSubmenuSecondaryView = {
224 | let secondaryView = DropdownTableSubmenuSecondaryView()
225 | return secondaryView
226 | }()
227 |
228 | weak var delegate: UITableViewDelegate? {
229 | didSet {
230 | mainView.delegate = delegate
231 | secondaryView.delegate = delegate
232 | }
233 | }
234 |
235 | weak var dataSource: UITableViewDataSource? {
236 | didSet {
237 | mainView.dataSource = dataSource
238 | secondaryView.dataSource = dataSource
239 | }
240 | }
241 |
242 | // MARK: Initializers
243 |
244 | init() {
245 | super.init(frame: CGRect.zero)
246 |
247 | translatesAutoresizingMaskIntoConstraints = false
248 |
249 | commonInit()
250 | }
251 |
252 | required init?(coder aDecoder: NSCoder) {
253 | fatalError("init(coder:) has not been implemented")
254 | }
255 |
256 | func commonInit() {
257 | addSubview(mainView)
258 | addSubview(secondaryView)
259 |
260 | mainView.tag = DropdownTableViewSubmenuDoubleViewType.Main.rawValue
261 | secondaryView.tag = DropdownTableViewSubmenuDoubleViewType.Secondary.rawValue
262 |
263 | mainView.fillSuperView(.Vertical)
264 | secondaryView.fillSuperView(.Vertical)
265 | LayoutKit.arrangeViews(.Horizontal, viewsTuple: [(mainView, 1.0), (secondaryView, 2)])
266 | }
267 | }
268 |
269 | // MARK: DropdownTableViewSubmenuDoubleView + DropdownSubmenu
270 |
271 | extension DropdownTableViewSubmenuDoubleView: DropdownSubmenu {
272 | var title: String? {
273 | if let indexPath = secondaryView.indexPathForSelectedRow,
274 | cell = secondaryView.cellForRowAtIndexPath(indexPath) as? DropdownSubmenuBaseCell {
275 | return cell.titleLabel.text
276 | }
277 | return nil
278 | }
279 |
280 | override func intrinsicContentSize() -> CGSize {
281 | return mainView.contentSize.height > secondaryView.contentSize.height ? mainView.contentSize : secondaryView.contentSize
282 | }
283 |
284 | func selectItemAtIndex(index: DropdownSubmenuIndex) {
285 | if let mainIndex = index.main {
286 | mainView.selectRowAtIndexPath(NSIndexPath(forRow: mainIndex, inSection: 0), animated: false, scrollPosition: .None)
287 | }
288 | if let secondaryIndex = index.secondary {
289 | secondaryView.selectRowAtIndexPath(NSIndexPath(forRow: secondaryIndex, inSection: 0), animated: false, scrollPosition: .None)
290 | }
291 | }
292 |
293 | func reload(includeMainMenu: Bool = false) {
294 | if includeMainMenu {
295 | mainView.reloadData()
296 | }
297 | secondaryView.reloadData()
298 | }
299 | }
300 |
--------------------------------------------------------------------------------
/TestMenu/DropdownMenu/Views/DropdownSubmenuCollectionView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DropdownCollectionView.swift
3 | // TestMenu
4 | //
5 | // Created by Shannon Wu on 12/20/15.
6 | // Copyright © 2015 Shannon's Dreamland. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | // MARK: - Collection View Cell
12 |
13 | class DropdownCollectionViewCell: UICollectionViewCell {
14 | // MARK: Properties
15 |
16 | let titleLabel: UILabel = {
17 | let label = UILabel()
18 | label.textAlignment = .Center
19 | label.font = DropdownMenuConfiguration.collectionViewSubmenuBodyFont
20 | label.textColor = DropdownMenuConfiguration.normalColor
21 | label.translatesAutoresizingMaskIntoConstraints = false
22 | return label
23 | }()
24 |
25 | // MARK: Initializers
26 |
27 | override init(frame: CGRect) {
28 | super.init(frame: frame)
29 |
30 | commonInit()
31 | }
32 |
33 | required init?(coder aDecoder: NSCoder) {
34 | fatalError("init(coder:) has not been implemented")
35 | }
36 |
37 | func commonInit() {
38 | translatesAutoresizingMaskIntoConstraints = false
39 |
40 | addSubview(titleLabel)
41 | titleLabel.fillSuperView(.Both)
42 |
43 | backgroundColor = UIColor.whiteColor()
44 | layer.cornerRadius = 4.0
45 | layer.borderWidth = 1.0
46 | layer.borderColor = DropdownMenuConfiguration.separatorColor.CGColor
47 | }
48 |
49 | // MARK: Properties
50 |
51 | override var selected: Bool {
52 | didSet {
53 | if selected {
54 | layer.borderColor = DropdownMenuConfiguration.highlightColor.CGColor
55 | titleLabel.textColor = DropdownMenuConfiguration.highlightColor
56 | } else {
57 | layer.borderColor = DropdownMenuConfiguration.separatorColor.CGColor
58 | titleLabel.textColor = DropdownMenuConfiguration.normalColor
59 | }
60 | }
61 | }
62 | }
63 |
64 | // MARK: - Section Header
65 |
66 | protocol DropdownCollectionViewSectionHeaderDelegate: class {
67 | func toggleSectionContentHiddenState(state: Bool)
68 | }
69 |
70 | class DropdownCollectionViewSectionHeader: UICollectionReusableView {
71 | // MARK: Properties
72 | private var expandState = false
73 | weak var delegate: DropdownCollectionViewSectionHeaderDelegate?
74 |
75 | let titleLabel: UILabel = {
76 | let label = UILabel()
77 | label.textColor = DropdownMenuConfiguration.normalColor
78 | label.font = DropdownMenuConfiguration.collectionViewSubmenuHeaderFont
79 | label.translatesAutoresizingMaskIntoConstraints = false
80 | return label
81 | }()
82 |
83 | let expandButton: UIButton = {
84 | let button = UIButton(type: .Custom)
85 | button.setImage(DropdownMenuConfiguration.triangleImage, forState: .Normal)
86 | button.translatesAutoresizingMaskIntoConstraints = false
87 | return button
88 | }()
89 |
90 | override var reuseIdentifier: String {
91 | return DropdownMenuConfiguration.headerIdentifier
92 | }
93 |
94 | // MARK: Initializers
95 |
96 | override init(frame: CGRect) {
97 | super.init(frame: frame)
98 |
99 | commonInit()
100 | }
101 |
102 | func commonInit() {
103 | translatesAutoresizingMaskIntoConstraints = false
104 |
105 | expandButton.addTarget(self, action: "toggleExpandState", forControlEvents: .TouchUpInside)
106 |
107 | addSubview(titleLabel)
108 | addSubview(expandButton)
109 |
110 | titleLabel.positionToSuperView(horizontal: .Left, hOffset: 15.0, vertical: .Center, vOffset: 0)
111 | expandButton.positionToSuperView(horizontal: .Right, hOffset: -15.0, vertical: .Center, vOffset: 0)
112 | }
113 |
114 | required init?(coder aDecoder: NSCoder) {
115 | fatalError("init(coder:) has not been implemented")
116 | }
117 |
118 | // MARK: Convenience
119 |
120 | func toggleExpandState() {
121 | expandState = !expandState
122 | if expandState {
123 | expandButton.transform = CGAffineTransformMakeRotation(CGFloat(M_PI))
124 | expandButton.tintColor = DropdownMenuConfiguration.highlightColor
125 | } else {
126 | expandButton.transform = CGAffineTransformMakeRotation(0)
127 | expandButton.tintColor = DropdownMenuConfiguration.normalColor
128 | }
129 | delegate?.toggleSectionContentHiddenState(expandState)
130 | }
131 | }
132 |
133 | // MARK: - Footer
134 |
135 | // MARK: DecorationFooter
136 |
137 | class DropdownCollectionViewSectionDecorationFooter: UICollectionReusableView {
138 | // MARK: Properties
139 |
140 | let decorationView: UIView = {
141 | let view = UIView()
142 | view.backgroundColor = DropdownMenuConfiguration.separatorColor
143 | view.translatesAutoresizingMaskIntoConstraints = false
144 | return view
145 | }()
146 |
147 | override var reuseIdentifier: String {
148 | return DropdownMenuConfiguration.decorationFooterIdentifier
149 | }
150 |
151 | // MARK: Initializers
152 |
153 | override init(frame: CGRect) {
154 | super.init(frame: frame)
155 | commonInit()
156 | }
157 |
158 | required init?(coder aDecoder: NSCoder) {
159 | fatalError("init(coder:) has not been implemented")
160 | }
161 |
162 | func commonInit() {
163 | translatesAutoresizingMaskIntoConstraints = false
164 |
165 | addSubview(decorationView)
166 | decorationView.addDimentionConstraints(.Height, constant: 1.0)
167 | decorationView.positionToSuperView(horizontal: .Left, hOffset: 15.0, vertical: .Bottom, vOffset: -1)
168 | decorationView.positionToSuperView(horizontal: .Right, hOffset: -15.0, vertical: .Bottom, vOffset: -1)
169 | }
170 | }
171 |
172 | // MARK: DoneFooter
173 |
174 | protocol DropdownCollectionViewSectionDoneFooterDelegate: class {
175 | func submenuSelectionFinished()
176 | }
177 |
178 | class DropdownCollectionViewSectionDoneFooter: UICollectionReusableView {
179 | // MARK: Properties
180 |
181 | weak var delegate: DropdownCollectionViewSectionDoneFooterDelegate?
182 |
183 | let doneButton: UIButton = {
184 | let button = UIButton(type: .Custom)
185 | button.setTitle(NSLocalizedString("完成", comment: ""), forState: .Normal)
186 | button.setTitleColor(DropdownMenuConfiguration.highlightColor, forState: .Normal)
187 | button.titleLabel?.font = DropdownMenuConfiguration.collectionViewSubmenuFinishButtonFont
188 |
189 | button.layer.borderColor = DropdownMenuConfiguration.highlightColor.CGColor
190 | button.layer.borderWidth = 1.0
191 | button.layer.cornerRadius = 4.0
192 | button.translatesAutoresizingMaskIntoConstraints = false
193 | return button
194 | }()
195 |
196 | override var reuseIdentifier: String {
197 | return DropdownMenuConfiguration.doneFooterIdentifier
198 | }
199 |
200 | // MARK: Initializers
201 |
202 | override init(frame: CGRect) {
203 | super.init(frame: frame)
204 | commonInit()
205 | }
206 |
207 | required init?(coder aDecoder: NSCoder) {
208 | fatalError("init(coder:) has not been implemented")
209 | }
210 |
211 | func commonInit() {
212 | translatesAutoresizingMaskIntoConstraints = false
213 |
214 | doneButton.addTarget(self, action: "select", forControlEvents: .TouchUpInside)
215 | addSubview(doneButton)
216 |
217 | doneButton.addDimentionConstraints(.Height, constant: 40.0)
218 | doneButton.positionToSuperView(horizontal: .Left, hOffset: 15.0, vertical: .Top, vOffset: 40.0)
219 | doneButton.positionToSuperView(horizontal: .Right, hOffset: -15.0, vertical: .Top, vOffset: 40.0)
220 | }
221 |
222 | // MARK: Convience
223 |
224 | func select() {
225 | delegate?.submenuSelectionFinished()
226 | }
227 | }
228 |
229 | // MARK: - CollectionViewSubmenuSubmenu
230 |
231 | class DropdownCollectionViewSubmenu: UICollectionView {
232 | // MARK: Initializers
233 |
234 | override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
235 | super.init(frame: frame, collectionViewLayout: layout)
236 |
237 | commonInit()
238 | }
239 |
240 | required init?(coder aDecoder: NSCoder) {
241 | fatalError("init(coder:) has not been implemented")
242 | }
243 |
244 | override var contentSize: CGSize {
245 | didSet {
246 | invalidateIntrinsicContentSize()
247 | }
248 | }
249 |
250 | func commonInit() {
251 | translatesAutoresizingMaskIntoConstraints = false
252 |
253 | backgroundColor = UIColor.whiteColor()
254 |
255 | registerClass(DropdownCollectionViewCell.self, forCellWithReuseIdentifier: DropdownMenuConfiguration.cellIdentifier)
256 | registerClass(DropdownCollectionViewSectionHeader.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: DropdownMenuConfiguration.headerIdentifier)
257 | registerClass(DropdownCollectionViewSectionDecorationFooter.self, forSupplementaryViewOfKind: UICollectionElementKindSectionFooter, withReuseIdentifier: DropdownMenuConfiguration.decorationFooterIdentifier)
258 | registerClass(DropdownCollectionViewSectionDoneFooter.self, forSupplementaryViewOfKind: UICollectionElementKindSectionFooter, withReuseIdentifier: DropdownMenuConfiguration.doneFooterIdentifier)
259 | }
260 | }
261 |
262 | // MARK: DropdownSubmenu
263 |
264 | extension DropdownCollectionViewSubmenu: DropdownSubmenu {
265 |
266 | func reload(includeMainMenu: Bool = false) {
267 | reloadData()
268 | }
269 |
270 | var title: String? {
271 | return nil
272 | }
273 |
274 | override func intrinsicContentSize() -> CGSize {
275 | return contentSize
276 | }
277 |
278 | func selectItemAtIndex(index: DropdownSubmenuIndex) {
279 | if let mainIndex = index.main {
280 | selectItemAtIndexPath(NSIndexPath(forRow: mainIndex, inSection: 0), animated: false, scrollPosition: .Top)
281 | }
282 | if let secondaryIndex = index.secondary {
283 | selectItemAtIndexPath(NSIndexPath(forRow: secondaryIndex, inSection: 1), animated: false, scrollPosition: .Top)
284 | }
285 | }
286 | }
--------------------------------------------------------------------------------
/TestMenu/DropdownMenu/Utils/UIView+AutoLayout.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+AutoLayout.swift
3 | // Client
4 | //
5 | // Created by Shannon Wu on 12/22/15.
6 | // Copyright © 2015 36Kr. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | // MARK: - Types
12 |
13 | enum LayoutDirection {
14 | case Horizontal
15 | case Vertical
16 | case Both
17 | }
18 |
19 | extension UIView {
20 | typealias Relation = NSLayoutRelation
21 |
22 | enum Horizontal {
23 | case Left
24 | case Center
25 | case Right
26 |
27 | var attribute: NSLayoutAttribute {
28 | switch self {
29 | case .Left:
30 | return .Left
31 | case .Right:
32 | return .Right
33 | case .Center:
34 | return .CenterX
35 | }
36 | }
37 | }
38 |
39 | enum Vertical {
40 | case Top
41 | case Center
42 | case Bottom
43 |
44 | var attribute: NSLayoutAttribute {
45 | switch self {
46 | case .Top:
47 | return .Top
48 | case .Center:
49 | return .CenterY
50 | case .Bottom:
51 | return .Bottom
52 | }
53 | }
54 | }
55 |
56 | enum Dimension {
57 | case Width
58 | case Height
59 |
60 | var attribute: NSLayoutAttribute {
61 | switch self {
62 | case .Width:
63 | return .Width
64 | case .Height:
65 | return .Height
66 | }
67 | }
68 | }
69 |
70 | enum Direction {
71 | case Leading
72 | case Trailing
73 | case Bottom
74 | case Top
75 | }
76 |
77 | // MARK: - Layout Methods
78 |
79 | func addDimentionConstraints(dimention: Dimension, constant: CGFloat, relation: Relation = .Equal) {
80 | var constraints = [NSLayoutConstraint]()
81 | switch dimention {
82 | case .Width:
83 | constraints.append(NSLayoutConstraint(item: self, attribute: .Width, relatedBy: relation, toItem: nil, attribute: .NotAnAttribute, multiplier: 0.0, constant: constant))
84 | case .Height:
85 | constraints.append(NSLayoutConstraint(item: self, attribute: .Height, relatedBy: relation, toItem: nil, attribute: .NotAnAttribute, multiplier: 0.0, constant: constant))
86 | }
87 | NSLayoutConstraint.activateConstraints(constraints)
88 | }
89 |
90 | func positionToSuperView(horizontal horizontal: Horizontal, hOffset: CGFloat, vertical: Vertical, vOffset: CGFloat) {
91 | guard let superView = self.superview else {
92 | assertionFailure("在调用这个方法前要将它加入到父 View 上面")
93 | return
94 | }
95 |
96 | var constraints = [NSLayoutConstraint]()
97 | constraints.append(NSLayoutConstraint(item: self, attribute: horizontal.attribute, relatedBy: .Equal, toItem: superView, attribute: horizontal.attribute, multiplier: 1.0, constant: hOffset))
98 | constraints.append(NSLayoutConstraint(item: self, attribute: vertical.attribute, relatedBy: .Equal, toItem: superView, attribute: vertical.attribute, multiplier: 1.0, constant: vOffset))
99 | NSLayoutConstraint.activateConstraints(constraints)
100 | }
101 |
102 | func pinToSuperView(direction: Direction, inset: CGFloat, relation: Relation) {
103 | guard self.superview != nil else {
104 | assertionFailure("在调用这个方法前要将它加入到父 View 上面")
105 | return
106 | }
107 |
108 | var constraints = [NSLayoutConstraint]()
109 | let views = ["self": self]
110 | var formats = [String]()
111 |
112 | let relationSubFormat: String
113 | switch relation {
114 | case .GreaterThanOrEqual:
115 | relationSubFormat = ">=\(inset)"
116 | case .Equal:
117 | relationSubFormat = "==\(inset)"
118 | case .LessThanOrEqual:
119 | relationSubFormat = "<=\(inset)"
120 | }
121 |
122 | switch direction {
123 | case .Top:
124 | formats.append("|-(\(relationSubFormat))-[self]|")
125 | formats.append("V:|[self]")
126 | case .Trailing:
127 | formats.append("V:|[self]|")
128 | formats.append("[self]-(\(relationSubFormat))-|")
129 | case .Bottom:
130 | formats.append("V:[self]-(\(relationSubFormat))-|")
131 | formats.append("|[self]|")
132 | case .Leading:
133 | formats.append("V:|[self]|")
134 | formats.append("|-(\(relationSubFormat))-[self]")
135 | }
136 |
137 | formats.forEach { format in
138 | constraints += NSLayoutConstraint.constraintsWithVisualFormat(format, options: [], metrics: nil, views: views)
139 | }
140 | NSLayoutConstraint.activateConstraints(constraints)
141 | }
142 |
143 | func positionRelativeToView(view: UIView, direction: Direction, space: CGFloat) {
144 | guard view.superview == self.superview else {
145 | assertionFailure("在调用这个方法前要将它它们加入到同一个 View 的下面")
146 | return
147 | }
148 |
149 | var constraints = [NSLayoutConstraint]()
150 |
151 | let selfSideAttribute: NSLayoutAttribute
152 | let viewSideAttribute: NSLayoutAttribute
153 | let centerAttribute: NSLayoutAttribute
154 | switch direction {
155 | case .Top:
156 | selfSideAttribute = .Bottom
157 | viewSideAttribute = .Top
158 | centerAttribute = .CenterX
159 | case .Trailing:
160 | selfSideAttribute = .Leading
161 | viewSideAttribute = .Trailing
162 | centerAttribute = .CenterY
163 | case .Bottom:
164 | selfSideAttribute = .Top
165 | viewSideAttribute = .Bottom
166 | centerAttribute = .CenterX
167 | case .Leading:
168 | selfSideAttribute = .Trailing
169 | viewSideAttribute = .Leading
170 | centerAttribute = .CenterY
171 | }
172 |
173 | constraints.append(NSLayoutConstraint(item: self, attribute: selfSideAttribute, relatedBy: .Equal, toItem: view, attribute: viewSideAttribute, multiplier: 1.0, constant: space))
174 | constraints.append(NSLayoutConstraint(item: self, attribute: centerAttribute, relatedBy: .Equal, toItem: view, attribute: centerAttribute, multiplier: 1.0, constant: 0))
175 | NSLayoutConstraint.activateConstraints(constraints)
176 | }
177 |
178 | func fillSuperView(direction: LayoutDirection, edgeInsets: UIEdgeInsets = UIEdgeInsetsZero) {
179 | guard self.superview != nil else {
180 | assertionFailure("在调用这个方法前要将它加入到父 View 上面")
181 | return
182 | }
183 |
184 | let view = ["self": self]
185 | var constraints = [NSLayoutConstraint]()
186 |
187 | let hConstraints = NSLayoutConstraint.constraintsWithVisualFormat("|-\(edgeInsets.left)-[self]-\(edgeInsets.right)-|", options: [], metrics: nil, views: view)
188 | let vConstraints = NSLayoutConstraint.constraintsWithVisualFormat("V:|-\(edgeInsets.top)-[self]-\(edgeInsets.bottom)-|", options: [], metrics: nil, views: view)
189 |
190 | switch direction {
191 | case .Horizontal:
192 | constraints += hConstraints
193 | case .Vertical:
194 | constraints += vConstraints
195 | case .Both:
196 | constraints += hConstraints
197 | constraints += vConstraints
198 | }
199 | NSLayoutConstraint.activateConstraints(constraints)
200 | }
201 | }
202 |
203 | typealias ViewTuple = (view: UIView, multiplierRelativeToFirstView: CGFloat)
204 | struct LayoutKit {
205 |
206 | static func arrangeViews(direction: LayoutDirection, viewsTuple: [ViewTuple]) {
207 |
208 | var viewsDict = [String: AnyObject]()
209 | guard let viewFlag = viewsTuple.first?.view.superview else {
210 | assertionFailure("在调用这个方法前要将它加入到父 View 上面")
211 | return
212 | }
213 | for (index, viewTuple) in viewsTuple.enumerate() {
214 | viewsDict["Item\(index)"] = viewTuple.view
215 | if viewFlag != viewTuple.view.superview {
216 | assertionFailure("这个方法的所有视图必须放在同一个父视图中")
217 | return
218 | }
219 | }
220 |
221 | var constraints = [NSLayoutConstraint]()
222 | switch direction {
223 | case .Horizontal:
224 | for (index, viewTuple) in viewsTuple.enumerate() {
225 | let format: String
226 | if index == 0 {
227 | format = "|[Item\(index)]"
228 | }
229 | else if index == viewsTuple.count - 1 {
230 | format = "[Item\(index-1)][Item\(index)]|"
231 | }
232 | else {
233 | format = "[Item\(index-1)][Item\(index)]"
234 | }
235 | constraints += NSLayoutConstraint.constraintsWithVisualFormat(format, options: [], metrics: nil, views: viewsDict)
236 | constraints += NSLayoutConstraint.constraintsWithVisualFormat("V:|[Item\(index)]|", options: [], metrics: nil, views: viewsDict)
237 | constraints.append(NSLayoutConstraint(item: viewsDict["Item\(index)"]!, attribute: .Width, relatedBy: .Equal, toItem: viewsDict["Item0"], attribute: .Width, multiplier: viewTuple.multiplierRelativeToFirstView, constant: 0))
238 | }
239 | case .Vertical:
240 | for (index, viewTuple) in viewsTuple.enumerate() {
241 | let format: String
242 | if index == 0 {
243 | format = "V:|[Item\(index)]"
244 | }
245 | else if index == viewsTuple.count - 1 {
246 | format = "V:[Item\(index-1)][Item\(index)]|"
247 | }
248 | else {
249 | format = "V:[Item\(index-1)][Item\(index)]"
250 | }
251 | constraints += NSLayoutConstraint.constraintsWithVisualFormat(format, options: [], metrics: nil, views: viewsDict)
252 | constraints += NSLayoutConstraint.constraintsWithVisualFormat("|[Item\(index)]|", options: [], metrics: nil, views: viewsDict)
253 | constraints.append(NSLayoutConstraint(item: viewsDict["Item\(index)"]!, attribute: .Height, relatedBy: .Equal, toItem: viewsDict["Item0"], attribute: .Height, multiplier: viewTuple.multiplierRelativeToFirstView, constant: 0))
254 | }
255 | case .Both: ()
256 | }
257 | NSLayoutConstraint.activateConstraints(constraints)
258 | }
259 | }
--------------------------------------------------------------------------------
/TestMenu.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 610C3B8D1C252B9E007DB909 /* DemoDropdownMenuManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 610C3B8C1C252B9E007DB909 /* DemoDropdownMenuManager.swift */; };
11 | 614DAC8A1C2AFEAF0063CAD4 /* DropdownMenu+Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = 614DAC7E1C2AFEAF0063CAD4 /* DropdownMenu+Types.swift */; };
12 | 614DAC8B1C2AFEAF0063CAD4 /* DropdownMenu.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 614DAC7F1C2AFEAF0063CAD4 /* DropdownMenu.xcassets */; };
13 | 614DAC8C1C2AFEAF0063CAD4 /* DropdownMenuConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 614DAC801C2AFEAF0063CAD4 /* DropdownMenuConfiguration.swift */; };
14 | 614DAC8D1C2AFEAF0063CAD4 /* DropdownMenuViewController+CollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 614DAC811C2AFEAF0063CAD4 /* DropdownMenuViewController+CollectionView.swift */; };
15 | 614DAC8E1C2AFEAF0063CAD4 /* DropdownMenuViewController+TableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 614DAC821C2AFEAF0063CAD4 /* DropdownMenuViewController+TableView.swift */; };
16 | 614DAC8F1C2AFEAF0063CAD4 /* DropdownMenuViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 614DAC831C2AFEAF0063CAD4 /* DropdownMenuViewController.swift */; };
17 | 614DAC901C2AFEAF0063CAD4 /* UIView+AutoLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 614DAC841C2AFEAF0063CAD4 /* UIView+AutoLayout.swift */; };
18 | 614DAC911C2AFEAF0063CAD4 /* DorpdownMainMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 614DAC861C2AFEAF0063CAD4 /* DorpdownMainMenu.swift */; };
19 | 614DAC921C2AFEAF0063CAD4 /* DropdownSubmenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 614DAC871C2AFEAF0063CAD4 /* DropdownSubmenu.swift */; };
20 | 614DAC931C2AFEAF0063CAD4 /* DropdownSubmenuCollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 614DAC881C2AFEAF0063CAD4 /* DropdownSubmenuCollectionView.swift */; };
21 | 614DAC941C2AFEAF0063CAD4 /* DropdownSubmenuTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 614DAC891C2AFEAF0063CAD4 /* DropdownSubmenuTableView.swift */; };
22 | 614DAC981C2B01050063CAD4 /* FontManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 614DAC971C2B01050063CAD4 /* FontManager.swift */; };
23 | 614DAC9A1C2B01290063CAD4 /* ColorManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 614DAC991C2B01290063CAD4 /* ColorManager.swift */; };
24 | 614DAC9C1C2B01550063CAD4 /* AppColor+Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 614DAC9B1C2B01550063CAD4 /* AppColor+Utils.swift */; };
25 | 614DAC9E1C2B017D0063CAD4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 614DAC9D1C2B017D0063CAD4 /* Assets.xcassets */; };
26 | 6162CD241C2407F90094A00B /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6162CD231C2407F90094A00B /* AppDelegate.swift */; };
27 | 6162CD261C2407F90094A00B /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6162CD251C2407F90094A00B /* ViewController.swift */; };
28 | 6162CD291C2407F90094A00B /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6162CD271C2407F90094A00B /* Main.storyboard */; };
29 | 6162CD2E1C2407F90094A00B /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6162CD2C1C2407F90094A00B /* LaunchScreen.storyboard */; };
30 | 6162CD391C2407F90094A00B /* TestMenuTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6162CD381C2407F90094A00B /* TestMenuTests.swift */; };
31 | 619A2A371C2B875900011B6E /* UIView+Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 619A2A361C2B875900011B6E /* UIView+Utils.swift */; };
32 | /* End PBXBuildFile section */
33 |
34 | /* Begin PBXContainerItemProxy section */
35 | 6162CD351C2407F90094A00B /* PBXContainerItemProxy */ = {
36 | isa = PBXContainerItemProxy;
37 | containerPortal = 6162CD181C2407F90094A00B /* Project object */;
38 | proxyType = 1;
39 | remoteGlobalIDString = 6162CD1F1C2407F90094A00B;
40 | remoteInfo = TestMenu;
41 | };
42 | /* End PBXContainerItemProxy section */
43 |
44 | /* Begin PBXFileReference section */
45 | 610C3B8C1C252B9E007DB909 /* DemoDropdownMenuManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DemoDropdownMenuManager.swift; path = TestMenu/DemoDropdownMenuManager.swift; sourceTree = ""; };
46 | 614DAC7E1C2AFEAF0063CAD4 /* DropdownMenu+Types.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DropdownMenu+Types.swift"; sourceTree = ""; };
47 | 614DAC7F1C2AFEAF0063CAD4 /* DropdownMenu.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = DropdownMenu.xcassets; sourceTree = ""; };
48 | 614DAC801C2AFEAF0063CAD4 /* DropdownMenuConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DropdownMenuConfiguration.swift; sourceTree = ""; };
49 | 614DAC811C2AFEAF0063CAD4 /* DropdownMenuViewController+CollectionView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DropdownMenuViewController+CollectionView.swift"; sourceTree = ""; };
50 | 614DAC821C2AFEAF0063CAD4 /* DropdownMenuViewController+TableView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DropdownMenuViewController+TableView.swift"; sourceTree = ""; };
51 | 614DAC831C2AFEAF0063CAD4 /* DropdownMenuViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DropdownMenuViewController.swift; sourceTree = ""; };
52 | 614DAC841C2AFEAF0063CAD4 /* UIView+AutoLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+AutoLayout.swift"; sourceTree = ""; };
53 | 614DAC861C2AFEAF0063CAD4 /* DorpdownMainMenu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DorpdownMainMenu.swift; sourceTree = ""; };
54 | 614DAC871C2AFEAF0063CAD4 /* DropdownSubmenu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DropdownSubmenu.swift; sourceTree = ""; };
55 | 614DAC881C2AFEAF0063CAD4 /* DropdownSubmenuCollectionView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DropdownSubmenuCollectionView.swift; sourceTree = ""; };
56 | 614DAC891C2AFEAF0063CAD4 /* DropdownSubmenuTableView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DropdownSubmenuTableView.swift; sourceTree = ""; };
57 | 614DAC971C2B01050063CAD4 /* FontManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FontManager.swift; sourceTree = ""; };
58 | 614DAC991C2B01290063CAD4 /* ColorManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColorManager.swift; sourceTree = ""; };
59 | 614DAC9B1C2B01550063CAD4 /* AppColor+Utils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AppColor+Utils.swift"; sourceTree = ""; };
60 | 614DAC9D1C2B017D0063CAD4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
61 | 6162CD201C2407F90094A00B /* TestMenu.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TestMenu.app; sourceTree = BUILT_PRODUCTS_DIR; };
62 | 6162CD231C2407F90094A00B /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
63 | 6162CD251C2407F90094A00B /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ViewController.swift; path = TestMenu/ViewController.swift; sourceTree = ""; };
64 | 6162CD281C2407F90094A00B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
65 | 6162CD2D1C2407F90094A00B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
66 | 6162CD2F1C2407F90094A00B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
67 | 6162CD341C2407F90094A00B /* TestMenuTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TestMenuTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
68 | 6162CD381C2407F90094A00B /* TestMenuTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestMenuTests.swift; sourceTree = ""; };
69 | 6162CD3A1C2407F90094A00B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
70 | 619A2A361C2B875900011B6E /* UIView+Utils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Utils.swift"; sourceTree = ""; };
71 | /* End PBXFileReference section */
72 |
73 | /* Begin PBXFrameworksBuildPhase section */
74 | 6162CD1D1C2407F90094A00B /* Frameworks */ = {
75 | isa = PBXFrameworksBuildPhase;
76 | buildActionMask = 2147483647;
77 | files = (
78 | );
79 | runOnlyForDeploymentPostprocessing = 0;
80 | };
81 | 6162CD311C2407F90094A00B /* Frameworks */ = {
82 | isa = PBXFrameworksBuildPhase;
83 | buildActionMask = 2147483647;
84 | files = (
85 | );
86 | runOnlyForDeploymentPostprocessing = 0;
87 | };
88 | /* End PBXFrameworksBuildPhase section */
89 |
90 | /* Begin PBXGroup section */
91 | 614DAC7C1C2AFBFC0063CAD4 /* Supporting Files */ = {
92 | isa = PBXGroup;
93 | children = (
94 | 6162CD231C2407F90094A00B /* AppDelegate.swift */,
95 | 614DAC9D1C2B017D0063CAD4 /* Assets.xcassets */,
96 | 6162CD2F1C2407F90094A00B /* Info.plist */,
97 | 6162CD2C1C2407F90094A00B /* LaunchScreen.storyboard */,
98 | 6162CD271C2407F90094A00B /* Main.storyboard */,
99 | );
100 | path = "Supporting Files";
101 | sourceTree = "";
102 | };
103 | 614DAC7D1C2AFEAF0063CAD4 /* DropdownMenu */ = {
104 | isa = PBXGroup;
105 | children = (
106 | 614DAC7E1C2AFEAF0063CAD4 /* DropdownMenu+Types.swift */,
107 | 614DAC801C2AFEAF0063CAD4 /* DropdownMenuConfiguration.swift */,
108 | 614DAC831C2AFEAF0063CAD4 /* DropdownMenuViewController.swift */,
109 | 614DAC821C2AFEAF0063CAD4 /* DropdownMenuViewController+TableView.swift */,
110 | 614DAC811C2AFEAF0063CAD4 /* DropdownMenuViewController+CollectionView.swift */,
111 | 614DAC961C2B00780063CAD4 /* Utils */,
112 | 614DAC851C2AFEAF0063CAD4 /* Views */,
113 | 614DAC951C2B006E0063CAD4 /* Resource */,
114 | );
115 | path = DropdownMenu;
116 | sourceTree = "";
117 | };
118 | 614DAC851C2AFEAF0063CAD4 /* Views */ = {
119 | isa = PBXGroup;
120 | children = (
121 | 614DAC861C2AFEAF0063CAD4 /* DorpdownMainMenu.swift */,
122 | 614DAC871C2AFEAF0063CAD4 /* DropdownSubmenu.swift */,
123 | 614DAC891C2AFEAF0063CAD4 /* DropdownSubmenuTableView.swift */,
124 | 614DAC881C2AFEAF0063CAD4 /* DropdownSubmenuCollectionView.swift */,
125 | );
126 | path = Views;
127 | sourceTree = "";
128 | };
129 | 614DAC951C2B006E0063CAD4 /* Resource */ = {
130 | isa = PBXGroup;
131 | children = (
132 | 614DAC7F1C2AFEAF0063CAD4 /* DropdownMenu.xcassets */,
133 | );
134 | path = Resource;
135 | sourceTree = "";
136 | };
137 | 614DAC961C2B00780063CAD4 /* Utils */ = {
138 | isa = PBXGroup;
139 | children = (
140 | 619A2A361C2B875900011B6E /* UIView+Utils.swift */,
141 | 614DAC991C2B01290063CAD4 /* ColorManager.swift */,
142 | 614DAC971C2B01050063CAD4 /* FontManager.swift */,
143 | 614DAC9B1C2B01550063CAD4 /* AppColor+Utils.swift */,
144 | 614DAC841C2AFEAF0063CAD4 /* UIView+AutoLayout.swift */,
145 | );
146 | path = Utils;
147 | sourceTree = "";
148 | };
149 | 6162CD171C2407F90094A00B = {
150 | isa = PBXGroup;
151 | children = (
152 | 610C3B8C1C252B9E007DB909 /* DemoDropdownMenuManager.swift */,
153 | 6162CD251C2407F90094A00B /* ViewController.swift */,
154 | 6162CD221C2407F90094A00B /* TestMenu */,
155 | 6162CD211C2407F90094A00B /* Products */,
156 | 6162CD371C2407F90094A00B /* TestMenuTests */,
157 | );
158 | sourceTree = "";
159 | };
160 | 6162CD211C2407F90094A00B /* Products */ = {
161 | isa = PBXGroup;
162 | children = (
163 | 6162CD201C2407F90094A00B /* TestMenu.app */,
164 | 6162CD341C2407F90094A00B /* TestMenuTests.xctest */,
165 | );
166 | name = Products;
167 | sourceTree = "";
168 | };
169 | 6162CD221C2407F90094A00B /* TestMenu */ = {
170 | isa = PBXGroup;
171 | children = (
172 | 614DAC7D1C2AFEAF0063CAD4 /* DropdownMenu */,
173 | 614DAC7C1C2AFBFC0063CAD4 /* Supporting Files */,
174 | );
175 | path = TestMenu;
176 | sourceTree = "";
177 | };
178 | 6162CD371C2407F90094A00B /* TestMenuTests */ = {
179 | isa = PBXGroup;
180 | children = (
181 | 6162CD3A1C2407F90094A00B /* Info.plist */,
182 | 6162CD381C2407F90094A00B /* TestMenuTests.swift */,
183 | );
184 | path = TestMenuTests;
185 | sourceTree = "";
186 | };
187 | /* End PBXGroup section */
188 |
189 | /* Begin PBXNativeTarget section */
190 | 6162CD1F1C2407F90094A00B /* TestMenu */ = {
191 | isa = PBXNativeTarget;
192 | buildConfigurationList = 6162CD3D1C2407F90094A00B /* Build configuration list for PBXNativeTarget "TestMenu" */;
193 | buildPhases = (
194 | 6162CD1C1C2407F90094A00B /* Sources */,
195 | 6162CD1D1C2407F90094A00B /* Frameworks */,
196 | 6162CD1E1C2407F90094A00B /* Resources */,
197 | );
198 | buildRules = (
199 | );
200 | dependencies = (
201 | );
202 | name = TestMenu;
203 | productName = TestMenu;
204 | productReference = 6162CD201C2407F90094A00B /* TestMenu.app */;
205 | productType = "com.apple.product-type.application";
206 | };
207 | 6162CD331C2407F90094A00B /* TestMenuTests */ = {
208 | isa = PBXNativeTarget;
209 | buildConfigurationList = 6162CD401C2407F90094A00B /* Build configuration list for PBXNativeTarget "TestMenuTests" */;
210 | buildPhases = (
211 | 6162CD301C2407F90094A00B /* Sources */,
212 | 6162CD311C2407F90094A00B /* Frameworks */,
213 | 6162CD321C2407F90094A00B /* Resources */,
214 | );
215 | buildRules = (
216 | );
217 | dependencies = (
218 | 6162CD361C2407F90094A00B /* PBXTargetDependency */,
219 | );
220 | name = TestMenuTests;
221 | productName = TestMenuTests;
222 | productReference = 6162CD341C2407F90094A00B /* TestMenuTests.xctest */;
223 | productType = "com.apple.product-type.bundle.unit-test";
224 | };
225 | /* End PBXNativeTarget section */
226 |
227 | /* Begin PBXProject section */
228 | 6162CD181C2407F90094A00B /* Project object */ = {
229 | isa = PBXProject;
230 | attributes = {
231 | LastSwiftUpdateCheck = 0720;
232 | LastUpgradeCheck = 0720;
233 | ORGANIZATIONNAME = "Shannon's Dreamland";
234 | TargetAttributes = {
235 | 6162CD1F1C2407F90094A00B = {
236 | CreatedOnToolsVersion = 7.2;
237 | };
238 | 6162CD331C2407F90094A00B = {
239 | CreatedOnToolsVersion = 7.2;
240 | TestTargetID = 6162CD1F1C2407F90094A00B;
241 | };
242 | };
243 | };
244 | buildConfigurationList = 6162CD1B1C2407F90094A00B /* Build configuration list for PBXProject "TestMenu" */;
245 | compatibilityVersion = "Xcode 3.2";
246 | developmentRegion = English;
247 | hasScannedForEncodings = 0;
248 | knownRegions = (
249 | en,
250 | Base,
251 | );
252 | mainGroup = 6162CD171C2407F90094A00B;
253 | productRefGroup = 6162CD211C2407F90094A00B /* Products */;
254 | projectDirPath = "";
255 | projectRoot = "";
256 | targets = (
257 | 6162CD1F1C2407F90094A00B /* TestMenu */,
258 | 6162CD331C2407F90094A00B /* TestMenuTests */,
259 | );
260 | };
261 | /* End PBXProject section */
262 |
263 | /* Begin PBXResourcesBuildPhase section */
264 | 6162CD1E1C2407F90094A00B /* Resources */ = {
265 | isa = PBXResourcesBuildPhase;
266 | buildActionMask = 2147483647;
267 | files = (
268 | 6162CD2E1C2407F90094A00B /* LaunchScreen.storyboard in Resources */,
269 | 6162CD291C2407F90094A00B /* Main.storyboard in Resources */,
270 | 614DAC9E1C2B017D0063CAD4 /* Assets.xcassets in Resources */,
271 | 614DAC8B1C2AFEAF0063CAD4 /* DropdownMenu.xcassets in Resources */,
272 | );
273 | runOnlyForDeploymentPostprocessing = 0;
274 | };
275 | 6162CD321C2407F90094A00B /* Resources */ = {
276 | isa = PBXResourcesBuildPhase;
277 | buildActionMask = 2147483647;
278 | files = (
279 | );
280 | runOnlyForDeploymentPostprocessing = 0;
281 | };
282 | /* End PBXResourcesBuildPhase section */
283 |
284 | /* Begin PBXSourcesBuildPhase section */
285 | 6162CD1C1C2407F90094A00B /* Sources */ = {
286 | isa = PBXSourcesBuildPhase;
287 | buildActionMask = 2147483647;
288 | files = (
289 | 614DAC8F1C2AFEAF0063CAD4 /* DropdownMenuViewController.swift in Sources */,
290 | 614DAC931C2AFEAF0063CAD4 /* DropdownSubmenuCollectionView.swift in Sources */,
291 | 614DAC981C2B01050063CAD4 /* FontManager.swift in Sources */,
292 | 614DAC941C2AFEAF0063CAD4 /* DropdownSubmenuTableView.swift in Sources */,
293 | 614DAC901C2AFEAF0063CAD4 /* UIView+AutoLayout.swift in Sources */,
294 | 614DAC921C2AFEAF0063CAD4 /* DropdownSubmenu.swift in Sources */,
295 | 614DAC9A1C2B01290063CAD4 /* ColorManager.swift in Sources */,
296 | 6162CD261C2407F90094A00B /* ViewController.swift in Sources */,
297 | 614DAC8E1C2AFEAF0063CAD4 /* DropdownMenuViewController+TableView.swift in Sources */,
298 | 614DAC8A1C2AFEAF0063CAD4 /* DropdownMenu+Types.swift in Sources */,
299 | 614DAC8C1C2AFEAF0063CAD4 /* DropdownMenuConfiguration.swift in Sources */,
300 | 614DAC9C1C2B01550063CAD4 /* AppColor+Utils.swift in Sources */,
301 | 614DAC8D1C2AFEAF0063CAD4 /* DropdownMenuViewController+CollectionView.swift in Sources */,
302 | 619A2A371C2B875900011B6E /* UIView+Utils.swift in Sources */,
303 | 6162CD241C2407F90094A00B /* AppDelegate.swift in Sources */,
304 | 614DAC911C2AFEAF0063CAD4 /* DorpdownMainMenu.swift in Sources */,
305 | 610C3B8D1C252B9E007DB909 /* DemoDropdownMenuManager.swift in Sources */,
306 | );
307 | runOnlyForDeploymentPostprocessing = 0;
308 | };
309 | 6162CD301C2407F90094A00B /* Sources */ = {
310 | isa = PBXSourcesBuildPhase;
311 | buildActionMask = 2147483647;
312 | files = (
313 | 6162CD391C2407F90094A00B /* TestMenuTests.swift in Sources */,
314 | );
315 | runOnlyForDeploymentPostprocessing = 0;
316 | };
317 | /* End PBXSourcesBuildPhase section */
318 |
319 | /* Begin PBXTargetDependency section */
320 | 6162CD361C2407F90094A00B /* PBXTargetDependency */ = {
321 | isa = PBXTargetDependency;
322 | target = 6162CD1F1C2407F90094A00B /* TestMenu */;
323 | targetProxy = 6162CD351C2407F90094A00B /* PBXContainerItemProxy */;
324 | };
325 | /* End PBXTargetDependency section */
326 |
327 | /* Begin PBXVariantGroup section */
328 | 6162CD271C2407F90094A00B /* Main.storyboard */ = {
329 | isa = PBXVariantGroup;
330 | children = (
331 | 6162CD281C2407F90094A00B /* Base */,
332 | );
333 | name = Main.storyboard;
334 | path = .;
335 | sourceTree = "";
336 | };
337 | 6162CD2C1C2407F90094A00B /* LaunchScreen.storyboard */ = {
338 | isa = PBXVariantGroup;
339 | children = (
340 | 6162CD2D1C2407F90094A00B /* Base */,
341 | );
342 | name = LaunchScreen.storyboard;
343 | path = .;
344 | sourceTree = "";
345 | };
346 | /* End PBXVariantGroup section */
347 |
348 | /* Begin XCBuildConfiguration section */
349 | 6162CD3B1C2407F90094A00B /* Debug */ = {
350 | isa = XCBuildConfiguration;
351 | buildSettings = {
352 | ALWAYS_SEARCH_USER_PATHS = NO;
353 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
354 | CLANG_CXX_LIBRARY = "libc++";
355 | CLANG_ENABLE_MODULES = YES;
356 | CLANG_ENABLE_OBJC_ARC = YES;
357 | CLANG_WARN_BOOL_CONVERSION = YES;
358 | CLANG_WARN_CONSTANT_CONVERSION = YES;
359 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
360 | CLANG_WARN_EMPTY_BODY = YES;
361 | CLANG_WARN_ENUM_CONVERSION = YES;
362 | CLANG_WARN_INT_CONVERSION = YES;
363 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
364 | CLANG_WARN_UNREACHABLE_CODE = YES;
365 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
366 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
367 | COPY_PHASE_STRIP = NO;
368 | DEBUG_INFORMATION_FORMAT = dwarf;
369 | ENABLE_STRICT_OBJC_MSGSEND = YES;
370 | ENABLE_TESTABILITY = YES;
371 | GCC_C_LANGUAGE_STANDARD = gnu99;
372 | GCC_DYNAMIC_NO_PIC = NO;
373 | GCC_NO_COMMON_BLOCKS = YES;
374 | GCC_OPTIMIZATION_LEVEL = 0;
375 | GCC_PREPROCESSOR_DEFINITIONS = (
376 | "DEBUG=1",
377 | "$(inherited)",
378 | );
379 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
380 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
381 | GCC_WARN_UNDECLARED_SELECTOR = YES;
382 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
383 | GCC_WARN_UNUSED_FUNCTION = YES;
384 | GCC_WARN_UNUSED_VARIABLE = YES;
385 | IPHONEOS_DEPLOYMENT_TARGET = 9.2;
386 | MTL_ENABLE_DEBUG_INFO = YES;
387 | ONLY_ACTIVE_ARCH = YES;
388 | SDKROOT = iphoneos;
389 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
390 | TARGETED_DEVICE_FAMILY = "1,2";
391 | };
392 | name = Debug;
393 | };
394 | 6162CD3C1C2407F90094A00B /* Release */ = {
395 | isa = XCBuildConfiguration;
396 | buildSettings = {
397 | ALWAYS_SEARCH_USER_PATHS = NO;
398 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
399 | CLANG_CXX_LIBRARY = "libc++";
400 | CLANG_ENABLE_MODULES = YES;
401 | CLANG_ENABLE_OBJC_ARC = YES;
402 | CLANG_WARN_BOOL_CONVERSION = YES;
403 | CLANG_WARN_CONSTANT_CONVERSION = YES;
404 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
405 | CLANG_WARN_EMPTY_BODY = YES;
406 | CLANG_WARN_ENUM_CONVERSION = YES;
407 | CLANG_WARN_INT_CONVERSION = YES;
408 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
409 | CLANG_WARN_UNREACHABLE_CODE = YES;
410 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
411 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
412 | COPY_PHASE_STRIP = NO;
413 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
414 | ENABLE_NS_ASSERTIONS = NO;
415 | ENABLE_STRICT_OBJC_MSGSEND = YES;
416 | GCC_C_LANGUAGE_STANDARD = gnu99;
417 | GCC_NO_COMMON_BLOCKS = YES;
418 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
419 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
420 | GCC_WARN_UNDECLARED_SELECTOR = YES;
421 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
422 | GCC_WARN_UNUSED_FUNCTION = YES;
423 | GCC_WARN_UNUSED_VARIABLE = YES;
424 | IPHONEOS_DEPLOYMENT_TARGET = 9.2;
425 | MTL_ENABLE_DEBUG_INFO = NO;
426 | SDKROOT = iphoneos;
427 | TARGETED_DEVICE_FAMILY = "1,2";
428 | VALIDATE_PRODUCT = YES;
429 | };
430 | name = Release;
431 | };
432 | 6162CD3E1C2407F90094A00B /* Debug */ = {
433 | isa = XCBuildConfiguration;
434 | buildSettings = {
435 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
436 | INFOPLIST_FILE = "TestMenu/Supporting Files/Info.plist";
437 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
438 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
439 | PRODUCT_BUNDLE_IDENTIFIER = com.redesignapp.ios.demo.TestMenu;
440 | PRODUCT_NAME = "$(TARGET_NAME)";
441 | };
442 | name = Debug;
443 | };
444 | 6162CD3F1C2407F90094A00B /* Release */ = {
445 | isa = XCBuildConfiguration;
446 | buildSettings = {
447 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
448 | INFOPLIST_FILE = "TestMenu/Supporting Files/Info.plist";
449 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
450 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
451 | PRODUCT_BUNDLE_IDENTIFIER = com.redesignapp.ios.demo.TestMenu;
452 | PRODUCT_NAME = "$(TARGET_NAME)";
453 | };
454 | name = Release;
455 | };
456 | 6162CD411C2407F90094A00B /* Debug */ = {
457 | isa = XCBuildConfiguration;
458 | buildSettings = {
459 | BUNDLE_LOADER = "$(TEST_HOST)";
460 | INFOPLIST_FILE = TestMenuTests/Info.plist;
461 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
462 | PRODUCT_BUNDLE_IDENTIFIER = com.redesignapp.ios.demo.TestMenuTests;
463 | PRODUCT_NAME = "$(TARGET_NAME)";
464 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TestMenu.app/TestMenu";
465 | };
466 | name = Debug;
467 | };
468 | 6162CD421C2407F90094A00B /* Release */ = {
469 | isa = XCBuildConfiguration;
470 | buildSettings = {
471 | BUNDLE_LOADER = "$(TEST_HOST)";
472 | INFOPLIST_FILE = TestMenuTests/Info.plist;
473 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
474 | PRODUCT_BUNDLE_IDENTIFIER = com.redesignapp.ios.demo.TestMenuTests;
475 | PRODUCT_NAME = "$(TARGET_NAME)";
476 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TestMenu.app/TestMenu";
477 | };
478 | name = Release;
479 | };
480 | /* End XCBuildConfiguration section */
481 |
482 | /* Begin XCConfigurationList section */
483 | 6162CD1B1C2407F90094A00B /* Build configuration list for PBXProject "TestMenu" */ = {
484 | isa = XCConfigurationList;
485 | buildConfigurations = (
486 | 6162CD3B1C2407F90094A00B /* Debug */,
487 | 6162CD3C1C2407F90094A00B /* Release */,
488 | );
489 | defaultConfigurationIsVisible = 0;
490 | defaultConfigurationName = Release;
491 | };
492 | 6162CD3D1C2407F90094A00B /* Build configuration list for PBXNativeTarget "TestMenu" */ = {
493 | isa = XCConfigurationList;
494 | buildConfigurations = (
495 | 6162CD3E1C2407F90094A00B /* Debug */,
496 | 6162CD3F1C2407F90094A00B /* Release */,
497 | );
498 | defaultConfigurationIsVisible = 0;
499 | defaultConfigurationName = Release;
500 | };
501 | 6162CD401C2407F90094A00B /* Build configuration list for PBXNativeTarget "TestMenuTests" */ = {
502 | isa = XCConfigurationList;
503 | buildConfigurations = (
504 | 6162CD411C2407F90094A00B /* Debug */,
505 | 6162CD421C2407F90094A00B /* Release */,
506 | );
507 | defaultConfigurationIsVisible = 0;
508 | defaultConfigurationName = Release;
509 | };
510 | /* End XCConfigurationList section */
511 | };
512 | rootObject = 6162CD181C2407F90094A00B /* Project object */;
513 | }
514 |
--------------------------------------------------------------------------------