├── .DS_Store ├── Demo ├── .DS_Store ├── MultilevelMenuOC │ ├── .DS_Store │ ├── MultilevelMenuOC │ │ ├── Assets.xcassets │ │ │ ├── Contents.json │ │ │ └── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ ├── .DS_Store │ │ ├── ViewController.h │ │ ├── AppDelegate.h │ │ ├── main.m │ │ ├── Info.plist │ │ ├── Base.lproj │ │ │ ├── LaunchScreen.storyboard │ │ │ └── Main.storyboard │ │ ├── AppDelegate.m │ │ └── ViewController.m │ ├── MultilevelMenuOC.xcodeproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ └── IDEWorkspaceChecks.plist │ │ └── project.pbxproj │ ├── MultilevelMenuOCTests │ │ ├── Info.plist │ │ └── MultilevelMenuOCTests.m │ └── MultilevelMenuOCUITests │ │ ├── Info.plist │ │ └── MultilevelMenuOCUITests.m └── MultilevelMenuSwift │ ├── .DS_Store │ ├── Assets.xcassets │ ├── Contents.json │ └── AppIcon.appiconset │ │ └── Contents.json │ ├── CustomMenu │ ├── China.png │ ├── CustomCell.swift │ ├── CustomMenuView.swift │ └── CustomCell.xib │ ├── MultilevelMenu.xcodeproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── project.pbxproj │ ├── Info.plist │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── AppDelegate.swift │ ├── ViewController.swift │ └── businessType.json ├── Screenshots ├── MultilevelStyle1Menu.gif ├── MultilevelStyle2Menu.gif ├── MultilevelStyle1Menu_True.gif ├── MultilevelStyle2Menu_True.gif └── MultilevelStyle2Menu_Custom.gif ├── podfile ├── MultilevelMenu ├── Resources │ └── MultilevelMenuBundle.bundle │ │ ├── Info.plist │ │ ├── btn_common_close_wh.png │ │ ├── btn_common_close_wh@2x.png │ │ └── btn_common_close_wh@3x.png └── Source │ ├── MenuDataModel.swift │ ├── MenuMarco.swift │ ├── MultilevelMenuStyle1View.swift │ ├── MultilevelMenuStyle2View.swift │ ├── MultilevelMenuOption.swift │ ├── MultilevelMenuView.swift │ ├── MultilevelStlyeMenu.swift │ ├── MultilevelStyle1Menu.swift │ └── MultilevelStyle2Menu.swift ├── MultilevelMenu.podspec ├── LICENSE ├── .gitignore └── README.md /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChokShen/MultilevelMenu/HEAD/.DS_Store -------------------------------------------------------------------------------- /Demo/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChokShen/MultilevelMenu/HEAD/Demo/.DS_Store -------------------------------------------------------------------------------- /Demo/MultilevelMenuOC/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChokShen/MultilevelMenu/HEAD/Demo/MultilevelMenuOC/.DS_Store -------------------------------------------------------------------------------- /Demo/MultilevelMenuSwift/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChokShen/MultilevelMenu/HEAD/Demo/MultilevelMenuSwift/.DS_Store -------------------------------------------------------------------------------- /Screenshots/MultilevelStyle1Menu.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChokShen/MultilevelMenu/HEAD/Screenshots/MultilevelStyle1Menu.gif -------------------------------------------------------------------------------- /Screenshots/MultilevelStyle2Menu.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChokShen/MultilevelMenu/HEAD/Screenshots/MultilevelStyle2Menu.gif -------------------------------------------------------------------------------- /Demo/MultilevelMenuSwift/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Screenshots/MultilevelStyle1Menu_True.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChokShen/MultilevelMenu/HEAD/Screenshots/MultilevelStyle1Menu_True.gif -------------------------------------------------------------------------------- /Screenshots/MultilevelStyle2Menu_True.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChokShen/MultilevelMenu/HEAD/Screenshots/MultilevelStyle2Menu_True.gif -------------------------------------------------------------------------------- /Screenshots/MultilevelStyle2Menu_Custom.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChokShen/MultilevelMenu/HEAD/Screenshots/MultilevelStyle2Menu_Custom.gif -------------------------------------------------------------------------------- /Demo/MultilevelMenuOC/MultilevelMenuOC/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Demo/MultilevelMenuSwift/CustomMenu/China.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChokShen/MultilevelMenu/HEAD/Demo/MultilevelMenuSwift/CustomMenu/China.png -------------------------------------------------------------------------------- /Demo/MultilevelMenuOC/MultilevelMenuOC/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChokShen/MultilevelMenu/HEAD/Demo/MultilevelMenuOC/MultilevelMenuOC/.DS_Store -------------------------------------------------------------------------------- /podfile: -------------------------------------------------------------------------------- 1 | source 'https://github.com/CocoaPods/Specs.git' 2 | platform :ios,'8.0' 3 | use_frameworks! 4 | 5 | target 'MultilevelMenu' do 6 | pod 'MultilevelMenu' 7 | end 8 | -------------------------------------------------------------------------------- /MultilevelMenu/Resources/MultilevelMenuBundle.bundle/Info.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChokShen/MultilevelMenu/HEAD/MultilevelMenu/Resources/MultilevelMenuBundle.bundle/Info.plist -------------------------------------------------------------------------------- /MultilevelMenu/Resources/MultilevelMenuBundle.bundle/btn_common_close_wh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChokShen/MultilevelMenu/HEAD/MultilevelMenu/Resources/MultilevelMenuBundle.bundle/btn_common_close_wh.png -------------------------------------------------------------------------------- /MultilevelMenu/Resources/MultilevelMenuBundle.bundle/btn_common_close_wh@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChokShen/MultilevelMenu/HEAD/MultilevelMenu/Resources/MultilevelMenuBundle.bundle/btn_common_close_wh@2x.png -------------------------------------------------------------------------------- /MultilevelMenu/Resources/MultilevelMenuBundle.bundle/btn_common_close_wh@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChokShen/MultilevelMenu/HEAD/MultilevelMenu/Resources/MultilevelMenuBundle.bundle/btn_common_close_wh@3x.png -------------------------------------------------------------------------------- /Demo/MultilevelMenuOC/MultilevelMenuOC.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Demo/MultilevelMenuSwift/MultilevelMenu.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Demo/MultilevelMenuOC/MultilevelMenuOC/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // MultilevelMenuOC 4 | // 5 | // Created by forwor on 2019/8/9. 6 | // Copyright © 2019 forwor. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | @end 13 | 14 | -------------------------------------------------------------------------------- /Demo/MultilevelMenuOC/MultilevelMenuOC.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Demo/MultilevelMenuSwift/MultilevelMenu.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Demo/MultilevelMenuOC/MultilevelMenuOC/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // MultilevelMenuOC 4 | // 5 | // Created by forwor on 2019/8/9. 6 | // Copyright © 2019 forwor. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /Demo/MultilevelMenuOC/MultilevelMenuOC/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // MultilevelMenuOC 4 | // 5 | // Created by forwor on 2019/8/9. 6 | // Copyright © 2019 forwor. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /MultilevelMenu.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "MultilevelMenu" 3 | s.version = "1.3.2" 4 | s.summary = "MultilevelMenu" 5 | s.description = "A custom multi-level menu/ address picker" 6 | s.homepage = "https://github.com/ChokShen/MultilevelMenu" 7 | s.license = { :type => "MIT", :file => "LICENSE" } 8 | s.author = { "shenzhiqiang" => "295297647@qq.com" } 9 | s.ios.deployment_target = '8.0' 10 | s.source = { :git => "https://github.com/ChokShen/MultilevelMenu.git", :tag => "1.3.2" } 11 | s.source_files = "MultilevelMenu/Source/**/*.swift" 12 | s.resources = "MultilevelMenu/Resources/MultilevelMenuBundle.bundle" 13 | s.framework = 'Foundation', 'UIKit' 14 | s.requires_arc = true 15 | s.swift_version = '5.0' 16 | end 17 | -------------------------------------------------------------------------------- /Demo/MultilevelMenuOC/MultilevelMenuOCTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Demo/MultilevelMenuOC/MultilevelMenuOCUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Demo/MultilevelMenuSwift/CustomMenu/CustomCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CustomCell.swift 3 | // MultilevelMenuDemo 4 | // 5 | // Created by shenzhiqiang on 2018/5/7. 6 | // Copyright © 2018年 ChokShen. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class CustomCell: UITableViewCell { 12 | 13 | @IBOutlet weak var contenLabel: UILabel! 14 | @IBOutlet weak var seperator: UILabel! { 15 | didSet { 16 | seperator.backgroundColor = UIColor.white 17 | } 18 | } 19 | 20 | @IBOutlet weak var iconImageView: UIImageView! 21 | override func awakeFromNib() { 22 | super.awakeFromNib() 23 | // Initialization code 24 | } 25 | 26 | override func setSelected(_ selected: Bool, animated: Bool) { 27 | super.setSelected(selected, animated: animated) 28 | 29 | // Configure the view for the selected state 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /MultilevelMenu/Source/MenuDataModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MenuDataModel.swift 3 | // MultilevelMenuDemo 4 | // 5 | // Created by ChokShen on 2018/4/27. 6 | // Copyright © 2018年 shenzhiqiang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | open class MenuDataModel: NSObject { 12 | ///Id of a piece of data in menu,required 13 | @objc open var id: String? 14 | ///Data name,required 15 | @objc open var name: String? 16 | ///Data value,optional 17 | @objc open var value: String? 18 | ///Id of last-level menu,required 19 | @objc open var pid: String? 20 | ///Menu current level,optional 21 | open var level: Int? 22 | 23 | public override init() {} 24 | 25 | @objc public init(dict: [AnyHashable: Any]) { 26 | self.id = dict["id"] as? String 27 | self.name = dict["name"] as? String 28 | self.value = dict["value"] as? String 29 | self.pid = dict["pid"] as? String 30 | self.level = dict["level"] as? Int 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /Demo/MultilevelMenuOC/MultilevelMenuOCTests/MultilevelMenuOCTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // MultilevelMenuOCTests.m 3 | // MultilevelMenuOCTests 4 | // 5 | // Created by forwor on 2019/8/9. 6 | // Copyright © 2019 forwor. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface MultilevelMenuOCTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation MultilevelMenuOCTests 16 | 17 | - (void)setUp { 18 | // Put setup code here. This method is called before the invocation of each test method in the class. 19 | } 20 | 21 | - (void)tearDown { 22 | // Put teardown code here. This method is called after the invocation of each test method in the class. 23 | } 24 | 25 | - (void)testExample { 26 | // This is an example of a functional test case. 27 | // Use XCTAssert and related functions to verify your tests produce the correct results. 28 | } 29 | 30 | - (void)testPerformanceExample { 31 | // This is an example of a performance test case. 32 | [self measureBlock:^{ 33 | // Put the code you want to measure the time of here. 34 | }]; 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 ChokShen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Demo/MultilevelMenuSwift/CustomMenu/CustomMenuView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CustomMenuView.swift 3 | // MultilevelMenuDemo 4 | // 5 | // Created by shenzhiqiang on 2018/5/7. 6 | // Copyright © 2018年 ChokShen. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class CustomMenuView: MultilevelMenuStyle2View { 12 | 13 | // MARK: - UITableViewDelegate 14 | open override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 15 | var cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell") as? CustomCell 16 | if cell == nil { 17 | cell = Bundle.main.loadNibNamed("CustomCell", owner: nil, options: nil)?.first as? CustomCell 18 | } 19 | cell?.contenLabel?.text = dataSouce[indexPath.row].name //Text 20 | //cell?.iconImageView.image = UIImage(named: dataSouce[indexPath.row].value!) //Image 21 | cell?.tintColor = option.checkMarkColor 22 | if indexPath == lastSelectedIndexPath { 23 | cell?.accessoryType = .checkmark 24 | } else { 25 | cell?.accessoryType = .none 26 | } 27 | return cell! 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Demo/MultilevelMenuOC/MultilevelMenuOCUITests/MultilevelMenuOCUITests.m: -------------------------------------------------------------------------------- 1 | // 2 | // MultilevelMenuOCUITests.m 3 | // MultilevelMenuOCUITests 4 | // 5 | // Created by forwor on 2019/8/9. 6 | // Copyright © 2019 forwor. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface MultilevelMenuOCUITests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation MultilevelMenuOCUITests 16 | 17 | - (void)setUp { 18 | // Put setup code here. This method is called before the invocation of each test method in the class. 19 | 20 | // In UI tests it is usually best to stop immediately when a failure occurs. 21 | self.continueAfterFailure = NO; 22 | 23 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 24 | [[[XCUIApplication alloc] init] launch]; 25 | 26 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 27 | } 28 | 29 | - (void)tearDown { 30 | // Put teardown code here. This method is called after the invocation of each test method in the class. 31 | } 32 | 33 | - (void)testExample { 34 | // Use recording to get started writing UI tests. 35 | // Use XCTAssert and related functions to verify your tests produce the correct results. 36 | } 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /MultilevelMenu/Source/MenuMarco.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MultilevelMenuVariable.swift 3 | // MultilevelMenuDemo 4 | // 5 | // Created by ChokShen on 2018/5/10. 6 | // Copyright © 2018年 shenzhiqiang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | struct MMScreen { 13 | ///屏幕宽度 14 | static let width = UIScreen.main.bounds.width 15 | ///屏幕高度 16 | static let height = UIScreen.main.bounds.height 17 | ///状态栏的高度 18 | static let statusBarHeight = UIApplication.shared.statusBarFrame.height 19 | ///导航栏的高度 20 | static let navigationBarHeight: CGFloat = 44 21 | ///状态栏+导航栏的高度 22 | static let navigationHeight = statusBarHeight + navigationBarHeight 23 | ///底部安全距离 24 | static let bottomSafeHeight: CGFloat = isFullScreen ? 34 : 0 25 | ///是否全面屏 26 | static var isFullScreen: Bool { 27 | if #available(iOS 11, *) { 28 | guard let w = UIApplication.shared.delegate?.window, let unwrapedWindow = w else { 29 | return false 30 | } 31 | 32 | if unwrapedWindow.safeAreaInsets.bottom > 0 { 33 | print(unwrapedWindow.safeAreaInsets) 34 | return true 35 | } 36 | } 37 | return false 38 | } 39 | 40 | } 41 | 42 | ///动画完成的代码块 43 | public typealias AnimationCompletionClosure = (Bool) -> Void 44 | ///点击辅助按钮的代码块 45 | public typealias ClickSupplementaryButtonClosure = (Int) -> Void 46 | -------------------------------------------------------------------------------- /Demo/MultilevelMenuSwift/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /Demo/MultilevelMenuOC/MultilevelMenuOC/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | ## Playgrounds 32 | timeline.xctimeline 33 | playground.xcworkspace 34 | 35 | # Swift Package Manager 36 | # 37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 38 | # Packages/ 39 | # Package.pins 40 | .build/ 41 | 42 | # CocoaPods 43 | # 44 | # We recommend against adding the Pods directory to your .gitignore. However 45 | # you should judge for yourself, the pros and cons are mentioned at: 46 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 47 | # 48 | # Pods/ 49 | 50 | # Carthage 51 | # 52 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 53 | # Carthage/Checkouts 54 | 55 | Carthage/Build 56 | 57 | # fastlane 58 | # 59 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 60 | # screenshots whenever they are needed. 61 | # For more information about the recommended setup visit: 62 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 63 | 64 | fastlane/report.xml 65 | fastlane/Preview.html 66 | fastlane/screenshots 67 | fastlane/test_output 68 | -------------------------------------------------------------------------------- /Demo/MultilevelMenuOC/MultilevelMenuOC/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 | -------------------------------------------------------------------------------- /MultilevelMenu/Source/MultilevelMenuStyle1View.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PickerListView.swift 3 | // FWOMSMerchant 4 | // 5 | // Created by ChokShen on 2018/5/10. 6 | // Copyright © 2018年 shenzhiqiang. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public protocol MultilevelMenuStlye1ViewDelegate: class { 12 | func didSelectRow(_ listView: MultilevelMenuStyle1View, _ row: Int, _ dateModel: MenuDataModel) 13 | } 14 | 15 | open class MultilevelMenuStyle1View: MultilevelMenuView { 16 | 17 | weak var delegate: MultilevelMenuStlye1ViewDelegate? 18 | 19 | //MARK: - Animation 20 | override func popFromRightAnimation(_ completion: AnimationCompletionClosure? = nil) { 21 | UIView.animate(withDuration: 0.5, animations: { 22 | self.animationView.frame.origin.x = 0 23 | }) { (finished) in 24 | if finished { 25 | self.animationView.frame.size = CGSize(width: self.initialWidth, height: self.bounds.height) 26 | self.tableView.frame.size = CGSize(width: self.animationView.bounds.width, height: self.tableView.bounds.height) 27 | } 28 | } 29 | } 30 | 31 | override func hideAnimation(_ completion: AnimationCompletionClosure? = nil) { 32 | UIView.animate(withDuration: 0.5, animations: { 33 | self.animationView.frame.origin.x = MMScreen.width 34 | }) { (finished) in 35 | if finished { 36 | self.removeFromSuperview() 37 | if completion != nil { 38 | completion!(finished) 39 | } 40 | } 41 | } 42 | } 43 | 44 | // MARK: - UITableViewDelegate & UITableViewDataSource 45 | open override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 46 | super.tableView(tableView, didSelectRowAt: indexPath) 47 | delegate?.didSelectRow(self, indexPath.row, dataSouce[indexPath.row]) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Demo/MultilevelMenuSwift/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 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Demo/MultilevelMenuSwift/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /Demo/MultilevelMenuOC/MultilevelMenuOC/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /Demo/MultilevelMenuOC/MultilevelMenuOC/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // MultilevelMenuOC 4 | // 5 | // Created by forwor on 2019/8/9. 6 | // Copyright © 2019 forwor. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | 24 | - (void)applicationWillResignActive:(UIApplication *)application { 25 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 27 | } 28 | 29 | 30 | - (void)applicationDidEnterBackground:(UIApplication *)application { 31 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | 36 | - (void)applicationWillEnterForeground:(UIApplication *)application { 37 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 38 | } 39 | 40 | 41 | - (void)applicationDidBecomeActive:(UIApplication *)application { 42 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 43 | } 44 | 45 | 46 | - (void)applicationWillTerminate:(UIApplication *)application { 47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 48 | } 49 | 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /Demo/MultilevelMenuOC/MultilevelMenuOC/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // MultilevelMenuOC 4 | // 5 | // Created by forwor on 2019/8/9. 6 | // Copyright © 2019 forwor. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "MultilevelMenuOC-Swift.h" 11 | 12 | @interface ViewController () 13 | @property (weak, nonatomic) IBOutlet UILabel *resultLabel; 14 | @end 15 | 16 | @implementation ViewController 17 | 18 | - (void)viewDidLoad { 19 | [super viewDidLoad]; 20 | // Do any additional setup after loading the view, typically from a nib. 21 | } 22 | 23 | - (IBAction)testAction:(id)sender { 24 | NSMutableArray *dataSource = [NSMutableArray array]; 25 | NSString *path = [[NSBundle mainBundle] pathForResource:@"businessType" ofType:@"json"]; 26 | NSData *data = [NSData dataWithContentsOfFile:path]; 27 | NSArray *tempArray = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:NULL]; 28 | for (NSDictionary *dic in tempArray) { 29 | //将字典数组转换成模型数组 30 | MenuDataModel *model = [[MenuDataModel alloc] initWithDict:dic]; 31 | //将模型存入到属性中 32 | [dataSource addObject:model]; 33 | } 34 | 35 | __weak typeof(self) weakSelf = self; 36 | MultilevelStyle1Menu *menu = [[MultilevelStyle1Menu alloc]initWithTitle:@"行业类型" dataSouce:dataSource option:nil customView:nil completion:^(NSString * text, MenuDataModel * model) { 37 | weakSelf.resultLabel.text = text; 38 | }]; 39 | [menu show]; 40 | } 41 | 42 | - (IBAction)customMenu:(id)sender { 43 | NSString *path = [[NSBundle mainBundle] pathForResource:@"businessType" ofType:@"json"]; 44 | NSURL *url = [NSURL fileURLWithPath:path]; 45 | MultilevelMenuOption *option = [[MultilevelMenuOption alloc]init]; 46 | option.rightBarButtonTitle = @"ok"; 47 | option.rightBarButtonColor = [UIColor redColor]; 48 | __weak typeof(self) weakSelf = self; 49 | MultilevelStyle2Menu *menu = [[MultilevelStyle2Menu alloc] initWithTitle:@"请选择行业类型" fileUrl:url option:option customView:nil completion:^(NSString * text, MenuDataModel * model) { 50 | weakSelf.resultLabel.text = text; 51 | }]; 52 | [menu show]; 53 | 54 | } 55 | 56 | 57 | @end 58 | -------------------------------------------------------------------------------- /Demo/MultilevelMenuSwift/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // MultilevelMenuDemo 4 | // 5 | // Created by ChokShen on 2018/4/27. 6 | // Copyright © 2018年 ChokShen. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /Demo/MultilevelMenuSwift/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // MultilevelMenuDemo 4 | // 5 | // Created by ChokShen on 2018/4/27. 6 | // Copyright © 2018年 ChokShen. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ViewController: UIViewController { 12 | 13 | private var customView: MultilevelMenuStyle1View! 14 | 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | // // Do any additional setup after loading the view, typically from a nib. 18 | } 19 | 20 | func getClassName(_ view: MultilevelMenuStyle1View) -> String { 21 | return String(describing: type(of: view)) 22 | } 23 | 24 | @IBOutlet weak var resultLabel: UILabel! 25 | @IBAction func testAction(_ sender: Any) { 26 | var dataSouce: [MenuDataModel] = [] 27 | guard let path = Bundle.main.path(forResource:"businessType", ofType: "json") else { return } 28 | let url = URL(fileURLWithPath: path) 29 | do{ 30 | let data = try Data(contentsOf: url) 31 | let json:Any = try JSONSerialization.jsonObject(with: data, options:JSONSerialization.ReadingOptions.mutableContainers) 32 | if let jsonArray = json as? [[String: String]] { 33 | for dict in jsonArray { 34 | let dataModel = MenuDataModel.init(dict: dict) 35 | dataSouce.append(dataModel) 36 | } 37 | } 38 | }catch{ 39 | print("读取本地数据出现错误!",error) 40 | } 41 | let menu = MultilevelStyle1Menu(title: "行业类型", dataSouce: dataSouce, completion: { (resultString, model) in 42 | self.resultLabel.text = resultString 43 | }) 44 | //menu.allowSelectAnyLevelData = true 45 | menu.show() 46 | } 47 | 48 | @IBAction func customMenu(_ sender: Any) { 49 | guard let path = Bundle.main.path(forResource:"businessType", ofType: "json") else { return } 50 | let url = URL(fileURLWithPath: path) 51 | let option = MultilevelMenuOption() 52 | option.rightBarButtonTitle = "ok" 53 | option.rightBarButtonColor = UIColor.red 54 | let menu = MultilevelStyle2Menu(title: "请选择行业类型", fileUrl: url, option: option, customView: CustomMenuView(), completion: { (resultString, model) in 55 | self.resultLabel.text = resultString 56 | }) 57 | menu.show() 58 | } 59 | override func didReceiveMemoryWarning() { 60 | super.didReceiveMemoryWarning() 61 | // Dispose of any resources that can be recreated. 62 | } 63 | 64 | 65 | } 66 | 67 | -------------------------------------------------------------------------------- /MultilevelMenu/Source/MultilevelMenuStyle2View.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MultilevelMenuView.swift 3 | // MultilevelMenuDemo 4 | // 5 | // Created by ChokShen on 2018/4/27. 6 | // Copyright © 2018年 shenzhiqiang. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public protocol MultilevelMenuStlye2ViewDelegate: class { 12 | func didSelectRow(_ menuView: MultilevelMenuStyle2View, _ row: Int, _ dataModel: MenuDataModel) 13 | func didRemoveFromView(_ menuView: MultilevelMenuStyle2View) 14 | } 15 | 16 | open class MultilevelMenuStyle2View: MultilevelMenuView{ 17 | 18 | override var initialWidth: CGFloat { 19 | get { 20 | return MMScreen.width - self.option.secondaryMenuWidth 21 | } 22 | } 23 | weak var delegate: MultilevelMenuStlye2ViewDelegate? 24 | private lazy var backgroundView: UIView = { 25 | let backgroundView = UIView(frame: CGRect(x: 0, y: 0, width: self.option.secondaryMenuWidth, height: self.bounds.height)) 26 | backgroundView.backgroundColor = UIColor.init(white: 1, alpha: 0) 27 | backgroundView.isUserInteractionEnabled = true 28 | backgroundView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.hideAnimation_ClickBackgroundView))) 29 | return backgroundView 30 | }() 31 | 32 | //MARK: - Animation 33 | override func popFromRightAnimation(_ completion: AnimationCompletionClosure? = nil) { 34 | UIView.animate(withDuration: 0.5, animations: { 35 | self.animationView.frame.origin.x = self.option.secondaryMenuWidth 36 | }) { (finished) in 37 | if finished { 38 | self.animationView.frame.size = CGSize(width: self.initialWidth, height: self.bounds.height) 39 | self.tableView.frame.size = CGSize(width: self.animationView.bounds.width, height: self.tableView.bounds.height) 40 | self.addSubview(self.backgroundView) 41 | } 42 | } 43 | } 44 | 45 | @objc func hideAnimation_ClickBackgroundView() { 46 | UIView.animate(withDuration: 0.5, animations: { 47 | self.animationView.frame.origin.x = MMScreen.width 48 | }) { (finished) in 49 | if finished { 50 | self.backgroundView.removeFromSuperview() 51 | self.removeFromSuperview() 52 | self.delegate?.didRemoveFromView(self) 53 | } 54 | } 55 | } 56 | 57 | func hideAnimation_ClickButton(_ completion: AnimationCompletionClosure? = nil) { 58 | UIView.animate(withDuration: 0.5, animations: { 59 | self.animationView.frame.origin.x = MMScreen.width 60 | }) { (finished) in 61 | if finished { 62 | self.backgroundView.removeFromSuperview() 63 | self.removeFromSuperview() 64 | if completion != nil { 65 | completion!(finished) 66 | } 67 | } 68 | } 69 | } 70 | 71 | func fullAnimation() { 72 | UIView.animate(withDuration: 0.5, animations: { 73 | self.animationView.frame.origin.x = 0 74 | }) { (finished) in 75 | if finished { 76 | self.animationView.frame.size = CGSize(width: MMScreen.width, height: self.bounds.height) 77 | self.tableView.frame.size = CGSize(width: self.animationView.bounds.width, height: self.tableView.bounds.height) 78 | } 79 | } 80 | } 81 | 82 | open override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 83 | super.tableView(tableView, didSelectRowAt: indexPath) 84 | delegate?.didSelectRow(self, indexPath.row, dataSouce[indexPath.row]) 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /MultilevelMenu/Source/MultilevelMenuOption.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MultilevelMenuOption.swift 3 | // MultilevelMenuDemo 4 | // 5 | // Created by ChokShen on 2018/4/27. 6 | // Copyright © 2018年 shenzhiqiang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | public class MultilevelMenuOption: NSObject { 13 | 14 | //MARK: - Common Option 15 | ///文本的字体 16 | @objc public var textFont: UIFont = UIFont.systemFont(ofSize: 17) 17 | ///文本的颜色 18 | @objc public var textColor: UIColor = UIColor.black 19 | ///勾选的颜色 20 | @objc public var checkMarkColor: UIColor = UIColor.material_cyan_accent_normal 21 | ///顶部视图左边文字颜色 22 | @objc public var upperBarLeftTextColor: UIColor = UIColor.ColorFromRGB(rgbValue: 0x999999) 23 | ///顶部视图左边文字字体 24 | @objc public var upperBarLeftTextFont: UIFont = UIFont.boldSystemFont(ofSize: 16) 25 | ///顶部视图展示按钮的颜色 26 | @objc public var upperBarButtonColor: UIColor = UIColor.material_cyan_accent_normal 27 | ///顶部视图展示按钮的字体 28 | @objc public var upperBarButtonFont: UIFont = UIFont.boldSystemFont(ofSize: 17) 29 | 30 | //MARK: - Style1Menu Option 31 | @objc public var bottomButtonTitle = "确定" 32 | @objc public var bottomButtonBackgroundColor_Normal: UIColor = UIColor.material_cyan_accent_normal 33 | @objc public var bottomButtonBackgroundColor_Disable: UIColor = UIColor.material_cyan_accent_disabled 34 | @objc public var bottomButtonBackgroundColor_Highlighted: UIColor = UIColor.material_cyan_accent_highlighted 35 | 36 | //MARK: - Style2Menu Option 37 | ///次级菜单(级数大于1的菜单)的宽度 38 | @objc public var secondaryMenuWidth: CGFloat = 80 39 | ///自定义导航栏的背景色 40 | @objc public var navigationBarColor: UIColor = UIColor.navigationBarColor 41 | ///导航标题的颜色 42 | @objc public var navigationTitleColor: UIColor = UIColor.black 43 | ///左侧关闭按钮的颜色 44 | @objc public var closeButtonColor: UIColor = UIColor.black 45 | ///右侧导航按钮的标题 46 | @objc public var rightBarButtonTitle: String = "确定" 47 | ///右侧导航按钮的颜色 48 | @objc public var rightBarButtonColor: UIColor = UIColor.black 49 | ///顶部视图左边默认显示的文字 50 | @objc public var upperBarDefalutLeftText = "请选择" 51 | ///选中菜单的一项后顶部视图左边显示的文字 52 | @objc public var upperBarSelectedLeftText = "已选择" 53 | 54 | public override init() {} 55 | } 56 | 57 | //MARK: - Extension 58 | extension UIImage { 59 | //创建有颜色的image 60 | class func imageWithColor(_ color: UIColor) -> UIImage { 61 | let rect = CGRect(x: 0.0, y: 0.0, width: 18.0, height: 18.0) 62 | UIGraphicsBeginImageContext(rect.size) 63 | let context = UIGraphicsGetCurrentContext() 64 | 65 | context?.setFillColor(color.cgColor) 66 | context?.fill(rect) 67 | 68 | let image = UIGraphicsGetImageFromCurrentImageContext() 69 | UIGraphicsEndImageContext() 70 | 71 | return image! 72 | } 73 | } 74 | 75 | extension UIColor { 76 | //RGB颜色 77 | class func ColorFromRGB(rgbValue: UInt) -> UIColor { 78 | return UIColor(red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0,green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0,blue: CGFloat(rgbValue & 0x0000FF) / 255.0,alpha: CGFloat(1.0) 79 | ) 80 | } 81 | class var material_cyan_accent_disabled : UIColor 82 | { 83 | return self.ColorFromRGB(rgbValue: 0x84FFFF ) 84 | } 85 | 86 | class var material_cyan_accent_normal : UIColor 87 | { 88 | return self.ColorFromRGB(rgbValue: 0x00E5FF ) 89 | } 90 | 91 | class var material_cyan_accent_highlighted : UIColor 92 | { 93 | return self.ColorFromRGB(rgbValue: 0x00B8D4 ) 94 | } 95 | 96 | class var protectedBackgroundColor : UIColor 97 | { 98 | return UIColor.init(white: 0.5, alpha: 0.5) 99 | } 100 | 101 | class var navigationBarColor : UIColor 102 | { 103 | return UIColor.init(red: 247/255, green: 247/255, blue: 247/255, alpha: 1) 104 | } 105 | 106 | class var seperatorLineColor : UIColor { 107 | return self.ColorFromRGB(rgbValue: 0xE1E1E1) 108 | } 109 | } 110 | 111 | extension UIImage { 112 | func imageMaskWithColor(_ maskColor: UIColor) -> UIImage { 113 | var newImage:UIImage? = nil 114 | let imageRect = CGRect(origin: CGPoint(x: 0, y: 0), size: self.size) 115 | UIGraphicsBeginImageContextWithOptions(imageRect.size, false, self.scale) 116 | let context = UIGraphicsGetCurrentContext() 117 | context?.scaleBy(x: 1.0, y: -1.0) 118 | context?.translateBy(x: 0.0, y: -(imageRect.size.height)) 119 | context?.clip(to: imageRect, mask: self.cgImage!);//选中选区 获取不透明区域路径 120 | context?.setFillColor(maskColor.cgColor);//设置颜色 121 | context?.fill(imageRect);//绘制 122 | newImage = UIGraphicsGetImageFromCurrentImageContext();//提取图片 123 | UIGraphicsEndImageContext() 124 | return newImage! 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MultilevelMenu 2 | A custom multi-level menu/ address picker. 3 | *** 4 | ![gif1](https://github.com/ChokShen/MultilevelMenu/raw/master/Screenshots/MultilevelStyle1Menu.gif) 5 | ***MultilevelStyle1Menu*** 6 | 7 | ![gif2](https://github.com/ChokShen/MultilevelMenu/raw/master/Screenshots/MultilevelStyle2Menu.gif) 8 | ***MultilevelStyle2Menu*** 9 | 10 | ## Requirements 11 | * iOS 8+ 12 | * Xcode 11+ 13 | * Swift 5.0+ 14 | 15 | ## Installation 16 | ### 1.CocoaPods 17 | ```swift 18 | pod 'MultilevelMenu' 19 | ``` 20 | ### 2.Manually 21 | Download the project, then drag the files of MultilevelMenu folder to your project. 22 | 23 | ## Basic usage 24 | ### 1.Data structure 25 | ```swift 26 | open class MenuDataModel { 27 | ///Id of a piece of data in menu,required 28 | open var id: String? 29 | ///Data name,required 30 | open var name: String? 31 | ///Data value,optional 32 | open var value: String? 33 | ///Id of last-level menu,required 34 | open var pid: String? 35 | ///Menu current level,optional 36 | open var level: Int? 37 | 38 | public init() {} 39 | 40 | public init(dict: [AnyHashable: Any]) { 41 | self.id = dict["id"] as? String 42 | self.name = dict["name"] as? String 43 | self.value = dict["value"] as? String 44 | self.pid = dict["pid"] as? String 45 | self.level = dict["level"] as? Int 46 | } 47 | } 48 | ``` 49 | ### 2.Init 50 | 51 | Data handle 52 | ```swift 53 | let array: [Dictionary] = [ 54 | ["id":"01","name":"实物产品行业","value":""], 55 | ["id":"02","name":"服务行业","value":""], 56 | ["id":"0101","name":"综合超市/卖场","pid":"01","value":""], 57 | ["id":"0102","name":"穿戴用品","pid":"01","value":""], 58 | ["id":"0103","name":"饮食产品","pid":"01","value":""], 59 | ["id":"0104","name":"房地产","pid":"01","value":""] 60 | ] 61 | 62 | var dataSouce: [MenuDataModel] = [] 63 | for dict in array { 64 | let dataModel = MenuDataModel.init(dict: dict) 65 | dataSouce.append(dataModel) 66 | } 67 | ``` 68 | Show 69 | * Swift 70 | 71 | ```swift 72 | let menu = MultilevelStyle1Menu(title: "行业类型", dataSouce: dataSouce, completion: { (resultString, model) in //'resultString' is combined with every level data that you have selected.'model' is the MenuDataModel that you have selected lastly. 73 | self.resultLabel.text = resultString 74 | }) 75 | menu.show() 76 | ``` 77 | * Objective-C 78 | 79 | ```objective-c 80 | __weak typeof(self) weakSelf = self; 81 | MultilevelStyle1Menu *menu = [[MultilevelStyle1Menu alloc]initWithTitle:@"行业类型" dataSouce:dataSource option:nil customView:nil completion:^(NSString * text, MenuDataModel * model) { 82 | weakSelf.resultLabel.text = text; 83 | }]; 84 | [menu show]; 85 | ``` 86 | 87 | Important Property 88 | ```swfit 89 | menu.allowSelectAnyLevelData = true 90 | // It's false by defalut that it means you must select the last level data, otherwise you can't confirm result.But If it's true, meaning that you can select any level data to confirm result. 91 | ``` 92 | ![gif3](https://github.com/ChokShen/MultilevelMenu/raw/master/Screenshots/MultilevelStyle1Menu_True.gif) 93 | ***MultilevelStyle1Menu*** 94 | 95 | ![gif4](https://github.com/ChokShen/MultilevelMenu/raw/master/Screenshots/MultilevelStyle2Menu_True.gif) 96 | ***MultilevelStyle2Menu*** 97 | 98 | ## Custom Menu 99 | * Custom Cell 100 | Creat your custom cell by xib or code. 101 | * Create a MultilevelMenuStyle1View or MultilevelMenuStyle2View subclass 102 | ```swift 103 | class CustomMenuView: MultilevelMenuStyle2View { 104 | // MARK: - UITableViewDelegate 105 | open override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 106 | var cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell") as? CustomCell 107 | if cell == nil { 108 | cell = Bundle.main.loadNibNamed("CustomCell", owner: nil, options: nil)?.first as? CustomCell 109 | } 110 | cell?.contenLabel?.text = dataSouce[indexPath.row].name //Text 111 | cell?.iconImageView.image = UIImage(named: dataSouce[indexPath.row].value!) //Image 112 | 113 | //Selected properties 114 | cell?.tintColor = option.checkMarkColor 115 | if indexPath == lastSelectedIndexPath { 116 | cell?.accessoryType = .checkmark 117 | } else { 118 | cell?.accessoryType = .none 119 | } 120 | return cell! 121 | } 122 | } 123 | ``` 124 | ![gif5](https://github.com/ChokShen/MultilevelMenu/raw/master/Screenshots/MultilevelStyle2Menu_Custom.gif) 125 | 126 | *Show 127 | * Swift 128 | 129 | ```swift 130 | var option = MultilevelMenuOption() 131 | option.rightBarButtonTitle = "ok" 132 | option.rightBarButtonColor = UIColor.red 133 | 134 | let menu = MultilevelStyle2Menu(title: "请选择行业类型", dataSouce: dataSouce, option: option, customView: CustomMenuView(), completion: { (resultString, model) in 135 | self.resultLabel.text = resultString 136 | }) 137 | menu.show() 138 | ``` 139 | * Objective-C 140 | ```objective-c 141 | MultilevelMenuOption *option = [[MultilevelMenuOption alloc]init]; 142 | option.rightBarButtonTitle = @"ok"; 143 | option.rightBarButtonColor = [UIColor redColor]; 144 | __weak typeof(self) weakSelf = self; 145 | MultilevelStyle2Menu *menu = [[MultilevelStyle2Menu alloc] initWithTitle:@"请选择行业类型" fileUrl:url option:option customView:nil completion:^(NSString * text, MenuDataModel * model) { 146 | weakSelf.resultLabel.text = text; 147 | }]; 148 | [menu show]; 149 | ``` 150 | You also can creat MultilevelMenuOption to set menu custom properties. 151 | 152 | 153 | 154 | 155 | 156 | 157 | -------------------------------------------------------------------------------- /Demo/MultilevelMenuSwift/CustomMenu/CustomCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 27 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /MultilevelMenu/Source/MultilevelMenuView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MultilevelMenuView.swift 3 | // MultilevelMenuDemo 4 | // 5 | // Created by ChokShen on 2018/5/14. 6 | // Copyright © 2018年 shenzhiqiang. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | open class MultilevelMenuView: UIView, UITableViewDelegate, UITableViewDataSource{ 12 | 13 | var isFirst: Bool = false { 14 | didSet { 15 | if isFirst == false { 16 | self.addSubview(animationView) 17 | setUpLayOut() 18 | popFromRightAnimation() 19 | } else { 20 | animationView.frame = self.bounds 21 | self.addSubview(animationView) 22 | setUpLayOut() 23 | } 24 | tableViewConfiguration() 25 | } 26 | } 27 | public var option: MultilevelMenuOption = MultilevelMenuOption() 28 | var initialWidth: CGFloat { 29 | get { 30 | return MMScreen.width 31 | } 32 | } 33 | 34 | public var dataSouce: [MenuDataModel] = [] { 35 | didSet { 36 | tableView.reloadData() 37 | } 38 | } 39 | 40 | lazy var animationView: UIView = { 41 | let animationView = UIView(frame: CGRect(x: MMScreen.width, y: 0, width: self.initialWidth, height: self.bounds.height)) 42 | animationView.backgroundColor = UIColor.white 43 | return animationView 44 | }() 45 | lazy var tableView: UITableView = { 46 | let tempTableView = UITableView(frame: CGRect.zero, style: .plain) 47 | return tempTableView 48 | }() 49 | var textLabel: UILabel! 50 | public var lastSelectedIndexPath: IndexPath? 51 | 52 | // MARK: - init 53 | /// 便利初始化方法 54 | /// 55 | /// - Parameters: 56 | /// - frame: 布局 57 | /// - option: 配置参数 58 | /// - isFirst: 是否第一级列表,默认为false 59 | /// - isSupplementaryButton: 是否需要底部辅助按钮,默认为false 60 | convenience init(frame: CGRect, option: MultilevelMenuOption, isFirst: Bool = false) { 61 | self.init(frame: frame) 62 | self.option = option 63 | if isFirst == false { 64 | self.addSubview(animationView) 65 | setUpLayOut() 66 | popFromRightAnimation() 67 | } else { 68 | animationView.frame = self.bounds 69 | self.addSubview(animationView) 70 | setUpLayOut() 71 | } 72 | tableViewConfiguration() 73 | } 74 | 75 | override public init(frame: CGRect) { 76 | super.init(frame: frame) 77 | self.backgroundColor = UIColor.init(white: 0.5, alpha: 0.5) 78 | } 79 | 80 | public init (_ className: String?) { 81 | self.init() 82 | } 83 | 84 | required public init?(coder aDecoder: NSCoder) { 85 | fatalError("init(coder:) has not been implemented") 86 | } 87 | 88 | // MARK: - ui 89 | func setUpLayOut() { 90 | self.tableView.frame = animationView.bounds 91 | animationView.addSubview(self.tableView) 92 | } 93 | 94 | func tableViewConfiguration() { 95 | tableView.delegate = self 96 | tableView.dataSource = self 97 | tableView.separatorStyle = .none 98 | tableView.backgroundColor = UIColor.white 99 | } 100 | 101 | // MARK: - animation 102 | func popFromRightAnimation(_ completion: AnimationCompletionClosure? = nil) { 103 | } 104 | 105 | func hideAnimation(_ completion: AnimationCompletionClosure? = nil) { 106 | UIView.animate(withDuration: 0.5, animations: { 107 | self.animationView.frame.origin.x = MMScreen.width 108 | }) { (finished) in 109 | if finished { 110 | self.removeFromSuperview() 111 | if completion != nil { 112 | completion!(finished) 113 | } 114 | } 115 | } 116 | } 117 | 118 | // MARK: - UITableViewDelegate & UITableViewDataSource 119 | open func numberOfSections(in tableView: UITableView) -> Int { 120 | return 1 121 | } 122 | 123 | open func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 124 | return dataSouce.count 125 | } 126 | 127 | open func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 128 | var cell = tableView.dequeueReusableCell(withIdentifier: "DisplayedCell") 129 | if cell == nil { 130 | cell = UITableViewCell(style: .default, reuseIdentifier: "DisplayedCell") 131 | } 132 | cell?.textLabel?.text = dataSouce[indexPath.row].name 133 | cell?.textLabel?.textColor = option.textColor 134 | cell?.textLabel?.font = option.textFont 135 | cell?.tintColor = option.checkMarkColor 136 | if indexPath == lastSelectedIndexPath { 137 | cell?.accessoryType = .checkmark 138 | } else { 139 | cell?.accessoryType = .none 140 | } 141 | return cell! 142 | } 143 | 144 | open func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 145 | tableView.deselectRow(at: indexPath, animated: true) 146 | let newIndexPath = indexPath 147 | if newIndexPath != lastSelectedIndexPath { 148 | let newCell = tableView.cellForRow(at: newIndexPath) 149 | newCell?.accessoryType = .checkmark 150 | newCell?.tintColor = option.checkMarkColor 151 | if lastSelectedIndexPath != nil { 152 | let lastSelectedCell = tableView.cellForRow(at: lastSelectedIndexPath!) 153 | lastSelectedCell?.accessoryType = .none 154 | } 155 | lastSelectedIndexPath = newIndexPath 156 | } 157 | } 158 | 159 | open func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 160 | return 44 161 | } 162 | 163 | } 164 | -------------------------------------------------------------------------------- /Demo/MultilevelMenuOC/MultilevelMenuOC/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 | 31 | 37 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /Demo/MultilevelMenuSwift/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 | 31 | 37 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /Demo/MultilevelMenuSwift/businessType.json: -------------------------------------------------------------------------------- 1 | [{"id":"01","name":"实物产品行业","value":""},{"id":"02","name":"服务行业","value":""},{"id":"0101","name":"综合超市/卖场","pid":"01","value":""},{"id":"0102","name":"穿戴用品","pid":"01","value":""},{"id":"0103","name":"饮食产品","pid":"01","value":""},{"id":"0104","name":"房地产","pid":"01","value":""},{"id":"0105","name":"建材/家居/装饰","pid":"01","value":""},{"id":"0106","name":"日化/日杂用品","pid":"01","value":""},{"id":"0107","name":"办公设备/文娱/体育用品","pid":"01","value":""},{"id":"0108","name":"礼品/婚庆用品","pid":"01","value":""},{"id":"0109","name":"电子产品","pid":"01","value":""},{"id":"0110","name":"出行/旅游相关产品","pid":"01","value":""},{"id":"0111","name":"医药/保健器材及用品","pid":"01","value":""},{"id":"0112","name":"机电设备及产品","pid":"01","value":""},{"id":"0113","name":"农业生产设备及用品","pid":"01","value":""},{"id":"0114","name":"花卉/苗木/园林","pid":"01","value":""},{"id":"0201","name":"餐饮","pid":"02","value":""},{"id":"0202","name":"住宿","pid":"02","value":""},{"id":"0203","name":"休闲/养生/娱乐","pid":"02","value":""},{"id":"0204","name":"教育/培训/咨询","pid":"02","value":""},{"id":"0205","name":"医疗","pid":"02","value":""},{"id":"0206","name":"旅游","pid":"02","value":""},{"id":"0207","name":"缴费","pid":"02","value":""},{"id":"0208","name":"租赁","pid":"02","value":""},{"id":"0209","name":"维修","pid":"02","value":""},{"id":"0210","name":"家政/干洗","pid":"02","value":""},{"id":"0211","name":"照相/摄影","pid":"02","value":""},{"id":"0212","name":"广告设计","pid":"02","value":""},{"id":"0213","name":"物流/快递","pid":"02","value":""},{"id":"0214","name":"停车/物业","pid":"02","value":""},{"id":"0215","name":"福利彩票","pid":"02","value":""},{"id":"010101","name":"便利店","pid":"0101","value":"5331"},{"id":"010102","name":"百货超市","pid":"0101","value":"5311"},{"id":"010103","name":"大型超市/卖场","pid":"0101","value":"5399"},{"id":"010201","name":"服装/鞋帽/袜子/配饰","pid":"0102","value":"5699"},{"id":"010202","name":"眼镜","pid":"0102","value":"8043"},{"id":"010203","name":"手表/手环","pid":"0102","value":"5944"},{"id":"010301","name":"烟酒/茶叶","pid":"0103","value":"5411"},{"id":"010302","name":"副食/糖果/饮品/奶制品","pid":"0103","value":"5411"},{"id":"010303","name":"粮油/调料","pid":"0103","value":"5411"},{"id":"010304","name":"生鲜/蔬菜/水果","pid":"0103","value":"5411"},{"id":"010305","name":"特产","pid":"0103","value":"5411"},{"id":"010401","name":"房地产开发销售","pid":"0104","value":"1520"},{"id":"010402","name":"二手房销售","pid":"0104","value":"7013"},{"id":"010501","name":"瓷砖/石材","pid":"0105","value":"5211"},{"id":"010502","name":"油漆/涂料/墙纸","pid":"0105","value":"5231"},{"id":"010503","name":"门框/板材","pid":"0105","value":"5211"},{"id":"010504","name":"钢材/铝材/玻璃","pid":"0105","value":"5211"},{"id":"010505","name":"五金/电线/电缆/安防器材","pid":"0105","value":"5251"},{"id":"010506","name":"家具/厨卫/灯饰","pid":"0105","value":"5712"},{"id":"010507","name":"家纺用品/窗帘布艺","pid":"0105","value":"5714"},{"id":"010508","name":"玉器/画饰/工艺美术品等装饰品","pid":"0105","value":"5970"},{"id":"010601","name":"洗护用品/化妆品","pid":"0106","value":"5977"},{"id":"010602","name":"日杂用品","pid":"0106","value":"5331"},{"id":"010603","name":"箱包/皮具","pid":"0106","value":"5948"},{"id":"010604","name":"布匹/轻纺","pid":"0106","value":"5949"},{"id":"010701","name":"办公家具及其它办公用品","pid":"0107","value":"5021"},{"id":"010702","name":"计算机及外围设备/电脑耗材/网络设备","pid":"0107","value":"5045"},{"id":"010703","name":"文具/书刊杂志","pid":"0107","value":"5942"},{"id":"010704","name":"音像制品","pid":"0107","value":"5735"},{"id":"010705","name":"体育用品/健生器材","pid":"0107","value":"5941"},{"id":"010706","name":"音乐商店—乐器、钢琴、乐谱","pid":"0107","value":"5733"},{"id":"010707","name":"玩具/麻将桌等娱乐器材","pid":"0107","value":"5943"},{"id":"010801","name":"礼品","pid":"0108","value":"5947"},{"id":"010802","name":"鲜花","pid":"0108","value":"5992"},{"id":"010803","name":"婚庆用品","pid":"0108","value":"5947"},{"id":"010901","name":"家电产品及配件","pid":"0109","value":"5722"},{"id":"010902","name":"手机及配件","pid":"0109","value":"5722"},{"id":"010903","name":"数码相机/照相器材","pid":"0109","value":"5044"},{"id":"011001","name":"加油站、收费站","pid":"0110","value":"5542"},{"id":"011002","name":"汽车销售(4S店/汽车商行/二手车行等)","pid":"0110","value":"5521"},{"id":"011003","name":"汽车配件销售/汽车美容装饰","pid":"0110","value":"5592"},{"id":"011004","name":"电动车/摩托车及其它机动车销售/配件销售","pid":"0110","value":"5571"},{"id":"011005","name":"自行车及其它代步工具销售/配件销售","pid":"0110","value":"5940"},{"id":"011006","name":"旅行箱包/帐篷等旅行设备","pid":"0110","value":"5948"},{"id":"011101","name":"药品/保健品","pid":"0111","value":"5912"},{"id":"011102","name":"医疗设备/医疗器材","pid":"0111","value":"5047"},{"id":"011103","name":"残疾人设备","pid":"0111","value":"5047"},{"id":"011201","name":"五金/电线/电缆","pid":"0112","value":"5251"},{"id":"011202","name":"电器设备","pid":"0112","value":"5251"},{"id":"011203","name":"机电设备及配件销售","pid":"0112","value":"5251"},{"id":"011301","name":"种植、养殖、畜牧等农业生产活动","pid":"0113","value":"9708"},{"id":"011302","name":"农药化肥、种子及其它农产品","pid":"0113","value":"9708"},{"id":"011303","name":"农机及配件","pid":"0113","value":"9708"},{"id":"011401","name":"花木栽种用品、苗木和花卉","pid":"0114","value":"5193"},{"id":"011402","name":"石雕/园林装饰产品","pid":"0114","value":"8912"},{"id":"020101","name":"餐馆/农庄","pid":"0201","value":"5812"},{"id":"020102","name":"早餐售卖点/宵夜摊","pid":"0201","value":"5812"},{"id":"020103","name":"茶楼","pid":"0201","value":"5812"},{"id":"020104","name":"蛋糕店/奶茶店","pid":"0201","value":"5812"},{"id":"020201","name":"酒店/宾馆","pid":"0202","value":"7011"},{"id":"020202","name":"度假村","pid":"0202","value":"7011"},{"id":"020301","name":"理发店/发廊","pid":"0203","value":"7230"},{"id":"020302","name":"美容店/美妆","pid":"0203","value":"7230"},{"id":"020303","name":"酒吧/KTV/娱乐会所","pid":"0203","value":"5813"},{"id":"020304","name":"健生/按摩/足浴及其它休闲养生场所","pid":"0203","value":"7298"},{"id":"020305","name":"桌游/桌球","pid":"0203","value":"7932"},{"id":"020306","name":"网吧/电玩","pid":"0203","value":"7994"},{"id":"020307","name":"电影院","pid":"0203","value":"7832"},{"id":"020401","name":"学校/教育机构","pid":"0204","value":"8299"},{"id":"020402","name":"培训机构","pid":"0204","value":"8299"},{"id":"020403","name":"咨询机构","pid":"0204","value":"8299"},{"id":"020501","name":"医院","pid":"0205","value":"8062"},{"id":"020502","name":"诊所","pid":"0205","value":"8099"},{"id":"020601","name":"交通运输售票处","pid":"0206","value":"4111"},{"id":"020602","name":"铁路运输","pid":"0206","value":"4112"},{"id":"020603","name":"旅行社","pid":"0206","value":"4733"},{"id":"020604","name":"景区售票处","pid":"0206","value":"4722"},{"id":"020701","name":"水电、煤气等便民缴费点","pid":"0207","value":"4900"},{"id":"020702","name":"电信缴费点","pid":"0207","value":"4814"},{"id":"020801","name":"房屋中介","pid":"0208","value":"7013"},{"id":"020802","name":"租车公司","pid":"0208","value":"5511"},{"id":"020803","name":"租船公司","pid":"0208","value":"5551"},{"id":"020901","name":"家电维修店","pid":"0209","value":"7629"},{"id":"020902","name":"汽车及其它机动车维修保养站","pid":"0209","value":"7538"},{"id":"020903","name":"摩托车维修站","pid":"0209","value":"5598"},{"id":"020904","name":"自行车维修站","pid":"0209","value":"5940"},{"id":"021001","name":"家政服务公司","pid":"0210","value":"7295"},{"id":"021002","name":"干洗店","pid":"0210","value":"7216"},{"id":"021101","name":"照相馆","pid":"0211","value":"7395"},{"id":"021102","name":"婚纱摄影店","pid":"0211","value":"7333"},{"id":"021103","name":"摄影工作室","pid":"0211","value":"7221"},{"id":"021201","name":"广告设计制","pid":"0212","value":"7311"},{"id":"021202","name":"复印/打印","pid":"0212","value":"7338"},{"id":"021301","name":"物流公司","pid":"0213","value":"4215"},{"id":"021302","name":"快递公司","pid":"0213","value":"4215"},{"id":"021401","name":"停车场","pid":"0214","value":"7523"},{"id":"021402","name":"物业管理","pid":"0214","value":"7013"},{"id":"021501","name":"福利彩票","pid":"0215","value":"7995"},{"id":"021502","name":"体育彩票","pid":"0215","value":"7995"}] -------------------------------------------------------------------------------- /MultilevelMenu/Source/MultilevelStlyeMenu.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MultilevelStlyeMenu.swift 3 | // MultilevelMenuDemo 4 | // 5 | // Created by ChokShen on 2018/5/14. 6 | // Copyright © 2018年 shenzhiqiang. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public typealias SelectResultClosure = (String, MenuDataModel) -> Void 12 | 13 | public class MultilevelStlyeMenu: UIView { 14 | 15 | ///false表示你必须要选择最后一级的数据才可以点确认按钮;true表示你可以选择任意一级的数据,然后确认结果 16 | @objc public var allowSelectAnyLevelData = false 17 | ///当前列表是第几级 18 | var currentLevel: Int = 1 19 | ///当前级别的行是否有下一级别的数据 20 | var hasNextLevel = true 21 | ///是否选中了最后一级列表的行 22 | var isSelectLastLevelRow = false 23 | var titleText: String? 24 | var allDataSource: [MenuDataModel] = [] 25 | var firstMenuDataSource: [MenuDataModel] = [] 26 | var modelSelected = MenuDataModel() 27 | var completion: SelectResultClosure? 28 | var defalutOption: MultilevelMenuOption = MultilevelMenuOption() 29 | var upperBarView: UIView! 30 | var reminderLabel: UILabel! 31 | var scrollView: UIScrollView! 32 | var currentButton: UIButton? 33 | var buttonTotalWidth: CGFloat = 0 34 | 35 | //MARK: - init 36 | override init(frame: CGRect) { 37 | super.init(frame: frame) 38 | layOut() 39 | } 40 | 41 | required public init?(coder aDecoder: NSCoder) { 42 | fatalError("init(coder:) has not been implemented") 43 | } 44 | 45 | //MARK: - Handle Data 46 | func getDataSourceFromJsonFile(_ url: URL) -> [MenuDataModel] { 47 | var dataSouce: [MenuDataModel] = [] 48 | do{ 49 | let data = try Data(contentsOf: url) 50 | let json:Any = try JSONSerialization.jsonObject(with: data, options:JSONSerialization.ReadingOptions.mutableContainers) 51 | if let jsonArray = json as? [[String: String]] { 52 | for dict in jsonArray { 53 | let model = MenuDataModel.init(dict: dict) 54 | dataSouce.append(model) 55 | } 56 | } 57 | }catch let erro as Error?{ 58 | print("读取本地数据出现错误!",erro!) 59 | } 60 | return dataSouce 61 | } 62 | 63 | func setFirstDataSource() { 64 | var tempDataSouce = [MenuDataModel]() 65 | for data in self.allDataSource { 66 | if data.pid == nil || data.pid == "" { 67 | tempDataSouce.append(data) 68 | } 69 | } 70 | self.firstMenuDataSource = tempDataSouce 71 | } 72 | 73 | func getNextLevelDataSouce(_ id: String?) -> [MenuDataModel] { 74 | var tempDataSouce = [MenuDataModel]() 75 | for data in self.allDataSource { 76 | if data.pid == id { 77 | tempDataSouce.append(data) 78 | } 79 | } 80 | return tempDataSouce 81 | } 82 | 83 | //MARK: - Show & Cancel 84 | @objc public func show() { 85 | 86 | } 87 | 88 | @objc func cancelAction() { 89 | 90 | } 91 | 92 | //MARK: - Layout 93 | func layOut() { 94 | 95 | } 96 | 97 | func layOutMenuView() { 98 | 99 | } 100 | 101 | func creatNextLevelMenuView(_ dataSouce: [MenuDataModel]) { 102 | 103 | } 104 | 105 | //MARK: - Scroll Button 106 | func selectResultDisplay(_ name: String?) { 107 | if hasNextLevel { 108 | isSelectLastLevelRow = false 109 | if currentButton == nil { 110 | creatDisplayButton(name) 111 | } else { 112 | if (currentButton?.tag)! - 200 != currentLevel { 113 | creatDisplayButton(name) 114 | } else { 115 | resetDisplayButton(name) 116 | } 117 | } 118 | } else { 119 | if isSelectLastLevelRow == false { 120 | if currentButton == nil { 121 | creatDisplayButton(name) 122 | } else if (currentButton?.tag)! - 200 != currentLevel { 123 | creatDisplayButton(name) 124 | isSelectLastLevelRow = true 125 | } else { 126 | resetDisplayButton(name) 127 | } 128 | } else { 129 | if currentButton == nil { 130 | creatDisplayButton(name) 131 | } else { 132 | resetDisplayButton(name) 133 | } 134 | } 135 | } 136 | } 137 | 138 | func creatDisplayButton(_ name: String?) { 139 | let buttonH = upperBarView.frame.height 140 | var text: String? 141 | if currentLevel == 1 { 142 | text = name 143 | } else { 144 | text = " > \(name ?? "")" 145 | } 146 | let buttonW_Text = text?.boundingRect(with: CGSize(width: CGFloat(MAXFLOAT), height: buttonH), options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 16)], context: nil).width 147 | let buttonW = buttonW_Text ?? 48 148 | let button = UIButton(frame: CGRect(x: buttonTotalWidth, y: 0, width: buttonW , height: buttonH)) 149 | self.buttonTotalWidth += buttonW 150 | button.setTitleColor(defalutOption.upperBarButtonColor, for: .normal) 151 | button.titleLabel?.font = UIFont.systemFont(ofSize: 16) 152 | button.tag = 200 + currentLevel 153 | if currentLevel == 1 { 154 | button.setTitle(name, for: .normal) 155 | } else { 156 | let attributedStr = NSMutableAttributedString.init(string: text ?? " ") 157 | attributedStr.addAttributes([NSAttributedString.Key.foregroundColor: UIColor.darkGray], range: NSRange(location: 2, length: 1)) 158 | button.titleLabel?.textColor = defalutOption.upperBarButtonColor 159 | button.titleLabel?.attributedText = attributedStr 160 | button.setAttributedTitle(attributedStr, for: .normal) 161 | } 162 | button.addTarget(self, action: #selector(clickName(_:)), for: .touchUpInside) 163 | currentButton = button 164 | scrollView.addSubview(button) 165 | if self.buttonTotalWidth > scrollView.frame.width { 166 | scrollView.contentSize = CGSize(width: buttonTotalWidth, height: 0) 167 | scrollView.showsHorizontalScrollIndicator = true 168 | scrollView.flashScrollIndicators() 169 | } 170 | } 171 | 172 | func resetDisplayButton(_ name: String?) { 173 | let buttonH = upperBarView.frame.height 174 | var text: String? 175 | if currentLevel == 1 { 176 | text = name 177 | } else { 178 | text = " > \(name ?? "")" 179 | } 180 | let buttonW_Text = text?.boundingRect(with: CGSize(width: CGFloat(MAXFLOAT), height: buttonH), options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 16)], context: nil).width 181 | let buttonW = buttonW_Text ?? 48 182 | let currentButtonW = currentButton?.bounds.size.width 183 | currentButton?.frame.size = CGSize(width: buttonW, height: buttonH) 184 | if currentLevel == 1 { 185 | currentButton?.setTitle(name, for: .normal) 186 | } else { 187 | let attributedStr = NSMutableAttributedString.init(string: text ?? " ") 188 | attributedStr.addAttributes([NSAttributedString.Key.foregroundColor: UIColor.darkGray], range: NSRange(location: 2, length: 1)) 189 | currentButton?.titleLabel?.textColor = defalutOption.upperBarButtonColor 190 | currentButton?.titleLabel?.attributedText = attributedStr 191 | currentButton?.setAttributedTitle(attributedStr, for: .normal) 192 | } 193 | self.buttonTotalWidth += (buttonW - currentButtonW!) 194 | scrollView.contentSize = CGSize(width: buttonTotalWidth, height: 0) 195 | } 196 | 197 | func removeDisplayButton(_ tag: Int) { 198 | if let button = scrollView.viewWithTag(tag) as? UIButton { 199 | button.removeFromSuperview() 200 | self.buttonTotalWidth -= button.frame.size.width 201 | scrollView.contentSize = CGSize(width: buttonTotalWidth, height: 0) 202 | } 203 | } 204 | 205 | @objc func clickName(_ sender: UIButton) { 206 | 207 | } 208 | 209 | // MARK: - Result Handle 210 | @objc func confirm() { 211 | if completion != nil { 212 | let combinedResultSting = getCombinedResultString() 213 | completion!(combinedResultSting, modelSelected) 214 | } 215 | cancelAction() 216 | } 217 | 218 | func getCombinedResultString() -> String { 219 | var string = "" 220 | for i in 1 ... currentLevel { 221 | if let button = scrollView.viewWithTag(i + 200) as? UIButton { 222 | string += (button.titleLabel?.text)! 223 | } 224 | } 225 | string = string.replacingOccurrences(of: " ", with: "") 226 | string = string.replacingOccurrences(of: ">", with: " ") 227 | return string 228 | } 229 | 230 | } 231 | -------------------------------------------------------------------------------- /MultilevelMenu/Source/MultilevelStyle1Menu.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MultilevelPicker.swift 3 | // FWOMSMerchant 4 | // 5 | // Created by ChokShen on 2018/5/10. 6 | // Copyright © 2018年 shenzhiqiang. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public class MultilevelStyle1Menu: MultilevelStlyeMenu, MultilevelMenuStlye1ViewDelegate { 12 | 13 | override var hasNextLevel: Bool { 14 | didSet { 15 | if allowSelectAnyLevelData == false { 16 | if hasNextLevel == false { 17 | setConfirmBtn(true) 18 | } else { 19 | setConfirmBtn(false) 20 | } 21 | } 22 | } 23 | } 24 | static let upperViewHeight: CGFloat = 44 25 | static let height: CGFloat = MMScreen.isFullScreen ? 352 + MMScreen.bottomSafeHeight : 352 26 | static let confirmButtonHeight: CGFloat = 44 27 | private var tableViewFrame: CGRect { 28 | return CGRect(x: 0, y: MultilevelStyle1Menu.upperViewHeight, width: MMScreen.width, height: MultilevelStyle1Menu.height - MultilevelStyle1Menu.upperViewHeight - MultilevelStyle1Menu.confirmButtonHeight - MMScreen.bottomSafeHeight) 29 | } 30 | private var firstMenuView: MultilevelMenuStyle1View! 31 | private var customMenuView: MultilevelMenuStyle1View? 32 | private var confirmButton: UIButton! 33 | private lazy var containerView: UIView = { 34 | let containerView = UIView() 35 | containerView.frame = CGRect(x: 0, y: 0, width: MMScreen.width, height: MMScreen.height - MultilevelStyle1Menu.height) 36 | containerView.backgroundColor = UIColor.protectedBackgroundColor 37 | containerView.isUserInteractionEnabled = true 38 | containerView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.cancelAction))) 39 | return containerView 40 | }() 41 | 42 | //MARK: - init 43 | @objc public convenience init(title: String?, 44 | fileUrl: URL, 45 | option: MultilevelMenuOption? = nil, 46 | customView: MultilevelMenuStyle1View? = nil, 47 | completion: SelectResultClosure?) { 48 | self.init(frame: CGRect(x: 0, y: MMScreen.height, width: MMScreen.width, height: MultilevelStyle1Menu.height)) 49 | self.allDataSource = getDataSourceFromJsonFile(fileUrl) 50 | self.titleText = title 51 | if option != nil { 52 | self.defalutOption = option! 53 | } else { 54 | self.defalutOption = MultilevelMenuOption() 55 | } 56 | self.completion = completion 57 | self.customMenuView = customView 58 | layOut() 59 | setFirstDataSource() 60 | } 61 | 62 | @objc public convenience init(title: String?, 63 | dataSouce: [MenuDataModel], 64 | option: MultilevelMenuOption? = nil, 65 | customView: MultilevelMenuStyle1View? = nil, 66 | completion: SelectResultClosure?) { 67 | self.init(frame: CGRect(x: 0, y: MMScreen.height, width: MMScreen.width, height: MultilevelStyle1Menu.height)) 68 | self.allDataSource = dataSouce 69 | self.titleText = title 70 | if option != nil { 71 | self.defalutOption = option! 72 | } else { 73 | self.defalutOption = MultilevelMenuOption() 74 | } 75 | self.completion = completion 76 | self.customMenuView = customView 77 | layOut() 78 | setFirstDataSource() 79 | } 80 | 81 | override init(frame: CGRect) { 82 | super.init(frame: frame) 83 | } 84 | 85 | private func initMultilevelMenuView() -> MultilevelMenuStyle1View { 86 | if customMenuView == nil { 87 | return MultilevelMenuStyle1View() 88 | } else { 89 | let className = String(describing: type(of: customMenuView!)) 90 | let projectName = Bundle.main.infoDictionary!["CFBundleExecutable"] as! String 91 | let multilevelMenuView = NSClassFromString(projectName + "." + className) as! MultilevelMenuStyle1View.Type 92 | return multilevelMenuView.init() 93 | } 94 | } 95 | 96 | required public init?(coder aDecoder: NSCoder) { 97 | fatalError("init(coder:) has not been implemented") 98 | } 99 | 100 | //MARK: - Handle Data 101 | override func setFirstDataSource() { 102 | super.setFirstDataSource() 103 | reminderLabel.text = self.titleText 104 | firstMenuView.dataSouce = firstMenuDataSource 105 | } 106 | 107 | //MARK: - Show & Cancel 108 | @objc override public func show() { 109 | if allowSelectAnyLevelData { 110 | setConfirmBtn(true) 111 | } else { 112 | setConfirmBtn(false) 113 | } 114 | // 通过window 弹出view 115 | guard let window = UIApplication.shared.delegate?.window else { return } 116 | guard let currentWindow = window else { return } 117 | UIView.animate(withDuration: 0.3, animations: { 118 | self.frame.origin = CGPoint(x: 0, y: MMScreen.height - MultilevelStyle1Menu.height) 119 | currentWindow.addSubview(self) 120 | }) { (finished) in 121 | if finished { 122 | currentWindow.addSubview(self.containerView) 123 | } 124 | } 125 | } 126 | 127 | @objc override func cancelAction() { 128 | self.containerView.removeFromSuperview() 129 | UIView.animate(withDuration: 0.3, animations: { 130 | self.frame.origin = CGPoint(x: 0, y: MMScreen.height) 131 | }) { (finished) in 132 | if finished { 133 | self.removeFromSuperview() 134 | } 135 | } 136 | } 137 | 138 | //MARK: - Layout 139 | override func layOut() { 140 | self.backgroundColor = UIColor.white 141 | layOutUpperView() 142 | layOutMenuView() 143 | layOutConfirmButton() 144 | } 145 | 146 | override func layOutMenuView() { 147 | firstMenuView = initMultilevelMenuView() 148 | firstMenuView.frame = tableViewFrame 149 | firstMenuView.option = self.defalutOption 150 | firstMenuView.isFirst = true 151 | firstMenuView.delegate = self 152 | firstMenuView.tag = currentLevel 153 | self.addSubview(firstMenuView) 154 | } 155 | 156 | override func creatNextLevelMenuView(_ dataSouce: [MenuDataModel]) { 157 | let nextMenuView = initMultilevelMenuView() 158 | nextMenuView.frame = tableViewFrame 159 | nextMenuView.option = self.defalutOption 160 | nextMenuView.isFirst = false 161 | nextMenuView.delegate = self 162 | nextMenuView.dataSouce = dataSouce 163 | nextMenuView.tag = currentLevel 164 | self.addSubview(nextMenuView) 165 | } 166 | 167 | private func layOutUpperView() { 168 | upperBarView = UIView(frame: CGRect(x: 0, y: 0, width: MMScreen.width, height: MultilevelStyle1Menu.upperViewHeight)) 169 | upperBarView.backgroundColor = UIColor.white 170 | self.addSubview(upperBarView) 171 | 172 | //提示标签 173 | reminderLabel = UILabel(frame: CGRect(x: 15, y: 0, width: 70, height: upperBarView.frame.height - 0.5)) 174 | reminderLabel.font = UIFont.systemFont(ofSize: 16) 175 | reminderLabel.text = self.titleText 176 | reminderLabel.textColor = UIColor.black 177 | upperBarView.addSubview(reminderLabel) 178 | //滚动视图 179 | let scrollViewX = reminderLabel.frame.maxX + 15 180 | scrollView = UIScrollView(frame: CGRect(x: scrollViewX, y: 0, width: MMScreen.width - scrollViewX, height: upperBarView.frame.height - 0.5)) 181 | scrollView.showsHorizontalScrollIndicator = false 182 | scrollView.contentSize = CGSize(width: scrollView.frame.width, height: 0) 183 | upperBarView.addSubview(scrollView) 184 | //分割线 185 | let seperator = UILabel(frame: CGRect(x: 0, y: reminderLabel.frame.maxY, width: upperBarView.frame.width, height: 0.5)) 186 | seperator.backgroundColor = UIColor.seperatorLineColor 187 | upperBarView.addSubview(seperator) 188 | } 189 | 190 | private func layOutConfirmButton() { 191 | confirmButton = UIButton(type: .custom) 192 | confirmButton.frame = CGRect(x: 0, y: tableViewFrame.maxY, width: MMScreen.width, height: MultilevelStyle1Menu.confirmButtonHeight) 193 | confirmButton.setTitle(self.defalutOption.bottomButtonTitle, for: .normal) 194 | confirmButton.titleLabel?.font = UIFont.systemFont(ofSize: 18) 195 | confirmButton.setTitleColor(UIColor.white, for: .normal) 196 | confirmButton.setBackgroundImage(UIImage.imageWithColor(self.defalutOption.bottomButtonBackgroundColor_Disable), for: .normal) 197 | confirmButton.setBackgroundImage(UIImage.imageWithColor(self.defalutOption.bottomButtonBackgroundColor_Highlighted), for: .highlighted) 198 | confirmButton.addTarget(self, action: #selector(confirm), for: .touchUpInside) 199 | self.addSubview(confirmButton) 200 | setConfirmBtn(false) 201 | } 202 | 203 | private func setConfirmBtn(_ enabled: Bool) { 204 | self.confirmButton.isEnabled = enabled 205 | if enabled { 206 | self.confirmButton.setBackgroundImage(UIImage.imageWithColor(self.defalutOption.bottomButtonBackgroundColor_Normal), for: .normal) 207 | } else { 208 | self.confirmButton.setBackgroundImage(UIImage.imageWithColor(self.defalutOption.bottomButtonBackgroundColor_Disable), for: .normal) 209 | } 210 | } 211 | 212 | //MARK: - Animation 213 | private func listViewHideAnimation(_ tag: Int, _ completion: AnimationCompletionClosure? = nil) { 214 | if let listView = self.viewWithTag(tag) as? MultilevelMenuStyle1View { 215 | listView.hideAnimation(completion) 216 | } 217 | } 218 | 219 | private func listViewRemoveFromSuperView(_ tag: Int) { 220 | if let listView = self.viewWithTag(tag) as? MultilevelMenuStyle1View { 221 | listView.removeFromSuperview() 222 | } 223 | } 224 | 225 | //MARK: - Scroll Button 226 | @objc override func clickName(_ sender: UIButton) { 227 | let clickedLevel = sender.tag - 200 228 | if clickedLevel < currentLevel { 229 | listViewHideAnimation(currentLevel, { (completion) in 230 | if completion { 231 | for i in (clickedLevel + 1) ..< self.currentLevel { 232 | self.listViewRemoveFromSuperView(i) 233 | } 234 | let low = clickedLevel + 1 235 | for j in low ... self.currentLevel { 236 | self.removeDisplayButton(j + 200) 237 | } 238 | self.isSelectLastLevelRow = false 239 | self.currentLevel = clickedLevel 240 | self.currentButton = self.scrollView.viewWithTag(self.currentLevel + 200) as? UIButton 241 | } 242 | }) 243 | hasNextLevel = true 244 | } 245 | } 246 | 247 | // MARK: - PickerListViewDelegate 248 | public func didSelectRow(_ listView: MultilevelMenuStyle1View, _ row: Int, _ dateModel: MenuDataModel) { 249 | modelSelected = dateModel 250 | let nextLevelDataSouce = self.getNextLevelDataSouce(dateModel.id) 251 | hasNextLevel = nextLevelDataSouce.isEmpty ? false : true 252 | selectResultDisplay(dateModel.name) 253 | if hasNextLevel { 254 | currentLevel += 1 255 | creatNextLevelMenuView(nextLevelDataSouce) 256 | } 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /MultilevelMenu/Source/MultilevelStyle2Menu.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MultilevelMenuController.swift 3 | // MultilevelMenuDemo 4 | // 5 | // Created by ChokShen on 2018/4/27. 6 | // Copyright © 2018年 shenzhiqiang. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public class MultilevelStyle2Menu: MultilevelStlyeMenu, MultilevelMenuStlye2ViewDelegate{ 12 | 13 | override var hasNextLevel: Bool { 14 | didSet { 15 | if allowSelectAnyLevelData == false { 16 | if hasNextLevel == false { 17 | setConfirmBtn(true) 18 | } else { 19 | setConfirmBtn(false) 20 | } 21 | } 22 | } 23 | } 24 | static let upperViewHeight: CGFloat = 44 25 | private var defalutFrame: CGRect { 26 | return CGRect(x: 0, y: MMScreen.navigationHeight + MultilevelStyle2Menu.upperViewHeight, width: MMScreen.width, height: MMScreen.height - MMScreen.navigationHeight - MultilevelStyle2Menu.upperViewHeight) 27 | } 28 | private var firstMenuView: MultilevelMenuStyle2View! 29 | private var customMenuView: MultilevelMenuStyle2View? 30 | private var navigationBar: UIView! 31 | private var titltLabel: UILabel! 32 | private var confirmButton: UIButton! 33 | private var cancelButton: UIButton! 34 | 35 | //MARK: - init 36 | /// 初始化 37 | /// 38 | /// - Parameters: 39 | /// - title: 标题 40 | /// - fileUrl: 文件的路径 41 | /// - option: 菜单的参数配置 42 | /// - customView: 自定义视图 43 | /// - completion: 选择结果的回调 44 | @objc public convenience init(title: String?, 45 | fileUrl: URL, 46 | option: MultilevelMenuOption? = nil, 47 | customView: MultilevelMenuStyle2View? = nil, 48 | completion: SelectResultClosure?) { 49 | self.init(frame: CGRect(x: 0, y: MMScreen.height, width: MMScreen.width, height: MMScreen.height)) 50 | self.allDataSource = getDataSourceFromJsonFile(fileUrl) 51 | self.titleText = title 52 | if option != nil { 53 | self.defalutOption = option! 54 | } else { 55 | self.defalutOption = MultilevelMenuOption() 56 | } 57 | self.completion = completion 58 | self.customMenuView = customView 59 | layOut() 60 | setFirstDataSource() 61 | } 62 | 63 | /// 初始化 64 | /// 65 | /// - Parameters: 66 | /// - title: 标题 67 | /// - dataSouce: 数据源 68 | /// - option: 菜单的参数配置 69 | /// - customView: 自定义视图 70 | /// - completion: 选择结果的回调 71 | @objc public convenience init(title: String?, 72 | dataSouce: [MenuDataModel], 73 | option: MultilevelMenuOption? = nil, 74 | customView: MultilevelMenuStyle2View? = nil, 75 | completion: SelectResultClosure?) { 76 | self.init(frame: CGRect(x: 0, y: MMScreen.height, width: MMScreen.width, height: MMScreen.height)) 77 | self.allDataSource = dataSouce 78 | self.titleText = title 79 | if option != nil { 80 | self.defalutOption = option! 81 | } else { 82 | self.defalutOption = MultilevelMenuOption() 83 | } 84 | self.completion = completion 85 | self.customMenuView = customView 86 | layOut() 87 | setFirstDataSource() 88 | } 89 | 90 | override init(frame: CGRect) { 91 | super.init(frame: frame) 92 | } 93 | 94 | private func initMultilevelMenuView() -> MultilevelMenuStyle2View { 95 | if customMenuView == nil { 96 | return MultilevelMenuStyle2View() 97 | } else { 98 | let className = String(describing: type(of: customMenuView!)) 99 | let projectName = Bundle.main.infoDictionary!["CFBundleExecutable"] as! String 100 | let multilevelMenuView = NSClassFromString(projectName + "." + className) as! MultilevelMenuStyle2View.Type 101 | return multilevelMenuView.init() 102 | } 103 | } 104 | 105 | required public init?(coder aDecoder: NSCoder) { 106 | fatalError("init(coder:) has not been implemented") 107 | } 108 | 109 | //MARK: - Layout 110 | override func layOut() { 111 | self.backgroundColor = UIColor.white 112 | layOutMenuView() 113 | layOutCustomStatusBar() 114 | layOutCustomNavigationBar() 115 | layOutUpperView() 116 | } 117 | 118 | override func layOutMenuView() { 119 | firstMenuView = initMultilevelMenuView() 120 | firstMenuView.frame = defalutFrame 121 | firstMenuView.option = self.defalutOption 122 | firstMenuView.isFirst = true 123 | firstMenuView.delegate = self 124 | firstMenuView.tag = currentLevel 125 | self.addSubview(firstMenuView) 126 | } 127 | 128 | override func creatNextLevelMenuView(_ dataSouce: [MenuDataModel]) { 129 | let nextMenuView = initMultilevelMenuView() 130 | nextMenuView.frame = defalutFrame 131 | nextMenuView.option = self.defalutOption 132 | nextMenuView.isFirst = false 133 | nextMenuView.delegate = self 134 | nextMenuView.dataSouce = dataSouce 135 | nextMenuView.tag = currentLevel 136 | self.addSubview(nextMenuView) 137 | } 138 | 139 | private func layOutCustomStatusBar() { 140 | //自定义状态栏 141 | let statusBar = UIView(frame: CGRect(x: 0, y: 0, width: MMScreen.width, height: MMScreen.statusBarHeight)) 142 | statusBar.backgroundColor = defalutOption.navigationBarColor 143 | self.addSubview(statusBar) 144 | } 145 | 146 | private func layOutCustomNavigationBar() { 147 | //自定义导航栏 148 | navigationBar = UIView(frame: CGRect(x: 0, y: MMScreen.statusBarHeight, width: MMScreen.width, height: MMScreen.navigationBarHeight)) 149 | navigationBar.backgroundColor = defalutOption.navigationBarColor 150 | self.addSubview(navigationBar) 151 | let leftEdge: CGFloat = 15 152 | //1.确定按钮 153 | confirmButton = UIButton(type: .custom) 154 | confirmButton.frame = CGRect(x: MMScreen.width - leftEdge - 50, y: (navigationBar.frame.height - 30) / 2, width: 50, height: 30) 155 | confirmButton.contentHorizontalAlignment = .right 156 | confirmButton.setTitle(self.defalutOption.rightBarButtonTitle, for: .normal) 157 | confirmButton.titleLabel?.font = UIFont.systemFont(ofSize: 18) 158 | confirmButton.setTitleColor(self.defalutOption.rightBarButtonColor, for: .normal) 159 | confirmButton.addTarget(self, action: #selector(confirm), for: .touchUpInside) 160 | setConfirmBtn(true) 161 | navigationBar.addSubview(confirmButton) 162 | //2.取消按钮 163 | cancelButton = UIButton(type: .custom) 164 | cancelButton.frame = CGRect(x: leftEdge, y: (navigationBar.frame.height - 18) / 2, width: 18, height: 18) 165 | let bundle = Bundle(for: MultilevelStlyeMenu.self) 166 | let closeImage = UIImage(named: "MultilevelMenuBundle.bundle/btn_common_close_wh", in: bundle, compatibleWith: nil) 167 | cancelButton.setImage(closeImage?.imageMaskWithColor(self.defalutOption.closeButtonColor), for: .normal) 168 | cancelButton.addTarget(self, action: #selector(cancelAction), for: .touchUpInside) 169 | navigationBar.addSubview(cancelButton) 170 | //3.标题 171 | titltLabel = UILabel(frame: CGRect(x: cancelButton.frame.maxX + leftEdge, y: (navigationBar.frame.height - 30) / 2, width: MMScreen.width - confirmButton.frame.width - cancelButton.frame.width - 4 * leftEdge , height: 30)) 172 | titltLabel.textAlignment = .center 173 | titltLabel.font = UIFont.boldSystemFont(ofSize: 18) 174 | titltLabel.textColor = defalutOption.navigationTitleColor 175 | navigationBar.addSubview(titltLabel) 176 | } 177 | 178 | private func setConfirmBtn(_ enabled: Bool) { 179 | confirmButton.isEnabled = enabled 180 | if enabled { 181 | confirmButton.setTitleColor(defalutOption.rightBarButtonColor, for: .normal) 182 | } else { 183 | confirmButton.setTitleColor(UIColor.init(white: 0.2, alpha: 0.5), for: .normal) 184 | } 185 | } 186 | 187 | private func layOutUpperView() { 188 | upperBarView = UIView(frame: CGRect(x: 0, y: navigationBar.frame.maxY, width: MMScreen.width, height: MultilevelStyle2Menu.upperViewHeight)) 189 | upperBarView.backgroundColor = UIColor.white 190 | self.addSubview(upperBarView) 191 | 192 | reminderLabel = UILabel(frame: CGRect(x: 16, y: 0, width: 70, height: upperBarView.frame.height - 1)) 193 | reminderLabel.font = defalutOption.upperBarLeftTextFont 194 | reminderLabel.text = defalutOption.upperBarDefalutLeftText 195 | reminderLabel.textColor = defalutOption.upperBarLeftTextColor 196 | upperBarView.addSubview(reminderLabel) 197 | let scrollViewX = reminderLabel.frame.maxX 198 | scrollView = UIScrollView(frame: CGRect(x: scrollViewX, y: 0, width: MMScreen.width - scrollViewX, height: upperBarView.frame.height - 1)) 199 | scrollView.showsHorizontalScrollIndicator = false 200 | scrollView.contentSize = CGSize(width: scrollView.frame.width, height: 0) 201 | upperBarView.addSubview(scrollView) 202 | 203 | let seperatorLine = UILabel(frame: CGRect(x: 0, y: reminderLabel.frame.maxY, width: MMScreen.width, height: 1)) 204 | seperatorLine.backgroundColor = UIColor.ColorFromRGB(rgbValue: 0xE1E1E1) 205 | upperBarView.addSubview(seperatorLine) 206 | } 207 | 208 | //MARK: - Handle Data 209 | override func setFirstDataSource() { 210 | super.setFirstDataSource() 211 | titltLabel.text = self.titleText 212 | firstMenuView.dataSouce = firstMenuDataSource 213 | } 214 | 215 | //MARK: - Show & Cancel 216 | @objc override public func show() { 217 | if allowSelectAnyLevelData { 218 | setConfirmBtn(true) 219 | } else { 220 | setConfirmBtn(false) 221 | } 222 | // 通过window 弹出view 223 | guard let window = UIApplication.shared.delegate?.window else { return } 224 | guard let currentWindow = window else { return } 225 | UIView.animate(withDuration: 0.3, animations: { 226 | self.frame.origin = CGPoint(x: 0, y: 0) 227 | currentWindow.addSubview(self) 228 | }) { (finished) in 229 | if finished { 230 | } 231 | } 232 | } 233 | 234 | @objc override func cancelAction() { 235 | UIView.animate(withDuration: 0.3, animations: { 236 | self.frame.origin = CGPoint(x: 0, y: MMScreen.height) 237 | }) { (finished) in 238 | if finished { 239 | self.removeFromSuperview() 240 | } 241 | } 242 | } 243 | 244 | //MARK: - Animation 245 | private func menuViewFullAnimation(_ tag: Int) { 246 | if let menuView = self.viewWithTag(tag) as? MultilevelMenuStyle2View { 247 | menuView.fullAnimation() 248 | } 249 | } 250 | 251 | private func menuViewBackToOriginalAnimation(_ tag: Int, _ completion: AnimationCompletionClosure? = nil) { 252 | if let menuView = self.viewWithTag(tag) as? MultilevelMenuStyle2View { 253 | menuView.popFromRightAnimation(completion) 254 | } 255 | } 256 | 257 | private func menuViewHideAnimation(_ tag: Int, _ completion: AnimationCompletionClosure? = nil) { 258 | if let menuView = self.viewWithTag(tag) as? MultilevelMenuStyle2View { 259 | menuView.hideAnimation_ClickButton(completion) 260 | } 261 | } 262 | 263 | private func menuViewRemoveFromSuperView(_ tag: Int) { 264 | if let menuView = self.viewWithTag(tag) as? MultilevelMenuStyle2View { 265 | menuView.removeFromSuperview() 266 | } 267 | } 268 | 269 | //MARK: - Scroll Button 270 | override func selectResultDisplay(_ name: String?) { 271 | super.selectResultDisplay(name) 272 | reminderLabel.text = defalutOption.upperBarSelectedLeftText 273 | } 274 | 275 | @objc override func clickName(_ sender: UIButton) { 276 | let clickedLevel = sender.tag - 200 277 | if clickedLevel < currentLevel { 278 | menuViewHideAnimation(currentLevel, { (completion) in 279 | if completion { 280 | if clickedLevel != 1 { 281 | self.menuViewBackToOriginalAnimation(clickedLevel, { (completion) in 282 | if completion { 283 | for i in (clickedLevel + 1) ..< self.currentLevel { 284 | self.menuViewRemoveFromSuperView(i) 285 | } 286 | } 287 | }) 288 | } else { 289 | for i in (clickedLevel + 1) ..< self.currentLevel { 290 | self.menuViewRemoveFromSuperView(i) 291 | } 292 | } 293 | let low = clickedLevel + 1 294 | for j in low ... self.currentLevel { 295 | self.removeDisplayButton(j + 200) 296 | } 297 | self.isSelectLastLevelRow = false 298 | self.currentLevel = clickedLevel 299 | self.currentButton = self.scrollView.viewWithTag(self.currentLevel + 200) as? UIButton 300 | } 301 | }) 302 | hasNextLevel = true 303 | } 304 | } 305 | 306 | // MARK: - MultilevelMenuViewDelegate 307 | public func didSelectRow(_ menuView: MultilevelMenuStyle2View, _ row: Int, _ dataModel: MenuDataModel) { 308 | modelSelected = dataModel 309 | let nextLevelDataSouce = self.getNextLevelDataSouce(dataModel.id) 310 | hasNextLevel = nextLevelDataSouce.isEmpty ? false : true 311 | selectResultDisplay(dataModel.name) 312 | if hasNextLevel { 313 | menuViewFullAnimation(currentLevel) 314 | currentLevel += 1 315 | creatNextLevelMenuView(nextLevelDataSouce) 316 | } 317 | } 318 | 319 | public func didRemoveFromView(_ menuView: MultilevelMenuStyle2View) { 320 | let lastLevel = currentLevel - 1 321 | if lastLevel > 1 { 322 | menuViewBackToOriginalAnimation(lastLevel) 323 | } 324 | removeDisplayButton(currentLevel + 200) 325 | isSelectLastLevelRow = false 326 | currentLevel -= 1 327 | currentButton = scrollView.viewWithTag(currentLevel + 200) as? UIButton 328 | hasNextLevel = true 329 | } 330 | 331 | } 332 | -------------------------------------------------------------------------------- /Demo/MultilevelMenuSwift/MultilevelMenu.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 4993E82322FD5754001EEB63 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4993E80E22FD5753001EEB63 /* ViewController.swift */; }; 11 | 4993E82722FD5754001EEB63 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4993E81422FD5753001EEB63 /* LaunchScreen.storyboard */; }; 12 | 4993E82822FD5754001EEB63 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4993E81622FD5753001EEB63 /* Main.storyboard */; }; 13 | 4993E82922FD5754001EEB63 /* businessType.json in Resources */ = {isa = PBXBuildFile; fileRef = 4993E81822FD5753001EEB63 /* businessType.json */; }; 14 | 4993E82A22FD5754001EEB63 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4993E81922FD5753001EEB63 /* Assets.xcassets */; }; 15 | 4993E82B22FD5754001EEB63 /* China.png in Resources */ = {isa = PBXBuildFile; fileRef = 4993E81B22FD5754001EEB63 /* China.png */; }; 16 | 4993E82C22FD5754001EEB63 /* CustomCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4993E81C22FD5754001EEB63 /* CustomCell.xib */; }; 17 | 4993E82D22FD5754001EEB63 /* CustomCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4993E81D22FD5754001EEB63 /* CustomCell.swift */; }; 18 | 4993E82E22FD5754001EEB63 /* CustomMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4993E81E22FD5754001EEB63 /* CustomMenuView.swift */; }; 19 | 4993E82F22FD5754001EEB63 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4993E81F22FD5754001EEB63 /* AppDelegate.swift */; }; 20 | 4993E83F22FD57B0001EEB63 /* MultilevelMenuBundle.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 4993E83422FD57B0001EEB63 /* MultilevelMenuBundle.bundle */; }; 21 | 4993E84022FD57B0001EEB63 /* MenuDataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4993E83622FD57B0001EEB63 /* MenuDataModel.swift */; }; 22 | 4993E84122FD57B0001EEB63 /* MultilevelMenuOption.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4993E83722FD57B0001EEB63 /* MultilevelMenuOption.swift */; }; 23 | 4993E84222FD57B0001EEB63 /* MultilevelStyle2Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4993E83822FD57B0001EEB63 /* MultilevelStyle2Menu.swift */; }; 24 | 4993E84322FD57B0001EEB63 /* MenuMarco.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4993E83922FD57B0001EEB63 /* MenuMarco.swift */; }; 25 | 4993E84422FD57B0001EEB63 /* MultilevelMenuStyle1View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4993E83A22FD57B0001EEB63 /* MultilevelMenuStyle1View.swift */; }; 26 | 4993E84522FD57B0001EEB63 /* MultilevelMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4993E83B22FD57B0001EEB63 /* MultilevelMenuView.swift */; }; 27 | 4993E84622FD57B0001EEB63 /* MultilevelMenuStyle2View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4993E83C22FD57B0001EEB63 /* MultilevelMenuStyle2View.swift */; }; 28 | 4993E84722FD57B0001EEB63 /* MultilevelStlyeMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4993E83D22FD57B0001EEB63 /* MultilevelStlyeMenu.swift */; }; 29 | 4993E84822FD57B0001EEB63 /* MultilevelStyle1Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4993E83E22FD57B0001EEB63 /* MultilevelStyle1Menu.swift */; }; 30 | /* End PBXBuildFile section */ 31 | 32 | /* Begin PBXContainerItemProxy section */ 33 | 499C67182092C49200C36F75 /* PBXContainerItemProxy */ = { 34 | isa = PBXContainerItemProxy; 35 | containerPortal = 499C66FB2092C48B00C36F75 /* Project object */; 36 | proxyType = 1; 37 | remoteGlobalIDString = 499C67022092C48B00C36F75; 38 | remoteInfo = MultilevelMenuDemo; 39 | }; 40 | 499C67232092C49200C36F75 /* PBXContainerItemProxy */ = { 41 | isa = PBXContainerItemProxy; 42 | containerPortal = 499C66FB2092C48B00C36F75 /* Project object */; 43 | proxyType = 1; 44 | remoteGlobalIDString = 499C67022092C48B00C36F75; 45 | remoteInfo = MultilevelMenuDemo; 46 | }; 47 | /* End PBXContainerItemProxy section */ 48 | 49 | /* Begin PBXFileReference section */ 50 | 4993E80E22FD5753001EEB63 /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 51 | 4993E81222FD5753001EEB63 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 52 | 4993E81522FD5753001EEB63 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = LaunchScreen.storyboard; sourceTree = ""; }; 53 | 4993E81722FD5753001EEB63 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Main.storyboard; sourceTree = ""; }; 54 | 4993E81822FD5753001EEB63 /* businessType.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = businessType.json; sourceTree = ""; }; 55 | 4993E81922FD5753001EEB63 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 56 | 4993E81B22FD5754001EEB63 /* China.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = China.png; sourceTree = ""; }; 57 | 4993E81C22FD5754001EEB63 /* CustomCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = CustomCell.xib; sourceTree = ""; }; 58 | 4993E81D22FD5754001EEB63 /* CustomCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomCell.swift; sourceTree = ""; }; 59 | 4993E81E22FD5754001EEB63 /* CustomMenuView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomMenuView.swift; sourceTree = ""; }; 60 | 4993E81F22FD5754001EEB63 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 61 | 4993E83422FD57B0001EEB63 /* MultilevelMenuBundle.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = MultilevelMenuBundle.bundle; sourceTree = ""; }; 62 | 4993E83622FD57B0001EEB63 /* MenuDataModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenuDataModel.swift; sourceTree = ""; }; 63 | 4993E83722FD57B0001EEB63 /* MultilevelMenuOption.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultilevelMenuOption.swift; sourceTree = ""; }; 64 | 4993E83822FD57B0001EEB63 /* MultilevelStyle2Menu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultilevelStyle2Menu.swift; sourceTree = ""; }; 65 | 4993E83922FD57B0001EEB63 /* MenuMarco.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenuMarco.swift; sourceTree = ""; }; 66 | 4993E83A22FD57B0001EEB63 /* MultilevelMenuStyle1View.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultilevelMenuStyle1View.swift; sourceTree = ""; }; 67 | 4993E83B22FD57B0001EEB63 /* MultilevelMenuView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultilevelMenuView.swift; sourceTree = ""; }; 68 | 4993E83C22FD57B0001EEB63 /* MultilevelMenuStyle2View.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultilevelMenuStyle2View.swift; sourceTree = ""; }; 69 | 4993E83D22FD57B0001EEB63 /* MultilevelStlyeMenu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultilevelStlyeMenu.swift; sourceTree = ""; }; 70 | 4993E83E22FD57B0001EEB63 /* MultilevelStyle1Menu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultilevelStyle1Menu.swift; sourceTree = ""; }; 71 | 499C67032092C48B00C36F75 /* MultilevelMenu.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MultilevelMenu.app; sourceTree = BUILT_PRODUCTS_DIR; }; 72 | 499C67172092C49200C36F75 /* MultilevelMenuTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MultilevelMenuTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 73 | 499C67222092C49200C36F75 /* MultilevelMenuUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MultilevelMenuUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 74 | /* End PBXFileReference section */ 75 | 76 | /* Begin PBXFrameworksBuildPhase section */ 77 | 499C67002092C48B00C36F75 /* Frameworks */ = { 78 | isa = PBXFrameworksBuildPhase; 79 | buildActionMask = 2147483647; 80 | files = ( 81 | ); 82 | runOnlyForDeploymentPostprocessing = 0; 83 | }; 84 | 499C67142092C49200C36F75 /* Frameworks */ = { 85 | isa = PBXFrameworksBuildPhase; 86 | buildActionMask = 2147483647; 87 | files = ( 88 | ); 89 | runOnlyForDeploymentPostprocessing = 0; 90 | }; 91 | 499C671F2092C49200C36F75 /* Frameworks */ = { 92 | isa = PBXFrameworksBuildPhase; 93 | buildActionMask = 2147483647; 94 | files = ( 95 | ); 96 | runOnlyForDeploymentPostprocessing = 0; 97 | }; 98 | /* End PBXFrameworksBuildPhase section */ 99 | 100 | /* Begin PBXGroup section */ 101 | 4993E81322FD5753001EEB63 /* Base.lproj */ = { 102 | isa = PBXGroup; 103 | children = ( 104 | 4993E81422FD5753001EEB63 /* LaunchScreen.storyboard */, 105 | 4993E81622FD5753001EEB63 /* Main.storyboard */, 106 | ); 107 | path = Base.lproj; 108 | sourceTree = ""; 109 | }; 110 | 4993E81A22FD5754001EEB63 /* CustomMenu */ = { 111 | isa = PBXGroup; 112 | children = ( 113 | 4993E81B22FD5754001EEB63 /* China.png */, 114 | 4993E81C22FD5754001EEB63 /* CustomCell.xib */, 115 | 4993E81D22FD5754001EEB63 /* CustomCell.swift */, 116 | 4993E81E22FD5754001EEB63 /* CustomMenuView.swift */, 117 | ); 118 | path = CustomMenu; 119 | sourceTree = ""; 120 | }; 121 | 4993E83222FD57B0001EEB63 /* MultilevelMenu */ = { 122 | isa = PBXGroup; 123 | children = ( 124 | 4993E83322FD57B0001EEB63 /* Resources */, 125 | 4993E83522FD57B0001EEB63 /* Source */, 126 | ); 127 | name = MultilevelMenu; 128 | path = ../../MultilevelMenu; 129 | sourceTree = ""; 130 | }; 131 | 4993E83322FD57B0001EEB63 /* Resources */ = { 132 | isa = PBXGroup; 133 | children = ( 134 | 4993E83422FD57B0001EEB63 /* MultilevelMenuBundle.bundle */, 135 | ); 136 | path = Resources; 137 | sourceTree = ""; 138 | }; 139 | 4993E83522FD57B0001EEB63 /* Source */ = { 140 | isa = PBXGroup; 141 | children = ( 142 | 4993E83622FD57B0001EEB63 /* MenuDataModel.swift */, 143 | 4993E83722FD57B0001EEB63 /* MultilevelMenuOption.swift */, 144 | 4993E83822FD57B0001EEB63 /* MultilevelStyle2Menu.swift */, 145 | 4993E83922FD57B0001EEB63 /* MenuMarco.swift */, 146 | 4993E83A22FD57B0001EEB63 /* MultilevelMenuStyle1View.swift */, 147 | 4993E83B22FD57B0001EEB63 /* MultilevelMenuView.swift */, 148 | 4993E83C22FD57B0001EEB63 /* MultilevelMenuStyle2View.swift */, 149 | 4993E83D22FD57B0001EEB63 /* MultilevelStlyeMenu.swift */, 150 | 4993E83E22FD57B0001EEB63 /* MultilevelStyle1Menu.swift */, 151 | ); 152 | path = Source; 153 | sourceTree = ""; 154 | }; 155 | 499C66FA2092C48B00C36F75 = { 156 | isa = PBXGroup; 157 | children = ( 158 | 4993E83222FD57B0001EEB63 /* MultilevelMenu */, 159 | 4993E81A22FD5754001EEB63 /* CustomMenu */, 160 | 4993E80E22FD5753001EEB63 /* ViewController.swift */, 161 | 4993E81F22FD5754001EEB63 /* AppDelegate.swift */, 162 | 4993E81922FD5753001EEB63 /* Assets.xcassets */, 163 | 4993E81322FD5753001EEB63 /* Base.lproj */, 164 | 4993E81822FD5753001EEB63 /* businessType.json */, 165 | 4993E81222FD5753001EEB63 /* Info.plist */, 166 | 499C67042092C48B00C36F75 /* Products */, 167 | ); 168 | sourceTree = ""; 169 | }; 170 | 499C67042092C48B00C36F75 /* Products */ = { 171 | isa = PBXGroup; 172 | children = ( 173 | 499C67032092C48B00C36F75 /* MultilevelMenu.app */, 174 | 499C67172092C49200C36F75 /* MultilevelMenuTests.xctest */, 175 | 499C67222092C49200C36F75 /* MultilevelMenuUITests.xctest */, 176 | ); 177 | name = Products; 178 | sourceTree = ""; 179 | }; 180 | /* End PBXGroup section */ 181 | 182 | /* Begin PBXNativeTarget section */ 183 | 499C67022092C48B00C36F75 /* MultilevelMenu */ = { 184 | isa = PBXNativeTarget; 185 | buildConfigurationList = 499C672B2092C49200C36F75 /* Build configuration list for PBXNativeTarget "MultilevelMenu" */; 186 | buildPhases = ( 187 | 499C66FF2092C48B00C36F75 /* Sources */, 188 | 499C67002092C48B00C36F75 /* Frameworks */, 189 | 499C67012092C48B00C36F75 /* Resources */, 190 | ); 191 | buildRules = ( 192 | ); 193 | dependencies = ( 194 | ); 195 | name = MultilevelMenu; 196 | productName = MultilevelMenuDemo; 197 | productReference = 499C67032092C48B00C36F75 /* MultilevelMenu.app */; 198 | productType = "com.apple.product-type.application"; 199 | }; 200 | 499C67162092C49200C36F75 /* MultilevelMenuTests */ = { 201 | isa = PBXNativeTarget; 202 | buildConfigurationList = 499C672E2092C49200C36F75 /* Build configuration list for PBXNativeTarget "MultilevelMenuTests" */; 203 | buildPhases = ( 204 | 499C67132092C49200C36F75 /* Sources */, 205 | 499C67142092C49200C36F75 /* Frameworks */, 206 | 499C67152092C49200C36F75 /* Resources */, 207 | ); 208 | buildRules = ( 209 | ); 210 | dependencies = ( 211 | 499C67192092C49200C36F75 /* PBXTargetDependency */, 212 | ); 213 | name = MultilevelMenuTests; 214 | productName = MultilevelMenuDemoTests; 215 | productReference = 499C67172092C49200C36F75 /* MultilevelMenuTests.xctest */; 216 | productType = "com.apple.product-type.bundle.unit-test"; 217 | }; 218 | 499C67212092C49200C36F75 /* MultilevelMenuUITests */ = { 219 | isa = PBXNativeTarget; 220 | buildConfigurationList = 499C67312092C49200C36F75 /* Build configuration list for PBXNativeTarget "MultilevelMenuUITests" */; 221 | buildPhases = ( 222 | 499C671E2092C49200C36F75 /* Sources */, 223 | 499C671F2092C49200C36F75 /* Frameworks */, 224 | 499C67202092C49200C36F75 /* Resources */, 225 | ); 226 | buildRules = ( 227 | ); 228 | dependencies = ( 229 | 499C67242092C49200C36F75 /* PBXTargetDependency */, 230 | ); 231 | name = MultilevelMenuUITests; 232 | productName = MultilevelMenuDemoUITests; 233 | productReference = 499C67222092C49200C36F75 /* MultilevelMenuUITests.xctest */; 234 | productType = "com.apple.product-type.bundle.ui-testing"; 235 | }; 236 | /* End PBXNativeTarget section */ 237 | 238 | /* Begin PBXProject section */ 239 | 499C66FB2092C48B00C36F75 /* Project object */ = { 240 | isa = PBXProject; 241 | attributes = { 242 | LastSwiftUpdateCheck = 0930; 243 | LastUpgradeCheck = 0930; 244 | ORGANIZATIONNAME = ChokShen; 245 | TargetAttributes = { 246 | 499C67022092C48B00C36F75 = { 247 | CreatedOnToolsVersion = 9.3; 248 | LastSwiftMigration = 1010; 249 | }; 250 | 499C67162092C49200C36F75 = { 251 | CreatedOnToolsVersion = 9.3; 252 | TestTargetID = 499C67022092C48B00C36F75; 253 | }; 254 | 499C67212092C49200C36F75 = { 255 | CreatedOnToolsVersion = 9.3; 256 | TestTargetID = 499C67022092C48B00C36F75; 257 | }; 258 | }; 259 | }; 260 | buildConfigurationList = 499C66FE2092C48B00C36F75 /* Build configuration list for PBXProject "MultilevelMenu" */; 261 | compatibilityVersion = "Xcode 9.3"; 262 | developmentRegion = en; 263 | hasScannedForEncodings = 0; 264 | knownRegions = ( 265 | en, 266 | Base, 267 | ); 268 | mainGroup = 499C66FA2092C48B00C36F75; 269 | productRefGroup = 499C67042092C48B00C36F75 /* Products */; 270 | projectDirPath = ""; 271 | projectRoot = ""; 272 | targets = ( 273 | 499C67022092C48B00C36F75 /* MultilevelMenu */, 274 | 499C67162092C49200C36F75 /* MultilevelMenuTests */, 275 | 499C67212092C49200C36F75 /* MultilevelMenuUITests */, 276 | ); 277 | }; 278 | /* End PBXProject section */ 279 | 280 | /* Begin PBXResourcesBuildPhase section */ 281 | 499C67012092C48B00C36F75 /* Resources */ = { 282 | isa = PBXResourcesBuildPhase; 283 | buildActionMask = 2147483647; 284 | files = ( 285 | 4993E82722FD5754001EEB63 /* LaunchScreen.storyboard in Resources */, 286 | 4993E82C22FD5754001EEB63 /* CustomCell.xib in Resources */, 287 | 4993E82922FD5754001EEB63 /* businessType.json in Resources */, 288 | 4993E82B22FD5754001EEB63 /* China.png in Resources */, 289 | 4993E82A22FD5754001EEB63 /* Assets.xcassets in Resources */, 290 | 4993E83F22FD57B0001EEB63 /* MultilevelMenuBundle.bundle in Resources */, 291 | 4993E82822FD5754001EEB63 /* Main.storyboard in Resources */, 292 | ); 293 | runOnlyForDeploymentPostprocessing = 0; 294 | }; 295 | 499C67152092C49200C36F75 /* Resources */ = { 296 | isa = PBXResourcesBuildPhase; 297 | buildActionMask = 2147483647; 298 | files = ( 299 | ); 300 | runOnlyForDeploymentPostprocessing = 0; 301 | }; 302 | 499C67202092C49200C36F75 /* Resources */ = { 303 | isa = PBXResourcesBuildPhase; 304 | buildActionMask = 2147483647; 305 | files = ( 306 | ); 307 | runOnlyForDeploymentPostprocessing = 0; 308 | }; 309 | /* End PBXResourcesBuildPhase section */ 310 | 311 | /* Begin PBXSourcesBuildPhase section */ 312 | 499C66FF2092C48B00C36F75 /* Sources */ = { 313 | isa = PBXSourcesBuildPhase; 314 | buildActionMask = 2147483647; 315 | files = ( 316 | 4993E84222FD57B0001EEB63 /* MultilevelStyle2Menu.swift in Sources */, 317 | 4993E84322FD57B0001EEB63 /* MenuMarco.swift in Sources */, 318 | 4993E84122FD57B0001EEB63 /* MultilevelMenuOption.swift in Sources */, 319 | 4993E84622FD57B0001EEB63 /* MultilevelMenuStyle2View.swift in Sources */, 320 | 4993E82322FD5754001EEB63 /* ViewController.swift in Sources */, 321 | 4993E82D22FD5754001EEB63 /* CustomCell.swift in Sources */, 322 | 4993E84522FD57B0001EEB63 /* MultilevelMenuView.swift in Sources */, 323 | 4993E84722FD57B0001EEB63 /* MultilevelStlyeMenu.swift in Sources */, 324 | 4993E82E22FD5754001EEB63 /* CustomMenuView.swift in Sources */, 325 | 4993E84822FD57B0001EEB63 /* MultilevelStyle1Menu.swift in Sources */, 326 | 4993E84022FD57B0001EEB63 /* MenuDataModel.swift in Sources */, 327 | 4993E84422FD57B0001EEB63 /* MultilevelMenuStyle1View.swift in Sources */, 328 | 4993E82F22FD5754001EEB63 /* AppDelegate.swift in Sources */, 329 | ); 330 | runOnlyForDeploymentPostprocessing = 0; 331 | }; 332 | 499C67132092C49200C36F75 /* Sources */ = { 333 | isa = PBXSourcesBuildPhase; 334 | buildActionMask = 2147483647; 335 | files = ( 336 | ); 337 | runOnlyForDeploymentPostprocessing = 0; 338 | }; 339 | 499C671E2092C49200C36F75 /* Sources */ = { 340 | isa = PBXSourcesBuildPhase; 341 | buildActionMask = 2147483647; 342 | files = ( 343 | ); 344 | runOnlyForDeploymentPostprocessing = 0; 345 | }; 346 | /* End PBXSourcesBuildPhase section */ 347 | 348 | /* Begin PBXTargetDependency section */ 349 | 499C67192092C49200C36F75 /* PBXTargetDependency */ = { 350 | isa = PBXTargetDependency; 351 | target = 499C67022092C48B00C36F75 /* MultilevelMenu */; 352 | targetProxy = 499C67182092C49200C36F75 /* PBXContainerItemProxy */; 353 | }; 354 | 499C67242092C49200C36F75 /* PBXTargetDependency */ = { 355 | isa = PBXTargetDependency; 356 | target = 499C67022092C48B00C36F75 /* MultilevelMenu */; 357 | targetProxy = 499C67232092C49200C36F75 /* PBXContainerItemProxy */; 358 | }; 359 | /* End PBXTargetDependency section */ 360 | 361 | /* Begin PBXVariantGroup section */ 362 | 4993E81422FD5753001EEB63 /* LaunchScreen.storyboard */ = { 363 | isa = PBXVariantGroup; 364 | children = ( 365 | 4993E81522FD5753001EEB63 /* Base */, 366 | ); 367 | name = LaunchScreen.storyboard; 368 | sourceTree = ""; 369 | }; 370 | 4993E81622FD5753001EEB63 /* Main.storyboard */ = { 371 | isa = PBXVariantGroup; 372 | children = ( 373 | 4993E81722FD5753001EEB63 /* Base */, 374 | ); 375 | name = Main.storyboard; 376 | sourceTree = ""; 377 | }; 378 | /* End PBXVariantGroup section */ 379 | 380 | /* Begin XCBuildConfiguration section */ 381 | 499C67292092C49200C36F75 /* Debug */ = { 382 | isa = XCBuildConfiguration; 383 | buildSettings = { 384 | ALWAYS_SEARCH_USER_PATHS = NO; 385 | CLANG_ANALYZER_NONNULL = YES; 386 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 387 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 388 | CLANG_CXX_LIBRARY = "libc++"; 389 | CLANG_ENABLE_MODULES = YES; 390 | CLANG_ENABLE_OBJC_ARC = YES; 391 | CLANG_ENABLE_OBJC_WEAK = YES; 392 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 393 | CLANG_WARN_BOOL_CONVERSION = YES; 394 | CLANG_WARN_COMMA = YES; 395 | CLANG_WARN_CONSTANT_CONVERSION = YES; 396 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 397 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 398 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 399 | CLANG_WARN_EMPTY_BODY = YES; 400 | CLANG_WARN_ENUM_CONVERSION = YES; 401 | CLANG_WARN_INFINITE_RECURSION = YES; 402 | CLANG_WARN_INT_CONVERSION = YES; 403 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 404 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 405 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 406 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 407 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 408 | CLANG_WARN_STRICT_PROTOTYPES = YES; 409 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 410 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 411 | CLANG_WARN_UNREACHABLE_CODE = YES; 412 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 413 | CODE_SIGN_IDENTITY = "iPhone Developer"; 414 | COPY_PHASE_STRIP = NO; 415 | DEBUG_INFORMATION_FORMAT = dwarf; 416 | ENABLE_STRICT_OBJC_MSGSEND = YES; 417 | ENABLE_TESTABILITY = YES; 418 | GCC_C_LANGUAGE_STANDARD = gnu11; 419 | GCC_DYNAMIC_NO_PIC = NO; 420 | GCC_NO_COMMON_BLOCKS = YES; 421 | GCC_OPTIMIZATION_LEVEL = 0; 422 | GCC_PREPROCESSOR_DEFINITIONS = ( 423 | "DEBUG=1", 424 | "$(inherited)", 425 | ); 426 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 427 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 428 | GCC_WARN_UNDECLARED_SELECTOR = YES; 429 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 430 | GCC_WARN_UNUSED_FUNCTION = YES; 431 | GCC_WARN_UNUSED_VARIABLE = YES; 432 | IPHONEOS_DEPLOYMENT_TARGET = 11.3; 433 | MTL_ENABLE_DEBUG_INFO = YES; 434 | ONLY_ACTIVE_ARCH = YES; 435 | SDKROOT = iphoneos; 436 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 437 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 438 | }; 439 | name = Debug; 440 | }; 441 | 499C672A2092C49200C36F75 /* Release */ = { 442 | isa = XCBuildConfiguration; 443 | buildSettings = { 444 | ALWAYS_SEARCH_USER_PATHS = NO; 445 | CLANG_ANALYZER_NONNULL = YES; 446 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 447 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 448 | CLANG_CXX_LIBRARY = "libc++"; 449 | CLANG_ENABLE_MODULES = YES; 450 | CLANG_ENABLE_OBJC_ARC = YES; 451 | CLANG_ENABLE_OBJC_WEAK = YES; 452 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 453 | CLANG_WARN_BOOL_CONVERSION = YES; 454 | CLANG_WARN_COMMA = YES; 455 | CLANG_WARN_CONSTANT_CONVERSION = YES; 456 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 457 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 458 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 459 | CLANG_WARN_EMPTY_BODY = YES; 460 | CLANG_WARN_ENUM_CONVERSION = YES; 461 | CLANG_WARN_INFINITE_RECURSION = YES; 462 | CLANG_WARN_INT_CONVERSION = YES; 463 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 464 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 465 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 466 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 467 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 468 | CLANG_WARN_STRICT_PROTOTYPES = YES; 469 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 470 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 471 | CLANG_WARN_UNREACHABLE_CODE = YES; 472 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 473 | CODE_SIGN_IDENTITY = "iPhone Developer"; 474 | COPY_PHASE_STRIP = NO; 475 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 476 | ENABLE_NS_ASSERTIONS = NO; 477 | ENABLE_STRICT_OBJC_MSGSEND = YES; 478 | GCC_C_LANGUAGE_STANDARD = gnu11; 479 | GCC_NO_COMMON_BLOCKS = YES; 480 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 481 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 482 | GCC_WARN_UNDECLARED_SELECTOR = YES; 483 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 484 | GCC_WARN_UNUSED_FUNCTION = YES; 485 | GCC_WARN_UNUSED_VARIABLE = YES; 486 | IPHONEOS_DEPLOYMENT_TARGET = 11.3; 487 | MTL_ENABLE_DEBUG_INFO = NO; 488 | SDKROOT = iphoneos; 489 | SWIFT_COMPILATION_MODE = wholemodule; 490 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 491 | VALIDATE_PRODUCT = YES; 492 | }; 493 | name = Release; 494 | }; 495 | 499C672C2092C49200C36F75 /* Debug */ = { 496 | isa = XCBuildConfiguration; 497 | buildSettings = { 498 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 499 | CLANG_ENABLE_MODULES = YES; 500 | CODE_SIGN_STYLE = Automatic; 501 | DEVELOPMENT_TEAM = RJUJXP82S4; 502 | INFOPLIST_FILE = "$(SRCROOT)/Info.plist"; 503 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 504 | LD_RUNPATH_SEARCH_PATHS = ( 505 | "$(inherited)", 506 | "@executable_path/Frameworks", 507 | ); 508 | PRODUCT_BUNDLE_IDENTIFIER = com.ChokShen.MultilevelMenuDemo; 509 | PRODUCT_NAME = "$(TARGET_NAME)"; 510 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 511 | SWIFT_VERSION = 5.0; 512 | TARGETED_DEVICE_FAMILY = "1,2"; 513 | }; 514 | name = Debug; 515 | }; 516 | 499C672D2092C49200C36F75 /* Release */ = { 517 | isa = XCBuildConfiguration; 518 | buildSettings = { 519 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 520 | CLANG_ENABLE_MODULES = YES; 521 | CODE_SIGN_STYLE = Automatic; 522 | DEVELOPMENT_TEAM = RJUJXP82S4; 523 | INFOPLIST_FILE = "$(SRCROOT)/Info.plist"; 524 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 525 | LD_RUNPATH_SEARCH_PATHS = ( 526 | "$(inherited)", 527 | "@executable_path/Frameworks", 528 | ); 529 | PRODUCT_BUNDLE_IDENTIFIER = com.ChokShen.MultilevelMenuDemo; 530 | PRODUCT_NAME = "$(TARGET_NAME)"; 531 | SWIFT_VERSION = 5.0; 532 | TARGETED_DEVICE_FAMILY = "1,2"; 533 | }; 534 | name = Release; 535 | }; 536 | 499C672F2092C49200C36F75 /* Debug */ = { 537 | isa = XCBuildConfiguration; 538 | buildSettings = { 539 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 540 | BUNDLE_LOADER = "$(TEST_HOST)"; 541 | CODE_SIGN_STYLE = Automatic; 542 | INFOPLIST_FILE = MultilevelMenuDemoTests/Info.plist; 543 | LD_RUNPATH_SEARCH_PATHS = ( 544 | "$(inherited)", 545 | "@executable_path/Frameworks", 546 | "@loader_path/Frameworks", 547 | ); 548 | PRODUCT_BUNDLE_IDENTIFIER = com.ChokShen.MultilevelMenuDemoTests; 549 | PRODUCT_NAME = "$(TARGET_NAME)"; 550 | SWIFT_VERSION = 4.0; 551 | TARGETED_DEVICE_FAMILY = "1,2"; 552 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/MultilevelMenu.app/MultilevelMenu"; 553 | }; 554 | name = Debug; 555 | }; 556 | 499C67302092C49200C36F75 /* Release */ = { 557 | isa = XCBuildConfiguration; 558 | buildSettings = { 559 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 560 | BUNDLE_LOADER = "$(TEST_HOST)"; 561 | CODE_SIGN_STYLE = Automatic; 562 | INFOPLIST_FILE = MultilevelMenuDemoTests/Info.plist; 563 | LD_RUNPATH_SEARCH_PATHS = ( 564 | "$(inherited)", 565 | "@executable_path/Frameworks", 566 | "@loader_path/Frameworks", 567 | ); 568 | PRODUCT_BUNDLE_IDENTIFIER = com.ChokShen.MultilevelMenuDemoTests; 569 | PRODUCT_NAME = "$(TARGET_NAME)"; 570 | SWIFT_VERSION = 4.0; 571 | TARGETED_DEVICE_FAMILY = "1,2"; 572 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/MultilevelMenu.app/MultilevelMenu"; 573 | }; 574 | name = Release; 575 | }; 576 | 499C67322092C49200C36F75 /* Debug */ = { 577 | isa = XCBuildConfiguration; 578 | buildSettings = { 579 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 580 | CODE_SIGN_STYLE = Automatic; 581 | INFOPLIST_FILE = MultilevelMenuDemoUITests/Info.plist; 582 | LD_RUNPATH_SEARCH_PATHS = ( 583 | "$(inherited)", 584 | "@executable_path/Frameworks", 585 | "@loader_path/Frameworks", 586 | ); 587 | PRODUCT_BUNDLE_IDENTIFIER = com.ChokShen.MultilevelMenuDemoUITests; 588 | PRODUCT_NAME = "$(TARGET_NAME)"; 589 | SWIFT_VERSION = 4.0; 590 | TARGETED_DEVICE_FAMILY = "1,2"; 591 | TEST_TARGET_NAME = MultilevelMenuDemo; 592 | }; 593 | name = Debug; 594 | }; 595 | 499C67332092C49200C36F75 /* Release */ = { 596 | isa = XCBuildConfiguration; 597 | buildSettings = { 598 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 599 | CODE_SIGN_STYLE = Automatic; 600 | INFOPLIST_FILE = MultilevelMenuDemoUITests/Info.plist; 601 | LD_RUNPATH_SEARCH_PATHS = ( 602 | "$(inherited)", 603 | "@executable_path/Frameworks", 604 | "@loader_path/Frameworks", 605 | ); 606 | PRODUCT_BUNDLE_IDENTIFIER = com.ChokShen.MultilevelMenuDemoUITests; 607 | PRODUCT_NAME = "$(TARGET_NAME)"; 608 | SWIFT_VERSION = 4.0; 609 | TARGETED_DEVICE_FAMILY = "1,2"; 610 | TEST_TARGET_NAME = MultilevelMenuDemo; 611 | }; 612 | name = Release; 613 | }; 614 | /* End XCBuildConfiguration section */ 615 | 616 | /* Begin XCConfigurationList section */ 617 | 499C66FE2092C48B00C36F75 /* Build configuration list for PBXProject "MultilevelMenu" */ = { 618 | isa = XCConfigurationList; 619 | buildConfigurations = ( 620 | 499C67292092C49200C36F75 /* Debug */, 621 | 499C672A2092C49200C36F75 /* Release */, 622 | ); 623 | defaultConfigurationIsVisible = 0; 624 | defaultConfigurationName = Release; 625 | }; 626 | 499C672B2092C49200C36F75 /* Build configuration list for PBXNativeTarget "MultilevelMenu" */ = { 627 | isa = XCConfigurationList; 628 | buildConfigurations = ( 629 | 499C672C2092C49200C36F75 /* Debug */, 630 | 499C672D2092C49200C36F75 /* Release */, 631 | ); 632 | defaultConfigurationIsVisible = 0; 633 | defaultConfigurationName = Release; 634 | }; 635 | 499C672E2092C49200C36F75 /* Build configuration list for PBXNativeTarget "MultilevelMenuTests" */ = { 636 | isa = XCConfigurationList; 637 | buildConfigurations = ( 638 | 499C672F2092C49200C36F75 /* Debug */, 639 | 499C67302092C49200C36F75 /* Release */, 640 | ); 641 | defaultConfigurationIsVisible = 0; 642 | defaultConfigurationName = Release; 643 | }; 644 | 499C67312092C49200C36F75 /* Build configuration list for PBXNativeTarget "MultilevelMenuUITests" */ = { 645 | isa = XCConfigurationList; 646 | buildConfigurations = ( 647 | 499C67322092C49200C36F75 /* Debug */, 648 | 499C67332092C49200C36F75 /* Release */, 649 | ); 650 | defaultConfigurationIsVisible = 0; 651 | defaultConfigurationName = Release; 652 | }; 653 | /* End XCConfigurationList section */ 654 | }; 655 | rootObject = 499C66FB2092C48B00C36F75 /* Project object */; 656 | } 657 | -------------------------------------------------------------------------------- /Demo/MultilevelMenuOC/MultilevelMenuOC.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 4993E7DC22FD53BD001EEB63 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4993E7DB22FD53BD001EEB63 /* AppDelegate.m */; }; 11 | 4993E7DF22FD53BD001EEB63 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4993E7DE22FD53BD001EEB63 /* ViewController.m */; }; 12 | 4993E7E222FD53BD001EEB63 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4993E7E022FD53BD001EEB63 /* Main.storyboard */; }; 13 | 4993E7E422FD53BF001EEB63 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4993E7E322FD53BF001EEB63 /* Assets.xcassets */; }; 14 | 4993E7E722FD53BF001EEB63 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4993E7E522FD53BF001EEB63 /* LaunchScreen.storyboard */; }; 15 | 4993E7EA22FD53BF001EEB63 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 4993E7E922FD53BF001EEB63 /* main.m */; }; 16 | 4993E7F422FD53BF001EEB63 /* MultilevelMenuOCTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4993E7F322FD53BF001EEB63 /* MultilevelMenuOCTests.m */; }; 17 | 4993E7FF22FD53BF001EEB63 /* MultilevelMenuOCUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4993E7FE22FD53BF001EEB63 /* MultilevelMenuOCUITests.m */; }; 18 | 4993E85822FD5BC8001EEB63 /* MultilevelMenuBundle.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 4993E84D22FD5BC8001EEB63 /* MultilevelMenuBundle.bundle */; }; 19 | 4993E85922FD5BC8001EEB63 /* MenuDataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4993E84F22FD5BC8001EEB63 /* MenuDataModel.swift */; }; 20 | 4993E85A22FD5BC8001EEB63 /* MultilevelMenuOption.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4993E85022FD5BC8001EEB63 /* MultilevelMenuOption.swift */; }; 21 | 4993E85B22FD5BC8001EEB63 /* MultilevelStyle2Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4993E85122FD5BC8001EEB63 /* MultilevelStyle2Menu.swift */; }; 22 | 4993E85C22FD5BC8001EEB63 /* MenuMarco.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4993E85222FD5BC8001EEB63 /* MenuMarco.swift */; }; 23 | 4993E85D22FD5BC8001EEB63 /* MultilevelMenuStyle1View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4993E85322FD5BC8001EEB63 /* MultilevelMenuStyle1View.swift */; }; 24 | 4993E85E22FD5BC8001EEB63 /* MultilevelMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4993E85422FD5BC8001EEB63 /* MultilevelMenuView.swift */; }; 25 | 4993E85F22FD5BC8001EEB63 /* MultilevelMenuStyle2View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4993E85522FD5BC8001EEB63 /* MultilevelMenuStyle2View.swift */; }; 26 | 4993E86022FD5BC8001EEB63 /* MultilevelStlyeMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4993E85622FD5BC8001EEB63 /* MultilevelStlyeMenu.swift */; }; 27 | 4993E86122FD5BC8001EEB63 /* MultilevelStyle1Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4993E85722FD5BC8001EEB63 /* MultilevelStyle1Menu.swift */; }; 28 | 4993E86722FD7065001EEB63 /* businessType.json in Resources */ = {isa = PBXBuildFile; fileRef = 4993E86622FD7065001EEB63 /* businessType.json */; }; 29 | /* End PBXBuildFile section */ 30 | 31 | /* Begin PBXContainerItemProxy section */ 32 | 4993E7F022FD53BF001EEB63 /* PBXContainerItemProxy */ = { 33 | isa = PBXContainerItemProxy; 34 | containerPortal = 4993E7CF22FD53BD001EEB63 /* Project object */; 35 | proxyType = 1; 36 | remoteGlobalIDString = 4993E7D622FD53BD001EEB63; 37 | remoteInfo = MultilevelMenuOC; 38 | }; 39 | 4993E7FB22FD53BF001EEB63 /* PBXContainerItemProxy */ = { 40 | isa = PBXContainerItemProxy; 41 | containerPortal = 4993E7CF22FD53BD001EEB63 /* Project object */; 42 | proxyType = 1; 43 | remoteGlobalIDString = 4993E7D622FD53BD001EEB63; 44 | remoteInfo = MultilevelMenuOC; 45 | }; 46 | /* End PBXContainerItemProxy section */ 47 | 48 | /* Begin PBXFileReference section */ 49 | 4993E7D722FD53BD001EEB63 /* MultilevelMenuOC.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MultilevelMenuOC.app; sourceTree = BUILT_PRODUCTS_DIR; }; 50 | 4993E7DA22FD53BD001EEB63 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 51 | 4993E7DB22FD53BD001EEB63 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 52 | 4993E7DD22FD53BD001EEB63 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 53 | 4993E7DE22FD53BD001EEB63 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 54 | 4993E7E122FD53BD001EEB63 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 55 | 4993E7E322FD53BF001EEB63 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 56 | 4993E7E622FD53BF001EEB63 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 57 | 4993E7E822FD53BF001EEB63 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 58 | 4993E7E922FD53BF001EEB63 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 59 | 4993E7EF22FD53BF001EEB63 /* MultilevelMenuOCTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MultilevelMenuOCTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 60 | 4993E7F322FD53BF001EEB63 /* MultilevelMenuOCTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MultilevelMenuOCTests.m; sourceTree = ""; }; 61 | 4993E7F522FD53BF001EEB63 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 62 | 4993E7FA22FD53BF001EEB63 /* MultilevelMenuOCUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MultilevelMenuOCUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 63 | 4993E7FE22FD53BF001EEB63 /* MultilevelMenuOCUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MultilevelMenuOCUITests.m; sourceTree = ""; }; 64 | 4993E80022FD53BF001EEB63 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 65 | 4993E84D22FD5BC8001EEB63 /* MultilevelMenuBundle.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = MultilevelMenuBundle.bundle; sourceTree = ""; }; 66 | 4993E84F22FD5BC8001EEB63 /* MenuDataModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenuDataModel.swift; sourceTree = ""; }; 67 | 4993E85022FD5BC8001EEB63 /* MultilevelMenuOption.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultilevelMenuOption.swift; sourceTree = ""; }; 68 | 4993E85122FD5BC8001EEB63 /* MultilevelStyle2Menu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultilevelStyle2Menu.swift; sourceTree = ""; }; 69 | 4993E85222FD5BC8001EEB63 /* MenuMarco.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenuMarco.swift; sourceTree = ""; }; 70 | 4993E85322FD5BC8001EEB63 /* MultilevelMenuStyle1View.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultilevelMenuStyle1View.swift; sourceTree = ""; }; 71 | 4993E85422FD5BC8001EEB63 /* MultilevelMenuView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultilevelMenuView.swift; sourceTree = ""; }; 72 | 4993E85522FD5BC8001EEB63 /* MultilevelMenuStyle2View.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultilevelMenuStyle2View.swift; sourceTree = ""; }; 73 | 4993E85622FD5BC8001EEB63 /* MultilevelStlyeMenu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultilevelStlyeMenu.swift; sourceTree = ""; }; 74 | 4993E85722FD5BC8001EEB63 /* MultilevelStyle1Menu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultilevelStyle1Menu.swift; sourceTree = ""; }; 75 | 4993E86622FD7065001EEB63 /* businessType.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = businessType.json; path = ../../MultilevelMenuSwift/businessType.json; sourceTree = ""; }; 76 | /* End PBXFileReference section */ 77 | 78 | /* Begin PBXFrameworksBuildPhase section */ 79 | 4993E7D422FD53BD001EEB63 /* Frameworks */ = { 80 | isa = PBXFrameworksBuildPhase; 81 | buildActionMask = 2147483647; 82 | files = ( 83 | ); 84 | runOnlyForDeploymentPostprocessing = 0; 85 | }; 86 | 4993E7EC22FD53BF001EEB63 /* Frameworks */ = { 87 | isa = PBXFrameworksBuildPhase; 88 | buildActionMask = 2147483647; 89 | files = ( 90 | ); 91 | runOnlyForDeploymentPostprocessing = 0; 92 | }; 93 | 4993E7F722FD53BF001EEB63 /* Frameworks */ = { 94 | isa = PBXFrameworksBuildPhase; 95 | buildActionMask = 2147483647; 96 | files = ( 97 | ); 98 | runOnlyForDeploymentPostprocessing = 0; 99 | }; 100 | /* End PBXFrameworksBuildPhase section */ 101 | 102 | /* Begin PBXGroup section */ 103 | 4993E7CE22FD53BD001EEB63 = { 104 | isa = PBXGroup; 105 | children = ( 106 | 4993E84B22FD5BC8001EEB63 /* MultilevelMenu */, 107 | 4993E7D922FD53BD001EEB63 /* MultilevelMenuOC */, 108 | 4993E7F222FD53BF001EEB63 /* MultilevelMenuOCTests */, 109 | 4993E7FD22FD53BF001EEB63 /* MultilevelMenuOCUITests */, 110 | 4993E7D822FD53BD001EEB63 /* Products */, 111 | ); 112 | sourceTree = ""; 113 | }; 114 | 4993E7D822FD53BD001EEB63 /* Products */ = { 115 | isa = PBXGroup; 116 | children = ( 117 | 4993E7D722FD53BD001EEB63 /* MultilevelMenuOC.app */, 118 | 4993E7EF22FD53BF001EEB63 /* MultilevelMenuOCTests.xctest */, 119 | 4993E7FA22FD53BF001EEB63 /* MultilevelMenuOCUITests.xctest */, 120 | ); 121 | name = Products; 122 | sourceTree = ""; 123 | }; 124 | 4993E7D922FD53BD001EEB63 /* MultilevelMenuOC */ = { 125 | isa = PBXGroup; 126 | children = ( 127 | 4993E86622FD7065001EEB63 /* businessType.json */, 128 | 4993E7DA22FD53BD001EEB63 /* AppDelegate.h */, 129 | 4993E7DB22FD53BD001EEB63 /* AppDelegate.m */, 130 | 4993E7DD22FD53BD001EEB63 /* ViewController.h */, 131 | 4993E7DE22FD53BD001EEB63 /* ViewController.m */, 132 | 4993E7E022FD53BD001EEB63 /* Main.storyboard */, 133 | 4993E7E322FD53BF001EEB63 /* Assets.xcassets */, 134 | 4993E7E522FD53BF001EEB63 /* LaunchScreen.storyboard */, 135 | 4993E7E822FD53BF001EEB63 /* Info.plist */, 136 | 4993E7E922FD53BF001EEB63 /* main.m */, 137 | ); 138 | path = MultilevelMenuOC; 139 | sourceTree = ""; 140 | }; 141 | 4993E7F222FD53BF001EEB63 /* MultilevelMenuOCTests */ = { 142 | isa = PBXGroup; 143 | children = ( 144 | 4993E7F322FD53BF001EEB63 /* MultilevelMenuOCTests.m */, 145 | 4993E7F522FD53BF001EEB63 /* Info.plist */, 146 | ); 147 | path = MultilevelMenuOCTests; 148 | sourceTree = ""; 149 | }; 150 | 4993E7FD22FD53BF001EEB63 /* MultilevelMenuOCUITests */ = { 151 | isa = PBXGroup; 152 | children = ( 153 | 4993E7FE22FD53BF001EEB63 /* MultilevelMenuOCUITests.m */, 154 | 4993E80022FD53BF001EEB63 /* Info.plist */, 155 | ); 156 | path = MultilevelMenuOCUITests; 157 | sourceTree = ""; 158 | }; 159 | 4993E84B22FD5BC8001EEB63 /* MultilevelMenu */ = { 160 | isa = PBXGroup; 161 | children = ( 162 | 4993E84C22FD5BC8001EEB63 /* Resources */, 163 | 4993E84E22FD5BC8001EEB63 /* Source */, 164 | ); 165 | name = MultilevelMenu; 166 | path = ../../MultilevelMenu; 167 | sourceTree = ""; 168 | }; 169 | 4993E84C22FD5BC8001EEB63 /* Resources */ = { 170 | isa = PBXGroup; 171 | children = ( 172 | 4993E84D22FD5BC8001EEB63 /* MultilevelMenuBundle.bundle */, 173 | ); 174 | path = Resources; 175 | sourceTree = ""; 176 | }; 177 | 4993E84E22FD5BC8001EEB63 /* Source */ = { 178 | isa = PBXGroup; 179 | children = ( 180 | 4993E84F22FD5BC8001EEB63 /* MenuDataModel.swift */, 181 | 4993E85022FD5BC8001EEB63 /* MultilevelMenuOption.swift */, 182 | 4993E85122FD5BC8001EEB63 /* MultilevelStyle2Menu.swift */, 183 | 4993E85222FD5BC8001EEB63 /* MenuMarco.swift */, 184 | 4993E85322FD5BC8001EEB63 /* MultilevelMenuStyle1View.swift */, 185 | 4993E85422FD5BC8001EEB63 /* MultilevelMenuView.swift */, 186 | 4993E85522FD5BC8001EEB63 /* MultilevelMenuStyle2View.swift */, 187 | 4993E85622FD5BC8001EEB63 /* MultilevelStlyeMenu.swift */, 188 | 4993E85722FD5BC8001EEB63 /* MultilevelStyle1Menu.swift */, 189 | ); 190 | path = Source; 191 | sourceTree = ""; 192 | }; 193 | /* End PBXGroup section */ 194 | 195 | /* Begin PBXNativeTarget section */ 196 | 4993E7D622FD53BD001EEB63 /* MultilevelMenuOC */ = { 197 | isa = PBXNativeTarget; 198 | buildConfigurationList = 4993E80322FD53BF001EEB63 /* Build configuration list for PBXNativeTarget "MultilevelMenuOC" */; 199 | buildPhases = ( 200 | 4993E7D322FD53BD001EEB63 /* Sources */, 201 | 4993E7D422FD53BD001EEB63 /* Frameworks */, 202 | 4993E7D522FD53BD001EEB63 /* Resources */, 203 | ); 204 | buildRules = ( 205 | ); 206 | dependencies = ( 207 | ); 208 | name = MultilevelMenuOC; 209 | productName = MultilevelMenuOC; 210 | productReference = 4993E7D722FD53BD001EEB63 /* MultilevelMenuOC.app */; 211 | productType = "com.apple.product-type.application"; 212 | }; 213 | 4993E7EE22FD53BF001EEB63 /* MultilevelMenuOCTests */ = { 214 | isa = PBXNativeTarget; 215 | buildConfigurationList = 4993E80622FD53BF001EEB63 /* Build configuration list for PBXNativeTarget "MultilevelMenuOCTests" */; 216 | buildPhases = ( 217 | 4993E7EB22FD53BF001EEB63 /* Sources */, 218 | 4993E7EC22FD53BF001EEB63 /* Frameworks */, 219 | 4993E7ED22FD53BF001EEB63 /* Resources */, 220 | ); 221 | buildRules = ( 222 | ); 223 | dependencies = ( 224 | 4993E7F122FD53BF001EEB63 /* PBXTargetDependency */, 225 | ); 226 | name = MultilevelMenuOCTests; 227 | productName = MultilevelMenuOCTests; 228 | productReference = 4993E7EF22FD53BF001EEB63 /* MultilevelMenuOCTests.xctest */; 229 | productType = "com.apple.product-type.bundle.unit-test"; 230 | }; 231 | 4993E7F922FD53BF001EEB63 /* MultilevelMenuOCUITests */ = { 232 | isa = PBXNativeTarget; 233 | buildConfigurationList = 4993E80922FD53BF001EEB63 /* Build configuration list for PBXNativeTarget "MultilevelMenuOCUITests" */; 234 | buildPhases = ( 235 | 4993E7F622FD53BF001EEB63 /* Sources */, 236 | 4993E7F722FD53BF001EEB63 /* Frameworks */, 237 | 4993E7F822FD53BF001EEB63 /* Resources */, 238 | ); 239 | buildRules = ( 240 | ); 241 | dependencies = ( 242 | 4993E7FC22FD53BF001EEB63 /* PBXTargetDependency */, 243 | ); 244 | name = MultilevelMenuOCUITests; 245 | productName = MultilevelMenuOCUITests; 246 | productReference = 4993E7FA22FD53BF001EEB63 /* MultilevelMenuOCUITests.xctest */; 247 | productType = "com.apple.product-type.bundle.ui-testing"; 248 | }; 249 | /* End PBXNativeTarget section */ 250 | 251 | /* Begin PBXProject section */ 252 | 4993E7CF22FD53BD001EEB63 /* Project object */ = { 253 | isa = PBXProject; 254 | attributes = { 255 | LastUpgradeCheck = 1010; 256 | ORGANIZATIONNAME = forwor; 257 | TargetAttributes = { 258 | 4993E7D622FD53BD001EEB63 = { 259 | CreatedOnToolsVersion = 10.1; 260 | }; 261 | 4993E7EE22FD53BF001EEB63 = { 262 | CreatedOnToolsVersion = 10.1; 263 | TestTargetID = 4993E7D622FD53BD001EEB63; 264 | }; 265 | 4993E7F922FD53BF001EEB63 = { 266 | CreatedOnToolsVersion = 10.1; 267 | TestTargetID = 4993E7D622FD53BD001EEB63; 268 | }; 269 | }; 270 | }; 271 | buildConfigurationList = 4993E7D222FD53BD001EEB63 /* Build configuration list for PBXProject "MultilevelMenuOC" */; 272 | compatibilityVersion = "Xcode 9.3"; 273 | developmentRegion = en; 274 | hasScannedForEncodings = 0; 275 | knownRegions = ( 276 | en, 277 | Base, 278 | ); 279 | mainGroup = 4993E7CE22FD53BD001EEB63; 280 | productRefGroup = 4993E7D822FD53BD001EEB63 /* Products */; 281 | projectDirPath = ""; 282 | projectRoot = ""; 283 | targets = ( 284 | 4993E7D622FD53BD001EEB63 /* MultilevelMenuOC */, 285 | 4993E7EE22FD53BF001EEB63 /* MultilevelMenuOCTests */, 286 | 4993E7F922FD53BF001EEB63 /* MultilevelMenuOCUITests */, 287 | ); 288 | }; 289 | /* End PBXProject section */ 290 | 291 | /* Begin PBXResourcesBuildPhase section */ 292 | 4993E7D522FD53BD001EEB63 /* Resources */ = { 293 | isa = PBXResourcesBuildPhase; 294 | buildActionMask = 2147483647; 295 | files = ( 296 | 4993E7E722FD53BF001EEB63 /* LaunchScreen.storyboard in Resources */, 297 | 4993E85822FD5BC8001EEB63 /* MultilevelMenuBundle.bundle in Resources */, 298 | 4993E86722FD7065001EEB63 /* businessType.json in Resources */, 299 | 4993E7E422FD53BF001EEB63 /* Assets.xcassets in Resources */, 300 | 4993E7E222FD53BD001EEB63 /* Main.storyboard in Resources */, 301 | ); 302 | runOnlyForDeploymentPostprocessing = 0; 303 | }; 304 | 4993E7ED22FD53BF001EEB63 /* Resources */ = { 305 | isa = PBXResourcesBuildPhase; 306 | buildActionMask = 2147483647; 307 | files = ( 308 | ); 309 | runOnlyForDeploymentPostprocessing = 0; 310 | }; 311 | 4993E7F822FD53BF001EEB63 /* Resources */ = { 312 | isa = PBXResourcesBuildPhase; 313 | buildActionMask = 2147483647; 314 | files = ( 315 | ); 316 | runOnlyForDeploymentPostprocessing = 0; 317 | }; 318 | /* End PBXResourcesBuildPhase section */ 319 | 320 | /* Begin PBXSourcesBuildPhase section */ 321 | 4993E7D322FD53BD001EEB63 /* Sources */ = { 322 | isa = PBXSourcesBuildPhase; 323 | buildActionMask = 2147483647; 324 | files = ( 325 | 4993E85B22FD5BC8001EEB63 /* MultilevelStyle2Menu.swift in Sources */, 326 | 4993E85E22FD5BC8001EEB63 /* MultilevelMenuView.swift in Sources */, 327 | 4993E7DF22FD53BD001EEB63 /* ViewController.m in Sources */, 328 | 4993E7EA22FD53BF001EEB63 /* main.m in Sources */, 329 | 4993E85A22FD5BC8001EEB63 /* MultilevelMenuOption.swift in Sources */, 330 | 4993E86022FD5BC8001EEB63 /* MultilevelStlyeMenu.swift in Sources */, 331 | 4993E85F22FD5BC8001EEB63 /* MultilevelMenuStyle2View.swift in Sources */, 332 | 4993E86122FD5BC8001EEB63 /* MultilevelStyle1Menu.swift in Sources */, 333 | 4993E85922FD5BC8001EEB63 /* MenuDataModel.swift in Sources */, 334 | 4993E7DC22FD53BD001EEB63 /* AppDelegate.m in Sources */, 335 | 4993E85D22FD5BC8001EEB63 /* MultilevelMenuStyle1View.swift in Sources */, 336 | 4993E85C22FD5BC8001EEB63 /* MenuMarco.swift in Sources */, 337 | ); 338 | runOnlyForDeploymentPostprocessing = 0; 339 | }; 340 | 4993E7EB22FD53BF001EEB63 /* Sources */ = { 341 | isa = PBXSourcesBuildPhase; 342 | buildActionMask = 2147483647; 343 | files = ( 344 | 4993E7F422FD53BF001EEB63 /* MultilevelMenuOCTests.m in Sources */, 345 | ); 346 | runOnlyForDeploymentPostprocessing = 0; 347 | }; 348 | 4993E7F622FD53BF001EEB63 /* Sources */ = { 349 | isa = PBXSourcesBuildPhase; 350 | buildActionMask = 2147483647; 351 | files = ( 352 | 4993E7FF22FD53BF001EEB63 /* MultilevelMenuOCUITests.m in Sources */, 353 | ); 354 | runOnlyForDeploymentPostprocessing = 0; 355 | }; 356 | /* End PBXSourcesBuildPhase section */ 357 | 358 | /* Begin PBXTargetDependency section */ 359 | 4993E7F122FD53BF001EEB63 /* PBXTargetDependency */ = { 360 | isa = PBXTargetDependency; 361 | target = 4993E7D622FD53BD001EEB63 /* MultilevelMenuOC */; 362 | targetProxy = 4993E7F022FD53BF001EEB63 /* PBXContainerItemProxy */; 363 | }; 364 | 4993E7FC22FD53BF001EEB63 /* PBXTargetDependency */ = { 365 | isa = PBXTargetDependency; 366 | target = 4993E7D622FD53BD001EEB63 /* MultilevelMenuOC */; 367 | targetProxy = 4993E7FB22FD53BF001EEB63 /* PBXContainerItemProxy */; 368 | }; 369 | /* End PBXTargetDependency section */ 370 | 371 | /* Begin PBXVariantGroup section */ 372 | 4993E7E022FD53BD001EEB63 /* Main.storyboard */ = { 373 | isa = PBXVariantGroup; 374 | children = ( 375 | 4993E7E122FD53BD001EEB63 /* Base */, 376 | ); 377 | name = Main.storyboard; 378 | sourceTree = ""; 379 | }; 380 | 4993E7E522FD53BF001EEB63 /* LaunchScreen.storyboard */ = { 381 | isa = PBXVariantGroup; 382 | children = ( 383 | 4993E7E622FD53BF001EEB63 /* Base */, 384 | ); 385 | name = LaunchScreen.storyboard; 386 | sourceTree = ""; 387 | }; 388 | /* End PBXVariantGroup section */ 389 | 390 | /* Begin XCBuildConfiguration section */ 391 | 4993E80122FD53BF001EEB63 /* Debug */ = { 392 | isa = XCBuildConfiguration; 393 | buildSettings = { 394 | ALWAYS_SEARCH_USER_PATHS = NO; 395 | CLANG_ANALYZER_NONNULL = YES; 396 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 397 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 398 | CLANG_CXX_LIBRARY = "libc++"; 399 | CLANG_ENABLE_MODULES = YES; 400 | CLANG_ENABLE_OBJC_ARC = YES; 401 | CLANG_ENABLE_OBJC_WEAK = YES; 402 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 403 | CLANG_WARN_BOOL_CONVERSION = YES; 404 | CLANG_WARN_COMMA = YES; 405 | CLANG_WARN_CONSTANT_CONVERSION = YES; 406 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 407 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 408 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 409 | CLANG_WARN_EMPTY_BODY = YES; 410 | CLANG_WARN_ENUM_CONVERSION = YES; 411 | CLANG_WARN_INFINITE_RECURSION = YES; 412 | CLANG_WARN_INT_CONVERSION = YES; 413 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 414 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 415 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 416 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 417 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 418 | CLANG_WARN_STRICT_PROTOTYPES = YES; 419 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 420 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 421 | CLANG_WARN_UNREACHABLE_CODE = YES; 422 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 423 | CODE_SIGN_IDENTITY = "iPhone Developer"; 424 | COPY_PHASE_STRIP = NO; 425 | DEBUG_INFORMATION_FORMAT = dwarf; 426 | ENABLE_STRICT_OBJC_MSGSEND = YES; 427 | ENABLE_TESTABILITY = YES; 428 | GCC_C_LANGUAGE_STANDARD = gnu11; 429 | GCC_DYNAMIC_NO_PIC = NO; 430 | GCC_NO_COMMON_BLOCKS = YES; 431 | GCC_OPTIMIZATION_LEVEL = 0; 432 | GCC_PREPROCESSOR_DEFINITIONS = ( 433 | "DEBUG=1", 434 | "$(inherited)", 435 | ); 436 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 437 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 438 | GCC_WARN_UNDECLARED_SELECTOR = YES; 439 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 440 | GCC_WARN_UNUSED_FUNCTION = YES; 441 | GCC_WARN_UNUSED_VARIABLE = YES; 442 | IPHONEOS_DEPLOYMENT_TARGET = 12.1; 443 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 444 | MTL_FAST_MATH = YES; 445 | ONLY_ACTIVE_ARCH = YES; 446 | SDKROOT = iphoneos; 447 | }; 448 | name = Debug; 449 | }; 450 | 4993E80222FD53BF001EEB63 /* Release */ = { 451 | isa = XCBuildConfiguration; 452 | buildSettings = { 453 | ALWAYS_SEARCH_USER_PATHS = NO; 454 | CLANG_ANALYZER_NONNULL = YES; 455 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 456 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 457 | CLANG_CXX_LIBRARY = "libc++"; 458 | CLANG_ENABLE_MODULES = YES; 459 | CLANG_ENABLE_OBJC_ARC = YES; 460 | CLANG_ENABLE_OBJC_WEAK = YES; 461 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 462 | CLANG_WARN_BOOL_CONVERSION = YES; 463 | CLANG_WARN_COMMA = YES; 464 | CLANG_WARN_CONSTANT_CONVERSION = YES; 465 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 466 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 467 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 468 | CLANG_WARN_EMPTY_BODY = YES; 469 | CLANG_WARN_ENUM_CONVERSION = YES; 470 | CLANG_WARN_INFINITE_RECURSION = YES; 471 | CLANG_WARN_INT_CONVERSION = YES; 472 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 473 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 474 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 475 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 476 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 477 | CLANG_WARN_STRICT_PROTOTYPES = YES; 478 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 479 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 480 | CLANG_WARN_UNREACHABLE_CODE = YES; 481 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 482 | CODE_SIGN_IDENTITY = "iPhone Developer"; 483 | COPY_PHASE_STRIP = NO; 484 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 485 | ENABLE_NS_ASSERTIONS = NO; 486 | ENABLE_STRICT_OBJC_MSGSEND = YES; 487 | GCC_C_LANGUAGE_STANDARD = gnu11; 488 | GCC_NO_COMMON_BLOCKS = YES; 489 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 490 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 491 | GCC_WARN_UNDECLARED_SELECTOR = YES; 492 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 493 | GCC_WARN_UNUSED_FUNCTION = YES; 494 | GCC_WARN_UNUSED_VARIABLE = YES; 495 | IPHONEOS_DEPLOYMENT_TARGET = 12.1; 496 | MTL_ENABLE_DEBUG_INFO = NO; 497 | MTL_FAST_MATH = YES; 498 | SDKROOT = iphoneos; 499 | VALIDATE_PRODUCT = YES; 500 | }; 501 | name = Release; 502 | }; 503 | 4993E80422FD53BF001EEB63 /* Debug */ = { 504 | isa = XCBuildConfiguration; 505 | buildSettings = { 506 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 507 | CODE_SIGN_STYLE = Automatic; 508 | DEFINES_MODULE = YES; 509 | DEVELOPMENT_TEAM = RJUJXP82S4; 510 | INFOPLIST_FILE = MultilevelMenuOC/Info.plist; 511 | LD_RUNPATH_SEARCH_PATHS = ( 512 | "$(inherited)", 513 | "@executable_path/Frameworks", 514 | ); 515 | PRODUCT_BUNDLE_IDENTIFIER = shenzhiqiang.MultilevelMenuOC; 516 | PRODUCT_NAME = "$(TARGET_NAME)"; 517 | SWIFT_OBJC_BRIDGING_HEADER = ""; 518 | SWIFT_VERSION = 4.2; 519 | TARGETED_DEVICE_FAMILY = "1,2"; 520 | }; 521 | name = Debug; 522 | }; 523 | 4993E80522FD53BF001EEB63 /* Release */ = { 524 | isa = XCBuildConfiguration; 525 | buildSettings = { 526 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 527 | CODE_SIGN_STYLE = Automatic; 528 | DEFINES_MODULE = YES; 529 | DEVELOPMENT_TEAM = RJUJXP82S4; 530 | INFOPLIST_FILE = MultilevelMenuOC/Info.plist; 531 | LD_RUNPATH_SEARCH_PATHS = ( 532 | "$(inherited)", 533 | "@executable_path/Frameworks", 534 | ); 535 | PRODUCT_BUNDLE_IDENTIFIER = shenzhiqiang.MultilevelMenuOC; 536 | PRODUCT_NAME = "$(TARGET_NAME)"; 537 | SWIFT_OBJC_BRIDGING_HEADER = ""; 538 | SWIFT_VERSION = 4.2; 539 | TARGETED_DEVICE_FAMILY = "1,2"; 540 | }; 541 | name = Release; 542 | }; 543 | 4993E80722FD53BF001EEB63 /* Debug */ = { 544 | isa = XCBuildConfiguration; 545 | buildSettings = { 546 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 547 | BUNDLE_LOADER = "$(TEST_HOST)"; 548 | CODE_SIGN_STYLE = Automatic; 549 | DEVELOPMENT_TEAM = RJUJXP82S4; 550 | INFOPLIST_FILE = MultilevelMenuOCTests/Info.plist; 551 | LD_RUNPATH_SEARCH_PATHS = ( 552 | "$(inherited)", 553 | "@executable_path/Frameworks", 554 | "@loader_path/Frameworks", 555 | ); 556 | PRODUCT_BUNDLE_IDENTIFIER = shenzhiqiang.MultilevelMenuOCTests; 557 | PRODUCT_NAME = "$(TARGET_NAME)"; 558 | TARGETED_DEVICE_FAMILY = "1,2"; 559 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/MultilevelMenuOC.app/MultilevelMenuOC"; 560 | }; 561 | name = Debug; 562 | }; 563 | 4993E80822FD53BF001EEB63 /* Release */ = { 564 | isa = XCBuildConfiguration; 565 | buildSettings = { 566 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 567 | BUNDLE_LOADER = "$(TEST_HOST)"; 568 | CODE_SIGN_STYLE = Automatic; 569 | DEVELOPMENT_TEAM = RJUJXP82S4; 570 | INFOPLIST_FILE = MultilevelMenuOCTests/Info.plist; 571 | LD_RUNPATH_SEARCH_PATHS = ( 572 | "$(inherited)", 573 | "@executable_path/Frameworks", 574 | "@loader_path/Frameworks", 575 | ); 576 | PRODUCT_BUNDLE_IDENTIFIER = shenzhiqiang.MultilevelMenuOCTests; 577 | PRODUCT_NAME = "$(TARGET_NAME)"; 578 | TARGETED_DEVICE_FAMILY = "1,2"; 579 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/MultilevelMenuOC.app/MultilevelMenuOC"; 580 | }; 581 | name = Release; 582 | }; 583 | 4993E80A22FD53BF001EEB63 /* Debug */ = { 584 | isa = XCBuildConfiguration; 585 | buildSettings = { 586 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 587 | CODE_SIGN_STYLE = Automatic; 588 | DEVELOPMENT_TEAM = RJUJXP82S4; 589 | INFOPLIST_FILE = MultilevelMenuOCUITests/Info.plist; 590 | LD_RUNPATH_SEARCH_PATHS = ( 591 | "$(inherited)", 592 | "@executable_path/Frameworks", 593 | "@loader_path/Frameworks", 594 | ); 595 | PRODUCT_BUNDLE_IDENTIFIER = shenzhiqiang.MultilevelMenuOCUITests; 596 | PRODUCT_NAME = "$(TARGET_NAME)"; 597 | TARGETED_DEVICE_FAMILY = "1,2"; 598 | TEST_TARGET_NAME = MultilevelMenuOC; 599 | }; 600 | name = Debug; 601 | }; 602 | 4993E80B22FD53BF001EEB63 /* Release */ = { 603 | isa = XCBuildConfiguration; 604 | buildSettings = { 605 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 606 | CODE_SIGN_STYLE = Automatic; 607 | DEVELOPMENT_TEAM = RJUJXP82S4; 608 | INFOPLIST_FILE = MultilevelMenuOCUITests/Info.plist; 609 | LD_RUNPATH_SEARCH_PATHS = ( 610 | "$(inherited)", 611 | "@executable_path/Frameworks", 612 | "@loader_path/Frameworks", 613 | ); 614 | PRODUCT_BUNDLE_IDENTIFIER = shenzhiqiang.MultilevelMenuOCUITests; 615 | PRODUCT_NAME = "$(TARGET_NAME)"; 616 | TARGETED_DEVICE_FAMILY = "1,2"; 617 | TEST_TARGET_NAME = MultilevelMenuOC; 618 | }; 619 | name = Release; 620 | }; 621 | /* End XCBuildConfiguration section */ 622 | 623 | /* Begin XCConfigurationList section */ 624 | 4993E7D222FD53BD001EEB63 /* Build configuration list for PBXProject "MultilevelMenuOC" */ = { 625 | isa = XCConfigurationList; 626 | buildConfigurations = ( 627 | 4993E80122FD53BF001EEB63 /* Debug */, 628 | 4993E80222FD53BF001EEB63 /* Release */, 629 | ); 630 | defaultConfigurationIsVisible = 0; 631 | defaultConfigurationName = Release; 632 | }; 633 | 4993E80322FD53BF001EEB63 /* Build configuration list for PBXNativeTarget "MultilevelMenuOC" */ = { 634 | isa = XCConfigurationList; 635 | buildConfigurations = ( 636 | 4993E80422FD53BF001EEB63 /* Debug */, 637 | 4993E80522FD53BF001EEB63 /* Release */, 638 | ); 639 | defaultConfigurationIsVisible = 0; 640 | defaultConfigurationName = Release; 641 | }; 642 | 4993E80622FD53BF001EEB63 /* Build configuration list for PBXNativeTarget "MultilevelMenuOCTests" */ = { 643 | isa = XCConfigurationList; 644 | buildConfigurations = ( 645 | 4993E80722FD53BF001EEB63 /* Debug */, 646 | 4993E80822FD53BF001EEB63 /* Release */, 647 | ); 648 | defaultConfigurationIsVisible = 0; 649 | defaultConfigurationName = Release; 650 | }; 651 | 4993E80922FD53BF001EEB63 /* Build configuration list for PBXNativeTarget "MultilevelMenuOCUITests" */ = { 652 | isa = XCConfigurationList; 653 | buildConfigurations = ( 654 | 4993E80A22FD53BF001EEB63 /* Debug */, 655 | 4993E80B22FD53BF001EEB63 /* Release */, 656 | ); 657 | defaultConfigurationIsVisible = 0; 658 | defaultConfigurationName = Release; 659 | }; 660 | /* End XCConfigurationList section */ 661 | }; 662 | rootObject = 4993E7CF22FD53BD001EEB63 /* Project object */; 663 | } 664 | --------------------------------------------------------------------------------