Skip to content

Commit

Permalink
Merge pull request #18 from FranklinSamboni/dropdown-toggle
Browse files Browse the repository at this point in the history
Dropdown toggle
  • Loading branch information
tejuamirthi authored Oct 26, 2020
2 parents fd7a9b2 + cd881ee commit 4647099
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 17 deletions.
4 changes: 4 additions & 0 deletions CustomDropDown.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
172E2CB6254254A5001F37B7 /* DropDownMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 172E2CB5254254A5001F37B7 /* DropDownMode.swift */; };
172E2CBF25425537001F37B7 /* CustomDropDownDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 172E2CBE25425537001F37B7 /* CustomDropDownDataSource.swift */; };
172E2CC32542556A001F37B7 /* CustomDropDownDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 172E2CC22542556A001F37B7 /* CustomDropDownDelegate.swift */; };
27EDDDEA2546A17800DB0ECA /* UIWindowExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27EDDDE92546A17800DB0ECA /* UIWindowExtension.swift */; };
3D469C3D2545DDFB00B2993A /* ShadowAndCornerConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D469C3C2545DDFB00B2993A /* ShadowAndCornerConfig.swift */; };
600DFEAB2529BA4200206E64 /* CustomDropDown.swift in Sources */ = {isa = PBXBuildFile; fileRef = 600DFEAA2529BA4200206E64 /* CustomDropDown.swift */; platformFilter = ios; };
6055FCBC2529AEC80096A0FD /* CustomDropDown.h in Headers */ = {isa = PBXBuildFile; fileRef = 6055FCBA2529AEC80096A0FD /* CustomDropDown.h */; settings = {ATTRIBUTES = (Public, ); }; };
Expand All @@ -41,6 +42,7 @@
172E2CB5254254A5001F37B7 /* DropDownMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropDownMode.swift; sourceTree = "<group>"; };
172E2CBE25425537001F37B7 /* CustomDropDownDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomDropDownDataSource.swift; sourceTree = "<group>"; };
172E2CC22542556A001F37B7 /* CustomDropDownDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomDropDownDelegate.swift; sourceTree = "<group>"; };
27EDDDE92546A17800DB0ECA /* UIWindowExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIWindowExtension.swift; sourceTree = "<group>"; };
3D469C3C2545DDFB00B2993A /* ShadowAndCornerConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShadowAndCornerConfig.swift; sourceTree = "<group>"; };
600DFEAA2529BA4200206E64 /* CustomDropDown.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomDropDown.swift; sourceTree = "<group>"; };
6055FCB72529AEC80096A0FD /* CustomDropDown.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CustomDropDown.framework; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -100,6 +102,7 @@
isa = PBXGroup;
children = (
172E2CAB254251AC001F37B7 /* UIViewExtension.swift */,
27EDDDE92546A17800DB0ECA /* UIWindowExtension.swift */,
);
path = Extensions;
sourceTree = "<group>";
Expand Down Expand Up @@ -301,6 +304,7 @@
172E2CB225425475001F37B7 /* DropDownConfig.swift in Sources */,
172E2C9425423F7B001F37B7 /* DropDownImageLabelView.swift in Sources */,
6055FCDA2529BF290096A0FD /* CustomDropDownPresenter.swift in Sources */,
27EDDDEA2546A17800DB0ECA /* UIWindowExtension.swift in Sources */,
172E2CB6254254A5001F37B7 /* DropDownMode.swift in Sources */,
600DFEAB2529BA4200206E64 /* CustomDropDown.swift in Sources */,
172E2CA325425123001F37B7 /* ImageLabelData.swift in Sources */,
Expand Down
27 changes: 27 additions & 0 deletions CustomDropDown/Extensions/UIWindowExtension.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//
// UIWindowExtension.swift
// CustomDropDown
//
// Created by Franklin Samboni on 26/10/20.
// Copyright © 2020 Amirthy Tejeshwar. All rights reserved.
//

import UIKit

extension UIWindow {
func topViewController() -> UIViewController? {
var top = self.rootViewController
while true {
if let presented = top?.presentedViewController {
top = presented
} else if let nav = top as? UINavigationController {
top = nav.visibleViewController
} else if let tab = top as? UITabBarController {
top = tab.selectedViewController
} else {
break
}
}
return top
}
}
79 changes: 62 additions & 17 deletions CustomDropDown/View/CustomDropDownView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import UIKit

class CustomDropDownView<T>: UIView, UITableViewDataSource, UITableViewDelegate {
class CustomDropDownView<T>: UIView, UITableViewDataSource, UITableViewDelegate, UIGestureRecognizerDelegate {

// MARK: - Constants

Expand All @@ -22,8 +22,9 @@ class CustomDropDownView<T>: UIView, UITableViewDataSource, UITableViewDelegate
var dropDown: CustomDropDown<T>?
var dropDownDisplayView: UIView!
var heightConstraint: NSLayoutConstraint = NSLayoutConstraint()
var isOpen: Bool = true
var isOpen: Bool = false
var identifier: Int
var outsideGesture: UITapGestureRecognizer?

// MARK: - Life cycle

Expand Down Expand Up @@ -121,26 +122,36 @@ class CustomDropDownView<T>: UIView, UITableViewDataSource, UITableViewDelegate
}

private func toggleDropDown() {
guard let dropDown = self.dropDown else { return }

if isOpen {
isOpen = false
setHeightConstraint(to: dropDownHeight, maxHeight: dropDown.tableView.contentSize.height)
superview?.bringSubviewToFront(dropDown)
animateDropDown(animations: {
dropDown.layoutIfNeeded()
dropDown.center.y += dropDown.frame.height/2
})
closeDropDown()
} else {
isOpen = true
setHeightConstraint(to: 0)
animateDropDown(animations: {
dropDown.center.y -= dropDown.frame.height/2
dropDown.layoutIfNeeded()
})
openDropDown()
}
}

private func openDropDown() {
guard let dropDown = self.dropDown else { return }
isOpen = true
addOutsideGesture()
setHeightConstraint(to: dropDownHeight, maxHeight: dropDown.tableView.contentSize.height)
superview?.bringSubviewToFront(dropDown)
animateDropDown(animations: {
dropDown.layoutIfNeeded()
dropDown.center.y += dropDown.frame.height/2
})
}

private func closeDropDown() {
guard let dropDown = self.dropDown else { return }
isOpen = false
removeOutsideGesture()
setHeightConstraint(to: 0)
animateDropDown(animations: {
dropDown.center.y -= dropDown.frame.height/2
dropDown.layoutIfNeeded()
})
}

private func setHeightConstraint(to height: CGFloat, maxHeight: CGFloat? = nil) {
var height: CGFloat = height
if let maxHeight = maxHeight, height > maxHeight {
Expand All @@ -162,6 +173,34 @@ class CustomDropDownView<T>: UIView, UITableViewDataSource, UITableViewDelegate
completion: completion)
}

private func addOutsideGesture() {
guard outsideGesture == nil else { return }
let rootView = window?.topViewController()?.view
outsideGesture = UITapGestureRecognizer(target: self, action: #selector(outsideGestureHandler))
outsideGesture!.cancelsTouchesInView = false
outsideGesture!.delegate = self
rootView?.addGestureRecognizer(outsideGesture!)
}

private func removeOutsideGesture() {
let rootView = window?.topViewController()?.view
if let tap = outsideGesture {
rootView?.removeGestureRecognizer(tap)
}
outsideGesture = nil
}

// This func is called even when user click on tableview row. So, to avoid conflicts
// is necessary to detect if tap is not over DropDown to close it.
@objc func outsideGestureHandler(gesture: UITapGestureRecognizer) {
let location = gesture.location(in: dropDown)
let wh = (w: dropDown?.frame.width ?? 0, h: dropDown?.frame.height ?? 0)
let tapOutsiteOfDropDown = (location.x < 0 || location.y < 0 || location.x > wh.w || location.y > wh.h)
if isOpen && tapOutsiteOfDropDown {
closeDropDown()
}
}

// MARK: - Table View

private func getImageLabelCell(tableView: UITableView, indexPath: IndexPath) -> UITableViewCell {
Expand Down Expand Up @@ -201,6 +240,12 @@ class CustomDropDownView<T>: UIView, UITableViewDataSource, UITableViewDelegate
return cell
}

// MARK: UIGestureRecognizerDelegate methods

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}

// MARK: - UITableViewDataSource

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
Expand Down

0 comments on commit 4647099

Please sign in to comment.