diff --git a/DropdownMenu.xcodeproj/project.pbxproj b/DropdownMenu.xcodeproj/project.pbxproj index 6f79606..b831363 100644 --- a/DropdownMenu.xcodeproj/project.pbxproj +++ b/DropdownMenu.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 4A076B271DAA32BF004BCBE4 /* SectionHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A076B261DAA32BF004BCBE4 /* SectionHeader.swift */; }; AC28BA811D5BAB25004F1663 /* DropUpMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = AC28BA801D5BAB25004F1663 /* DropUpMenu.swift */; }; AC4C1D5C1CF8325B006E36F5 /* DropdownItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = AC4C1D5B1CF8325B006E36F5 /* DropdownItem.swift */; }; ACE6DB701CF74183005C6667 /* DropdownMenu.h in Headers */ = {isa = PBXBuildFile; fileRef = ACE6DB6F1CF74183005C6667 /* DropdownMenu.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -26,6 +27,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 4A076B261DAA32BF004BCBE4 /* SectionHeader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SectionHeader.swift; sourceTree = ""; }; AC28BA801D5BAB25004F1663 /* DropUpMenu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DropUpMenu.swift; sourceTree = ""; }; AC4C1D5B1CF8325B006E36F5 /* DropdownItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DropdownItem.swift; sourceTree = ""; }; ACE6DB6C1CF74183005C6667 /* DropdownMenu.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DropdownMenu.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -81,6 +83,7 @@ ACE6DBC01CF74256005C6667 /* DropdownMenu.swift */, AC28BA801D5BAB25004F1663 /* DropUpMenu.swift */, AC4C1D5B1CF8325B006E36F5 /* DropdownItem.swift */, + 4A076B261DAA32BF004BCBE4 /* SectionHeader.swift */, ACE6DB711CF74183005C6667 /* Info.plist */, ); path = DropdownMenu; @@ -208,6 +211,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 4A076B271DAA32BF004BCBE4 /* SectionHeader.swift in Sources */, ACE6DBC11CF74256005C6667 /* DropdownMenu.swift in Sources */, AC28BA811D5BAB25004F1663 /* DropUpMenu.swift in Sources */, AC4C1D5C1CF8325B006E36F5 /* DropdownItem.swift in Sources */, diff --git a/DropdownMenu.xcodeproj/xcuserdata/wangwei.xcuserdatad/xcschemes/xcschememanagement.plist b/DropdownMenu.xcodeproj/xcuserdata/wangwei.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..e75a1dd --- /dev/null +++ b/DropdownMenu.xcodeproj/xcuserdata/wangwei.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,19 @@ + + + + + SuppressBuildableAutocreation + + ACE6DB6B1CF74183005C6667 + + primary + + + ACE6DB751CF74183005C6667 + + primary + + + + + diff --git a/DropdownMenu.xcworkspace/xcuserdata/wangwei.xcuserdatad/UserInterfaceState.xcuserstate b/DropdownMenu.xcworkspace/xcuserdata/wangwei.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..174cc3f Binary files /dev/null and b/DropdownMenu.xcworkspace/xcuserdata/wangwei.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/DropdownMenu.xcworkspace/xcuserdata/wangwei.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/DropdownMenu.xcworkspace/xcuserdata/wangwei.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000..ed9a9b4 --- /dev/null +++ b/DropdownMenu.xcworkspace/xcuserdata/wangwei.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,5 @@ + + + diff --git a/DropdownMenu/DropdownItem.swift b/DropdownMenu/DropdownItem.swift index f999d4a..f4c62a6 100644 --- a/DropdownMenu/DropdownItem.swift +++ b/DropdownMenu/DropdownItem.swift @@ -26,3 +26,13 @@ open class DropdownItem { self.accessoryImage = accessoryImage } } + +public struct DropdownSection { + public var sectionIdentifier: String + public var items: [DropdownItem] + + public init (sectionIdentifier: String, items: [DropdownItem]) { + self.items = items + self.sectionIdentifier = sectionIdentifier + } +} diff --git a/DropdownMenu/DropdownMenu.swift b/DropdownMenu/DropdownMenu.swift index f67a71c..e3c1d21 100644 --- a/DropdownMenu/DropdownMenu.swift +++ b/DropdownMenu/DropdownMenu.swift @@ -22,8 +22,8 @@ public extension DropdownMenuDelegate { open class DropdownMenu: UIView { fileprivate weak var navigationController: UINavigationController! - fileprivate var items: [DropdownItem] = [] - fileprivate var selectedRow: Int + fileprivate var sections: [DropdownSection] = [] + fileprivate var selectedIndexPath: IndexPath open var tableView: UITableView! fileprivate var barCoverView: UIView! fileprivate var isShow = false @@ -37,6 +37,7 @@ open class DropdownMenu: UIView { open var backgroudBeginColor: UIColor = UIColor.black.withAlphaComponent(0) open var backgroudEndColor = UIColor(white: 0, alpha: 0.4) open var rowHeight: CGFloat = 50 + open var sectionHeaderHeight: CGFloat = 44 open var tableViewHeight: CGFloat = 0 open var defaultBottonMargin: CGFloat = 150 open var textColor: UIColor = UIColor(red: 56.0/255.0, green: 56.0/255.0, blue: 56.0/255.0, alpha: 1.0) @@ -44,6 +45,10 @@ open class DropdownMenu: UIView { open var tableViewBackgroundColor: UIColor = UIColor(red: 242.0/255.0, green: 242.0/255.0, blue: 242.0/255.0, alpha: 1.0) open var tableViewSeperatorColor = UIColor(red: 217.0/255.0, green: 217.0/255.0, blue: 217.0/255.0, alpha: 1.0) open var displaySelected: Bool = true + open var displaySectionHeader: Bool = false + + // section header sytle + open var sectionHeaderStyle: SectionHeaderStyle = SectionHeaderStyle() required public init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") @@ -51,8 +56,8 @@ open class DropdownMenu: UIView { public init(navigationController: UINavigationController, items: [DropdownItem], selectedRow: Int = 0) { self.navigationController = navigationController - self.items = items - self.selectedRow = selectedRow + self.sections = [DropdownSection(sectionIdentifier: "", items: items)] + self.selectedIndexPath = IndexPath(row: selectedRow, section: 0) super.init(frame: CGRect.zero) @@ -63,6 +68,22 @@ open class DropdownMenu: UIView { NotificationCenter.default.addObserver(self, selector: #selector(self.updateForOrientationChange(_:)), name: NSNotification.Name.UIApplicationWillChangeStatusBarOrientation, object: nil) } + + public init(navigationController: UINavigationController, sections: [DropdownSection], selectedIndexPath: IndexPath = IndexPath(row: 0, section: 0), dispalySectionHeader: Bool = true, sectionHeaderStyle: SectionHeaderStyle = SectionHeaderStyle()) { + self.navigationController = navigationController + self.sections = sections + self.selectedIndexPath = selectedIndexPath + self.displaySectionHeader = dispalySectionHeader + + super.init(frame: CGRect.zero) + + clipsToBounds = true + setupGestureView() + setupTableView() + setupTopSeperatorView() + + NotificationCenter.default.addObserver(self, selector: #selector(self.updateForOrientationChange(_:)), name: NSNotification.Name.UIApplicationWillChangeStatusBarOrientation, object: nil) + } deinit { NotificationCenter.default.removeObserver(self) @@ -110,7 +131,7 @@ open class DropdownMenu: UIView { } fileprivate func setupTableView() { - tableViewHeight = CGFloat(items.count) * rowHeight + tableViewHeight = tableviewHeight() let navigationBarFrame: CGRect = navigationController.navigationBar.frame let maxHeight = navigationController.view.frame.height - navigationBarFrame.height + navigationBarFrame.origin.y - defaultBottonMargin if tableViewHeight > maxHeight { @@ -145,6 +166,17 @@ open class DropdownMenu: UIView { barCoverView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(hideMenu))) } + fileprivate func tableviewHeight() -> CGFloat { + var height: CGFloat = 0 + if displaySectionHeader { + height += sectionHeaderHeight * CGFloat(sections.count) + } + for section in sections { + height += CGFloat(section.items.count) * rowHeight + } + return height + } + open func showMenu(isOnNavigaitionView: Bool = false) { if isShow { hideMenu() @@ -201,15 +233,19 @@ open class DropdownMenu: UIView { } extension DropdownMenu: UITableViewDataSource { + public func numberOfSections(in tableView: UITableView) -> Int { + return sections.count + } + public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return items.count + return sections[section].items.count } public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { if let customCell = delegate?.dropdownMenu(self, cellForRowAt: indexPath) { return customCell } - let item = items[(indexPath as NSIndexPath).row] + let item = sections[indexPath.section].items[indexPath.row] let cell = UITableViewCell(style: .default, reuseIdentifier: "dropdownMenuCell") switch item.style { @@ -229,7 +265,7 @@ extension DropdownMenu: UITableViewDataSource { cell.textLabel?.text = item.title cell.tintColor = highlightColor - if displaySelected && (indexPath as NSIndexPath).row == selectedRow { + if displaySelected && indexPath == selectedIndexPath { cell.accessoryType = .checkmark } else { cell.accessoryType = .none @@ -241,15 +277,19 @@ extension DropdownMenu: UITableViewDataSource { return cell } + + public func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { + return displaySectionHeader ? sections[section].sectionIdentifier : nil + } } extension DropdownMenu: UITableViewDelegate { public func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return rowHeight } - + public func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { - return CGFloat.leastNormalMagnitude + return displaySectionHeader ? sectionHeaderHeight : CGFloat.leastNormalMagnitude } public func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat { @@ -258,11 +298,11 @@ extension DropdownMenu: UITableViewDelegate { public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { if displaySelected { - let item = items[(indexPath as NSIndexPath).row] + let item = sections[indexPath.section].items[indexPath.row] if item.accessoryImage == nil { - let previousSelectedcell = tableView.cellForRow(at: IndexPath(row: selectedRow, section: 0)) + let previousSelectedcell = tableView.cellForRow(at: selectedIndexPath) previousSelectedcell?.accessoryType = .none - selectedRow = (indexPath as NSIndexPath).row + selectedIndexPath = indexPath let cell = tableView.cellForRow(at: indexPath) cell?.accessoryType = .checkmark } @@ -271,4 +311,10 @@ extension DropdownMenu: UITableViewDelegate { hideMenu(isSelectAction: true) delegate?.dropdownMenu(self, didSelectRowAt: indexPath) } + + public func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { + let sectionHeader = SectionHeader(style: sectionHeaderStyle) + sectionHeader.titleLabel.text = sections[section].sectionIdentifier + return sectionHeader + } } diff --git a/DropdownMenu/SectionHeader.swift b/DropdownMenu/SectionHeader.swift new file mode 100644 index 0000000..1763574 --- /dev/null +++ b/DropdownMenu/SectionHeader.swift @@ -0,0 +1,70 @@ +// +// SectionHeader.swift +// DropdownMenu +// +// Created by WangWei on 2016/10/9. +// Copyright © 2016年 teambition. All rights reserved. +// + +open class SectionHeader: UIView { + var titleLabel: UILabel! + var style: SectionHeaderStyle = SectionHeaderStyle() + + convenience init(style: SectionHeaderStyle) { + self.init(frame: CGRect.zero) + self.style = style + commonInit() + } + + override init(frame: CGRect) { + super.init(frame: frame) + } + + required public init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + } + + func commonInit() { + titleLabel = UILabel() + titleLabel.translatesAutoresizingMaskIntoConstraints = false + titleLabel.font = style.font + titleLabel.textColor = style.textColor + backgroundColor = style.backgroundColor + addSubview(titleLabel) + updateTitleLabelConstraint() + } + + func updateTitleLabelConstraint() { + let constraints = NSLayoutConstraint.constraints(withVisualFormat: "H:|-leftPadding-[titleLabel]->=20-|", options: [], metrics: ["leftPadding": style.leftPadding], views: ["titleLabel": titleLabel]) + addConstraints(constraints) + if style.shouldTitleCenterVertically { + let centerY = NSLayoutConstraint(item: titleLabel, attribute: .centerY, relatedBy: .equal, toItem: self, attribute: .centerY, multiplier: 1.0, constant: 0) + addConstraint(centerY) + } else { + let vConstraints = NSLayoutConstraint(item: titleLabel, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1.0, constant: style.bottomPadding) + addConstraint(vConstraints) + } + } +} + + +public struct SectionHeaderStyle { + + /// leftPadding for title label, default is `20` + public var leftPadding: CGFloat = 20 + /// bottom padding for title label, default is `10`, + /// will be ignored when `shouldTitleCenterVertically` is `true` + public var bottomPadding: CGFloat = 10 + /// should title label center in axis Y, default is `true` + public var shouldTitleCenterVertically: Bool = true + + /// title label font, default is `UIFont.systemFont(ofSize: 14)` + public var font: UIFont = UIFont.systemFont(ofSize: 14) + /// title label textColor, default is A6A6A6 + public var textColor: UIColor = UIColor(red: 166.0/255.0, green: 166.0/255.0, blue: 166.0/255.0, alpha: 1.0) + /// backgroundColor for header, default is F2F2F2 + public var backgroundColor: UIColor = UIColor(red: 242.0/255.0, green: 242.0/255.0, blue: 242.0/255.0, alpha: 1.0) + + public init() { + } +} diff --git a/DropdownMenuDemo/DropdownMenuDemo.xcodeproj/xcuserdata/wangwei.xcuserdatad/xcschemes/xcschememanagement.plist b/DropdownMenuDemo/DropdownMenuDemo.xcodeproj/xcuserdata/wangwei.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..5cb33ec --- /dev/null +++ b/DropdownMenuDemo/DropdownMenuDemo.xcodeproj/xcuserdata/wangwei.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,24 @@ + + + + + SuppressBuildableAutocreation + + ACE6DB8E1CF741F6005C6667 + + primary + + + ACE6DBA21CF741F6005C6667 + + primary + + + ACE6DBAD1CF741F6005C6667 + + primary + + + + + diff --git a/DropdownMenuDemo/DropdownMenuDemo/Base.lproj/Main.storyboard b/DropdownMenuDemo/DropdownMenuDemo/Base.lproj/Main.storyboard index 725348e..b44faa5 100644 --- a/DropdownMenuDemo/DropdownMenuDemo/Base.lproj/Main.storyboard +++ b/DropdownMenuDemo/DropdownMenuDemo/Base.lproj/Main.storyboard @@ -1,5 +1,5 @@ - - + + @@ -18,15 +18,22 @@ - + + @@ -42,6 +49,9 @@ + + + @@ -79,7 +89,7 @@ - + diff --git a/DropdownMenuDemo/DropdownMenuDemo/ViewController.swift b/DropdownMenuDemo/DropdownMenuDemo/ViewController.swift index 2a41a28..94efb7e 100644 --- a/DropdownMenuDemo/DropdownMenuDemo/ViewController.swift +++ b/DropdownMenuDemo/DropdownMenuDemo/ViewController.swift @@ -10,8 +10,12 @@ import UIKit import DropdownMenu class ViewController: UIViewController { + @IBOutlet weak var sectionSwitch: UISwitch! + + var showSection: Bool = true var selectedRow: Int = 0 - var items: [DropdownItem]! + var selectedIndexPath: IndexPath = IndexPath(row: 0, section: 0) + var items: [[DropdownItem]]! override func viewDidLoad() { super.viewDidLoad() @@ -21,7 +25,6 @@ class ViewController: UIViewController { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } - @IBAction func showMenu(_ sender: UIBarButtonItem) { let item1 = DropdownItem(title: "NO Image") @@ -29,10 +32,19 @@ class ViewController: UIViewController { let item3 = DropdownItem(image: UIImage(named: "post")!, title: "Post", style: .highlight) let item4 = DropdownItem(image: UIImage(named: "post")!, title: "Event", style: .highlight, accessoryImage: UIImage(named: "accessory")!) - items = [item1, item2, item3, item4] - let menuView = DropdownMenu(navigationController: navigationController!, items: items, selectedRow: selectedRow) - menuView.delegate = self - menuView.showMenu() + let section0 = DropdownSection(sectionIdentifier: "Teambition", items: [item1, item2]) + let section1 = DropdownSection(sectionIdentifier: "Space", items: [item3, item4]) + + var menuView: DropdownMenu? + if showSection { + items = [[item1, item2], [item3, item4]] + menuView = DropdownMenu(navigationController: navigationController!, sections: [section0, section1], selectedIndexPath: selectedIndexPath) + } else { + items = [[item1, item2, item3, item4]] + menuView = DropdownMenu(navigationController: navigationController!, items: [item1, item2, item3, item4], selectedRow: selectedRow) + } + menuView?.delegate = self + menuView?.showMenu() } @IBAction func dropUpAction(_ sender: UIBarButtonItem) { @@ -41,21 +53,27 @@ class ViewController: UIViewController { let item3 = DropdownItem(image: UIImage(named: "post")!, title: "Post", style: .highlight) let item4 = DropdownItem(image: UIImage(named: "post")!, title: "Event", style: .highlight, accessoryImage: UIImage(named: "accessory")!) - items = [item1, item2, item3, item4] - let menuView = DropUpMenu(items: items, selectedRow: 0, bottomOffsetY: self.tabBarController?.tabBar.frame.height ?? 0) + let data = [item1, item2, item3, item4] + items = [data] + let menuView = DropUpMenu(items: data, selectedRow: 0, bottomOffsetY: self.tabBarController?.tabBar.frame.height ?? 0) menuView.delegate = self menuView.showMenu() } + + @IBAction func sectionSwitchValueChanged(_ sender: AnyObject) { + showSection = sectionSwitch.isOn + } } extension ViewController: DropdownMenuDelegate { func dropdownMenu(_ dropdownMenu: DropdownMenu, didSelectRowAt indexPath: IndexPath) { - print("DropdownMenu didselect \(indexPath.row) text:\(items[indexPath.row].title)") + selectedIndexPath = indexPath + print("DropdownMenu didselect \(indexPath.row) text:\(items[indexPath.section][indexPath.row].title)") if indexPath.row != items.count - 1 { self.selectedRow = indexPath.row } - let alertConroller = UIAlertController(title: "Nice", message: "You choose \(items[indexPath.row].title)", preferredStyle: .alert) + let alertConroller = UIAlertController(title: "Nice", message: "You choose \(items[indexPath.section][indexPath.row].title)", preferredStyle: .alert) let okAction = UIAlertAction(title: "OK", style: .cancel, handler: nil) alertConroller.addAction(okAction) present(alertConroller, animated: true) { @@ -66,7 +84,7 @@ extension ViewController: DropdownMenuDelegate { extension ViewController: DropUpMenuDelegate { func dropUpMenu(_ dropUpMenu: DropUpMenu, didSelectRowAt indexPath: IndexPath) { - let alertConroller = UIAlertController(title: "Nice", message: "DropUpMenu didselect \(indexPath.row) text:\(items[indexPath.row].title)", preferredStyle: .alert) + let alertConroller = UIAlertController(title: "Nice", message: "DropUpMenu didselect \(indexPath.row) text:\(items[indexPath.section][indexPath.row].title)", preferredStyle: .alert) let okAction = UIAlertAction(title: "OK", style: .cancel, handler: nil) alertConroller.addAction(okAction) present(alertConroller, animated: true) {