Skip to content

Commit

Permalink
support dropUp menu form bottom
Browse files Browse the repository at this point in the history
  • Loading branch information
Suric zhang committed Aug 11, 2016
1 parent cf3994f commit 144a383
Show file tree
Hide file tree
Showing 7 changed files with 417 additions and 24 deletions.
4 changes: 4 additions & 0 deletions DropdownMenu.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
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, ); }; };
ACE6DB771CF74183005C6667 /* DropdownMenu.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ACE6DB6C1CF74183005C6667 /* DropdownMenu.framework */; };
Expand All @@ -25,6 +26,7 @@
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
AC28BA801D5BAB25004F1663 /* DropUpMenu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DropUpMenu.swift; sourceTree = "<group>"; };
AC4C1D5B1CF8325B006E36F5 /* DropdownItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DropdownItem.swift; sourceTree = "<group>"; };
ACE6DB6C1CF74183005C6667 /* DropdownMenu.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DropdownMenu.framework; sourceTree = BUILT_PRODUCTS_DIR; };
ACE6DB6F1CF74183005C6667 /* DropdownMenu.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DropdownMenu.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -77,6 +79,7 @@
children = (
ACE6DB6F1CF74183005C6667 /* DropdownMenu.h */,
ACE6DBC01CF74256005C6667 /* DropdownMenu.swift */,
AC28BA801D5BAB25004F1663 /* DropUpMenu.swift */,
AC4C1D5B1CF8325B006E36F5 /* DropdownItem.swift */,
ACE6DB711CF74183005C6667 /* Info.plist */,
);
Expand Down Expand Up @@ -201,6 +204,7 @@
buildActionMask = 2147483647;
files = (
ACE6DBC11CF74256005C6667 /* DropdownMenu.swift in Sources */,
AC28BA811D5BAB25004F1663 /* DropUpMenu.swift in Sources */,
AC4C1D5C1CF8325B006E36F5 /* DropdownItem.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,96 @@
<Bucket
type = "0"
version = "2.0">
<Breakpoints>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.ExceptionBreakpoint">
<BreakpointContent
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
scope = "0"
stopOnStyle = "0">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "DropdownMenu/DropUpMenu.swift"
timestampString = "492575779.702114"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "29"
endingLineNumber = "29"
landmarkName = "dropUpMenu(_:didSelectRowAtIndexPath:)"
landmarkType = "5">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "DropdownMenu/DropUpMenu.swift"
timestampString = "492577289.049253"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "241"
endingLineNumber = "241"
landmarkName = "tableView(_:didSelectRowAtIndexPath:)"
landmarkType = "5">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "DropdownMenu/DropUpMenu.swift"
timestampString = "492576784.251824"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "168"
endingLineNumber = "168"
landmarkName = "hideMenu()"
landmarkType = "5">
<Locations>
<Location
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
symbolName = "DropdownMenu.DropUpMenu.hideMenu () -&gt; ()"
moduleName = "DropdownMenu"
usesParentBreakpointCondition = "Yes"
urlString = "file:///Users/zhangxiaolian/Work/Suric-Open-Source/DropdownMenu/DropdownMenu/DropUpMenu.swift"
timestampString = "492576281.192695"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "157"
endingLineNumber = "157"
offsetFromSymbolStart = "15">
</Location>
<Location
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
symbolName = "DropdownMenu.DropUpMenu.(hideMenu () -&gt; ()).(closure #1)"
moduleName = "DropdownMenu"
usesParentBreakpointCondition = "Yes"
urlString = "file:///Users/zhangxiaolian/Work/Suric-Open-Source/DropdownMenu/DropdownMenu/DropUpMenu.swift"
timestampString = "492576281.19287"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "158"
endingLineNumber = "158"
offsetFromSymbolStart = "15">
</Location>
</Locations>
</BreakpointContent>
</BreakpointProxy>
</Breakpoints>
</Bucket>
256 changes: 256 additions & 0 deletions DropdownMenu/DropUpMenu.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
//
// DropUpMenu.swift
// DropUpMenu
//
// Created by Suric on 16/8/11.
// Copyright © 2016年 teambition. All rights reserved.
//

//
// DropUpMenu.swift
// DropUpMenu
//
// Created by Suric on 16/5/26.
// Copyright © 2016年 teambition. All rights reserved.
//

import UIKit

public protocol DropUpMenuDelegate: class {
func dropUpMenu(dropUpMenu: DropUpMenu, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell?
func dropUpMenu(dropUpMenu: DropUpMenu, didSelectRowAtIndexPath indexPath: NSIndexPath)
}

public extension DropUpMenuDelegate {
func dropUpMenu(dropUpMenu: DropUpMenu, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell? {
return nil
}

func dropUpMenu(dropUpMenu: DropUpMenu, didSelectRowAtIndexPath indexPath: NSIndexPath) {
}
}

private let screenRect = UIScreen.mainScreen().bounds

public class DropUpMenu: UIView {
private var items: [DropdownItem] = []
private var selectedRow: Int
public var tableView: UITableView!
private var barCoverView: UIView!
private var isShow = false
private var addedWindow: UIWindow?
private var windowRootView: UIView?
private lazy var tapGestureRecognizer: UITapGestureRecognizer = {
return UITapGestureRecognizer(target: self, action: #selector(self.hideMenu))
}()

public weak var delegate: DropUpMenuDelegate?
public var animateDuration: NSTimeInterval = 0.25
public var backgroudBeginColor: UIColor = UIColor.blackColor().colorWithAlphaComponent(0)
public var backgroudEndColor = UIColor(white: 0, alpha: 0.4)
public var rowHeight: CGFloat = 50
public var tableViewHeight: CGFloat = 0
public var defaultBottonMargin: CGFloat = 150
public var textColor: UIColor = UIColor(red: 56.0/255.0, green: 56.0/255.0, blue: 56.0/255.0, alpha: 1.0)
public var highlightColor: UIColor = UIColor(red: 3.0/255.0, green: 169.0/255.0, blue: 244.0/255.0, alpha: 1.0)
public var tableViewBackgroundColor: UIColor = UIColor(red: 242.0/255.0, green: 242.0/255.0, blue: 242.0/255.0, alpha: 1.0)
public var tableViewSeperatorColor = UIColor(red: 217.0/255.0, green: 217.0/255.0, blue: 217.0/255.0, alpha: 1.0)
public var displaySelected: Bool = true
public var bottomOffsetY: CGFloat = 0

required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

public init(items: [DropdownItem], selectedRow: Int = 0, bottomOffsetY: CGFloat = 0) {
self.items = items
self.selectedRow = selectedRow
self.bottomOffsetY = bottomOffsetY

let frame = CGRect(x: 0, y: 0, width: screenRect.width, height: screenRect.height - bottomOffsetY)
super.init(frame: frame)

clipsToBounds = true
setupGestureView()
setupTableView()
}

private func setupGestureView() {
let gestureView = UIView()
gestureView.backgroundColor = UIColor.clearColor()
addSubview(gestureView)
gestureView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activateConstraints([NSLayoutConstraint.init(item: gestureView, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1.0, constant: 0)])
NSLayoutConstraint.activateConstraints([NSLayoutConstraint.init(item: gestureView, attribute: .Bottom, relatedBy: .Equal, toItem: self, attribute: .Bottom, multiplier: 1.0, constant: 0)])
NSLayoutConstraint.activateConstraints([NSLayoutConstraint.init(item: gestureView, attribute: .Left, relatedBy: .Equal, toItem: self, attribute: .Left, multiplier: 1.0, constant: 0)])
NSLayoutConstraint.activateConstraints([NSLayoutConstraint.init(item: gestureView, attribute: .Right, relatedBy: .Equal, toItem: self, attribute: .Right, multiplier: 1.0, constant: 0)])

gestureView.addGestureRecognizer(tapGestureRecognizer)
}

private func setupTopSeperatorView() {
let seperatorView = UIView()
seperatorView.backgroundColor = tableViewSeperatorColor
addSubview(seperatorView)
seperatorView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activateConstraints([NSLayoutConstraint.init(item: seperatorView, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1.0, constant: 0)])
NSLayoutConstraint.activateConstraints([NSLayoutConstraint.init(item: seperatorView, attribute: .Left, relatedBy: .Equal, toItem: self, attribute: .Left, multiplier: 1.0, constant: 0)])
NSLayoutConstraint.activateConstraints([NSLayoutConstraint.init(item: seperatorView, attribute: .Right, relatedBy: .Equal, toItem: self, attribute: .Right, multiplier: 1.0, constant: 0)])
NSLayoutConstraint.activateConstraints([NSLayoutConstraint.init(item: seperatorView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 0.5)])
}

private func setupTableView() {
tableViewHeight = CGFloat(items.count) * rowHeight
let maxHeight = UIScreen.mainScreen().bounds.height - bottomOffsetY
if tableViewHeight > maxHeight {
tableViewHeight = maxHeight
}

tableView = UITableView(frame: CGRect.zero, style: .Grouped)
tableView.separatorColor = tableViewSeperatorColor
tableView.backgroundColor = tableViewBackgroundColor
tableView?.delegate = self
tableView?.dataSource = self
addSubview(tableView)
tableView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activateConstraints([NSLayoutConstraint.init(item: tableView, attribute: .Bottom, relatedBy: .Equal, toItem: self, attribute: .Bottom, multiplier: 1.0, constant:0)])
NSLayoutConstraint.activateConstraints([NSLayoutConstraint.init(item: tableView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: tableViewHeight)])
NSLayoutConstraint.activateConstraints([NSLayoutConstraint.init(item: tableView, attribute: .Left, relatedBy: .Equal, toItem: self, attribute: .Left, multiplier: 1.0, constant: 0)])
NSLayoutConstraint.activateConstraints([NSLayoutConstraint.init(item: tableView, attribute: .Right, relatedBy: .Equal, toItem: self, attribute: .Right, multiplier: 1.0, constant: 0)])
}

private func setupBottomCoverView(onView: UIView) {
barCoverView = UIView()
barCoverView.backgroundColor = UIColor.clearColor()
barCoverView.translatesAutoresizingMaskIntoConstraints = false
onView.addSubview(barCoverView)
NSLayoutConstraint.activateConstraints([NSLayoutConstraint.init(item: barCoverView, attribute: .Bottom, relatedBy: .Equal, toItem: onView, attribute: .Bottom, multiplier: 1.0, constant: 0)])
NSLayoutConstraint.activateConstraints([NSLayoutConstraint.init(item: barCoverView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: bottomOffsetY)])
NSLayoutConstraint.activateConstraints([NSLayoutConstraint.init(item: barCoverView, attribute: .Left, relatedBy: .Equal, toItem: onView, attribute: .Left, multiplier: 1.0, constant: 0)])
NSLayoutConstraint.activateConstraints([NSLayoutConstraint.init(item: barCoverView, attribute: .Right, relatedBy: .Equal, toItem: onView, attribute: .Right, multiplier: 1.0, constant: 0)])
barCoverView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(hideMenu)))
}

public func showMenu() {
if isShow {
hideMenu()
return
}
isShow = true

if let rootView = UIApplication.sharedApplication().keyWindow {
windowRootView = rootView
} else {
addedWindow = UIWindow(frame: UIScreen.mainScreen().bounds)
addedWindow?.rootViewController = UIViewController()
addedWindow?.hidden = false
addedWindow?.makeKeyAndVisible()
windowRootView = addedWindow!
}
setupBottomCoverView(windowRootView!)
windowRootView?.addSubview(self)

translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activateConstraints([NSLayoutConstraint.init(item: self, attribute: .Top, relatedBy: .Equal, toItem: windowRootView, attribute: .Top, multiplier: 1.0, constant: 0)])
NSLayoutConstraint.activateConstraints([NSLayoutConstraint.init(item: self, attribute: .Bottom, relatedBy: .Equal, toItem: windowRootView, attribute: .Bottom, multiplier: 1.0, constant: -bottomOffsetY)])
NSLayoutConstraint.activateConstraints([NSLayoutConstraint.init(item: self, attribute: .Left, relatedBy: .Equal, toItem: windowRootView, attribute: .Left, multiplier: 1.0, constant: 0)])
NSLayoutConstraint.activateConstraints([NSLayoutConstraint.init(item: self, attribute: .Right, relatedBy: .Equal, toItem: windowRootView, attribute: .Right, multiplier: 1.0, constant: 0)])

backgroundColor = backgroudBeginColor
self.tableView.frame.origin.y = screenRect.height - bottomOffsetY
UIView.animateWithDuration(animateDuration, delay: 0, options: UIViewAnimationOptions(rawValue: 7<<16), animations: {
self.backgroundColor = self.backgroudEndColor
self.tableView.frame.origin.y = screenRect.height - self.bottomOffsetY - self.tableViewHeight
}, completion: nil)
}

public func hideMenu() {
UIView.animateWithDuration(animateDuration, animations: {
self.backgroundColor = self.backgroudBeginColor
self.tableView.frame.origin.y = screenRect.height - self.bottomOffsetY
}) { (finished) in
self.barCoverView.removeFromSuperview()
self.removeFromSuperview()
self.isShow = false

if let _ = self.addedWindow {
self.addedWindow?.hidden = true
UIApplication.sharedApplication().keyWindow?.makeKeyWindow()
}
}
}
}

extension DropUpMenu: UITableViewDataSource {
public func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}

public func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return rowHeight
}

public func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if let customCell = delegate?.dropUpMenu(self, cellForRowAtIndexPath: indexPath) {
return customCell
}
let item = items[indexPath.row]
let cell = UITableViewCell(style: .Default, reuseIdentifier: "dropUpMenuCell")

switch item.style {
case .Default:
cell.textLabel?.textColor = textColor
if let image = item.image {
cell.imageView?.image = image
}
case .Highlight:
cell.textLabel?.textColor = highlightColor
if let image = item.image {
let highlightImage = image.imageWithRenderingMode(.AlwaysTemplate)
cell.imageView?.image = highlightImage
cell.imageView?.tintColor = highlightColor
}
}

cell.textLabel?.text = item.title
cell.tintColor = highlightColor
if displaySelected && indexPath.row == selectedRow {
cell.accessoryType = .Checkmark
} else {
cell.accessoryType = .None
}

if let accesoryImage = item.accessoryImage {
cell.accessoryView = UIImageView(image: accesoryImage)
}

return cell
}
}

extension DropUpMenu: UITableViewDelegate {
public func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return CGFloat.min
}

public func tableView(tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return CGFloat.min
}

public func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if displaySelected {
let item = items[indexPath.row]
if item.accessoryImage == nil {
let previousSelectedcell = tableView.cellForRowAtIndexPath(NSIndexPath(forRow: selectedRow, inSection: 0))
previousSelectedcell?.accessoryType = .None
selectedRow = indexPath.row
let cell = tableView.cellForRowAtIndexPath(indexPath)
cell?.accessoryType = .Checkmark
}
}
tableView.deselectRowAtIndexPath(indexPath, animated: true)
hideMenu()
delegate?.dropUpMenu(self, didSelectRowAtIndexPath: indexPath)
}
}

Loading

0 comments on commit 144a383

Please sign in to comment.