I want to know what do you think about the structure of this code. If you think that there is some structural improvement to be made, tell me!
Here is a github link: https://github.com/LucianoPolit/LPDropdownMenu
Here is the code:
//
//  LPDropdownMenu.swift
//  Created by Luciano Polit on 1/8/16.
//  Copyright (c) 2016 Luciano Polit. All rights reserved.
//
import UIKit
@objc protocol LPDropdownMenuViewDelegate {
    optional func dropdownMenuView(dropdownMenuView: LPDropdownMenuView, shouldSwipeToPosition position: CGFloat) -> Bool
    optional func dropdownMenuView(dropdownMenuView: LPDropdownMenuView, shouldTouchToPosition position: CGFloat) -> Bool
    optional func dropdownMenuView(dropdownMenuView: LPDropdownMenuView, shouldDoubleTouchToPosition position: CGFloat) -> Bool
    optional func dropdownMenuView(dropdownMenuView: LPDropdownMenuView, shouldAproximateToPosition position: CGFloat) -> Bool
    optional func dropdownMenuView(dropdownMenuView: LPDropdownMenuView, shouldFinishSlidingAtPosition position: CGFloat) -> Bool
    optional func dropdownMenuView(dropdownMenuView: LPDropdownMenuView, willSwipeToPosition position: CGFloat)
    optional func dropdownMenuView(dropdownMenuView: LPDropdownMenuView, willTouchToPosition position: CGFloat)
    optional func dropdownMenuView(dropdownMenuView: LPDropdownMenuView, willDoubleTouchToPosition position: CGFloat)
    optional func dropdownMenuView(dropdownMenuView: LPDropdownMenuView, willAproximateToPosition position: CGFloat)
    optional func dropdownMenuView(dropdownMenuView: LPDropdownMenuView, willFinishSlidingAtPosition position: CGFloat)
    optional func dropdownMenuView(dropdownMenuView: LPDropdownMenuView, didSwipeToPosition position: CGFloat)
    optional func dropdownMenuView(dropdownMenuView: LPDropdownMenuView, didTouchToPosition position: CGFloat)
    optional func dropdownMenuView(dropdownMenuView: LPDropdownMenuView, didDoubleTouchToPosition position: CGFloat)
    optional func dropdownMenuView(dropdownMenuView: LPDropdownMenuView, didAproximateToPosition position: CGFloat)
    optional func dropdownMenuView(dropdownMenuView: LPDropdownMenuView, didFinishSlidingAtPosition position: CGFloat)
    optional func dropdownMenuView(dropdownMenuView: LPDropdownMenuView, didStartMovingAtPosition position: CGFloat)
    optional func dropdownMenuView(dropdownMenuView: LPDropdownMenuView, didFinishMovingAtPosition position: CGFloat)
}
class LPDropdownMenuView: UIView {
    private var panGestureRecognizer: UIPanGestureRecognizer!
    private var tapGestureRecognizer: UITapGestureRecognizer!
    private var doubleTapGestureRecognizer: UITapGestureRecognizer!
    private var movingCondition: Bool = false
    var delegate: LPDropdownMenuViewDelegate?
    var freeSlideable: Bool = true
    var swipeable: Bool = true
    var touchable: Bool = true
    var doubleTouchable: Bool = true
    var autoSetProperties: Bool = true
    var marginProximity: CGFloat = 50
    var swipeSensibility: CGFloat = 600
    var minPosition: CGFloat!
    var maxPosition: CGFloat!
    var contentFrame: CGRect! {
        didSet {
            setProperties()
        }
    }
    var barView: UIView! {
        willSet {
            if (self.barView != nil) {
                self.barView.removeFromSuperview()
            }
        }
        didSet {
            let height = barView.frame.size.height + (contentFrame.maxY - barView.frame.maxY)
            frame = CGRectMake(barView.frame.origin.x, barView.frame.origin.y, barView.frame.size.width, height)
            barView.frame.origin.y = 0
            addSubview(barView)
            setPosition(frame.origin.y)
            setProperties()
            setGestures()
        }
    }
    var menuView: UIView! {
        willSet {
            if (self.menuView != nil) {
                self.menuView.removeFromSuperview()
            }
        }
        didSet {
            if (!(menuView is UIScrollView)) {
                let newValue = menuView
                newValue.frame.origin.y = 0
                let height = frame.size.height - barView.frame.size.height
                menuView = UIScrollView(frame: CGRectMake(0, barView.frame.size.height, newValue.frame.size.width, height))
                (menuView as! UIScrollView).contentSize = CGSize(width: newValue.frame.size.width, height: newValue.frame.size.height)
                (menuView as! UIScrollView).bounces = false
                menuView.addSubview(newValue)
            } else {
                let height = frame.size.height - barView.frame.size.height
                menuView.frame = CGRectMake(0, barView.frame.size.height, menuView.frame.size.width, height)
            }
            addSubview(menuView)
        }
    }
    init (frame: CGRect, barView: UIView, menuView: UIView) {
        super.init(frame: frame)
        self.contentFrame = frame
        initView(barView, menuView: menuView)
    }
    override init(frame: CGRect) {
        super.init(frame: frame)
        self.contentFrame = frame
        let barView = DefaultBarView(frame: CGRectMake(0, frame.size.height - 60, frame.size.width, 60))
        let menuView = DefaultMenuView(frame: CGRectMake(0, barView.frame.size.height, frame.size.width, 600))
        initView(barView, menuView: menuView)
    }
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    private func initView(barView: UIView, menuView: UIView) {
        self.initGestures()
        self.barView = barView
        self.menuView = menuView
    }
}
extension LPDropdownMenuView {
    func getPosition() -> CGFloat {
        return frame.origin.y
    }
    func setProperties() {
        if (contentFrame != nil && autoSetProperties) {
            minPosition = contentFrame.maxY / 3
            maxPosition = contentFrame.maxY - barView.frame.size.height
        }
    }
    func setPosition(position: CGFloat) {
        self.frame.origin.y = position
        self.frame.size.height = self.contentFrame.size.height - position
        if (menuView != nil) {
            self.menuView.frame.size.height = self.contentFrame.size.height - self.barView.frame.size.height - position
        }
    }
    func setPositionWithAnimation(position: CGFloat, time: NSTimeInterval, completion: ((Void) -> Void)?) {
        UIView.animateWithDuration(time, delay: 0, options: .CurveEaseOut, animations: {
            self.frame.origin.y = position
            self.frame.size.height = self.contentFrame.size.height - position
            self.menuView.frame.size.height = self.contentFrame.size.height - position - self.barView.frame.size.height
            }, completion: { _ in
                if (completion != nil) {
                    completion!()
                }
        })
    }
}
extension LPDropdownMenuView {
    private func initGestures() {
        doubleTapGestureRecognizer = UITapGestureRecognizer(target: self, action: "handleDoubleTapGestures:")
        doubleTapGestureRecognizer.numberOfTapsRequired = 2
        tapGestureRecognizer = UITapGestureRecognizer(target: self, action: "handleTapGestures:")
        tapGestureRecognizer.numberOfTapsRequired = 1
        tapGestureRecognizer.requireGestureRecognizerToFail(doubleTapGestureRecognizer)
        panGestureRecognizer = UIPanGestureRecognizer(target: self, action: "handlePanGestures:")
        panGestureRecognizer.minimumNumberOfTouches = 1
        panGestureRecognizer.maximumNumberOfTouches = 1
    }
    private func setGestures() {
        barView.addGestureRecognizer(doubleTapGestureRecognizer)
        barView.addGestureRecognizer(tapGestureRecognizer)
        barView.addGestureRecognizer(panGestureRecognizer)
    }
    internal func handleDoubleTapGestures(sender: UITapGestureRecognizer) {
        if (doubleTouchable) {
            let minPosition = contentFrame.origin.y
            let maxPosition = contentFrame.maxY - barView.frame.size.height
            let fartherPosition = getFartherPosition(minPosition, maxPosition: maxPosition)
            if (delegate?.dropdownMenuView?(self, shouldDoubleTouchToPosition: fartherPosition) != false) {
                delegate?.dropdownMenuView?(self, willDoubleTouchToPosition: fartherPosition)
                setPositionWithAnimation(fartherPosition, time: 0.3, completion: {
                    delegate?.dropdownMenuView?(self, didDoubleTouchToPosition: fartherPosition)
                })
            }
        }
    }
    internal func handleTapGestures(sender: UITapGestureRecognizer) {
        if (touchable) {
            let fartherPosition = getFartherPosition(minPosition, maxPosition: maxPosition)
            if (delegate?.dropdownMenuView?(self, shouldTouchToPosition: fartherPosition) != false) {
                delegate?.dropdownMenuView?(self, willTouchToPosition: fartherPosition)
                setPositionWithAnimation(fartherPosition, time: 0.3, completion: {
                    delegate?.dropdownMenuView?(self, didTouchToPosition: fartherPosition)
                })
            }
        }
    }
    internal func handlePanGestures(sender: UIPanGestureRecognizer) {
        let location = sender.locationInView(sender.view!.superview!)
        if (sender.state != .Ended && sender.state != .Failed) {
            if (!movingCondition) {
                movingCondition = true
                delegate?.dropdownMenuView?(self, didStartMovingAtPosition: frame.origin.y)
            }
            let minPosition = contentFrame.origin.y
            let maxPosition = contentFrame.maxY - barView.frame.size.height
            let newPosition = frame.origin.y + location.y - (sender.view!.frame.size.height / 2)
            if (newPosition > minPosition && newPosition < maxPosition) {
                setPosition(newPosition)
            } else {
                if (newPosition < minPosition) {
                    setPosition(minPosition)
                } else {
                    setPosition(maxPosition)
                }
            }
        }
        if (sender.state == .Ended) {
            movingCondition = false
            delegate?.dropdownMenuView?(self, didFinishMovingAtPosition: frame.origin.y)
            if (checkMarginProximity(contentFrame.origin.y)) {
                if (delegate?.dropdownMenuView?(self, shouldAproximateToPosition: contentFrame.origin.y) != false) {
                    delegate?.dropdownMenuView?(self, willAproximateToPosition: contentFrame.origin.y)
                    setPositionWithAnimation(contentFrame.origin.y, time: 0.3, completion: {
                        delegate?.dropdownMenuView?(self, didAproximateToPosition: contentFrame.origin.y)
                    })
                    return
                }
            }
            if (checkMarginProximity(contentFrame.maxY - barView.frame.size.height)) {
                let proximatePosition = contentFrame.maxY - barView.frame.size.height
                if (delegate?.dropdownMenuView?(self, shouldAproximateToPosition: proximatePosition) != false) {
                    delegate?.dropdownMenuView?(self, willAproximateToPosition: proximatePosition)
                    setPositionWithAnimation(contentFrame.maxY - barView.frame.size.height, time: 0.3, completion: {
                        delegate?.dropdownMenuView?(self, didAproximateToPosition: proximatePosition)
                    })
                    return
                }
            }
            if (swipeable) {
                let swipePosition = getSwipePosition(sender.velocityInView(sender.view))
                if (swipePosition != nil) {
                    let swipeCondition = delegate?.dropdownMenuView?(self, shouldSwipeToPosition: swipePosition!) != false
                    if (swipeCondition) {
                        delegate?.dropdownMenuView?(self, willSwipeToPosition: swipePosition!)
                        setPositionWithAnimation(swipePosition!, time: 0.3, completion: {
                            delegate?.dropdownMenuView?(self, didSwipeToPosition: swipePosition!)
                        })
                        return
                    }
                }
            }
            if (freeSlideable && delegate?.dropdownMenuView?(self, shouldFinishSlidingAtPosition: frame.origin.y) == false) {
                let nearestPosition = getNearestPosition()
                delegate?.dropdownMenuView?(self, willAproximateToPosition: nearestPosition)
                setPositionWithAnimation(nearestPosition, time: 0.3, completion: {
                    delegate?.dropdownMenuView?(self, didAproximateToPosition: nearestPosition)
                })
                return
            }
            if (!freeSlideable) {
                let nearestPosition = getNearestPosition()
                delegate?.dropdownMenuView?(self, willAproximateToPosition: nearestPosition)
                setPositionWithAnimation(nearestPosition, time: 0.3, completion: {
                    delegate?.dropdownMenuView?(self, didAproximateToPosition: nearestPosition)
                })
                return
            }
            delegate?.dropdownMenuView?(self, willFinishSlidingAtPosition: frame.origin.y)
            delegate?.dropdownMenuView?(self, didFinishSlidingAtPosition: frame.origin.y)
        }
    }
    private func checkMarginProximity(position: CGFloat) -> Bool {
        if (frame.origin.y < position + marginProximity && frame.origin.y > position - marginProximity) {
            return true
        }
        return false
    }
    private func getNearestPosition() -> CGFloat {
        let currentPosition = frame.origin.y + (barView.frame.size.height / 2)
        let positions = [contentFrame.origin.y, minPosition, maxPosition, contentFrame.maxY]
        var nearestPosition: CGFloat!
        var distance: CGFloat!
        for position in positions {
            if (distance == nil || distance > abs(currentPosition - position)) {
                distance = abs(currentPosition - position)
                nearestPosition = position
            }
        }
        return nearestPosition
    }
    private func getSwipePosition(velocity: CGPoint) -> CGFloat? {
        if (velocity.y > swipeSensibility) {
            return maxPosition
        }
        if (velocity.y < -swipeSensibility) {
            if (frame.origin.y < minPosition) {
                return contentFrame.origin.y
            } else {
                return minPosition
            }
        }
        return nil
    }
    private func getFartherPosition(minPosition: CGFloat, maxPosition: CGFloat) -> CGFloat {
        let rangeMinPosition: CGFloat = 1.5
        let rangeMaxPosition: CGFloat = 0.5
        let distanceFromMin = (frame.origin.y - minPosition) * rangeMinPosition
        let distanceFromMax = (maxPosition - frame.origin.y) * rangeMaxPosition
        if (distanceFromMin > distanceFromMax) {
            return minPosition
        } else {
            return maxPosition
        }
    }
}
class DefaultBarView: UIView {
    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = UIColor.blueColor()
        initLabel()
    }
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    private func initLabel() {
        let label = UILabel(frame: CGRectMake(0, 0, frame.size.width, frame.size.height))
        label.textAlignment = .Center
        label.textColor = UIColor.whiteColor()
        label.font = UIFont.systemFontOfSize(22)
        label.text = "Something cool here!"
        addSubview(label)
    }
}
class DefaultMenuView: UIView {
    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = UIColor.grayColor()
        initLabel()
    }
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    private func initLabel() {
        let label = UILabel(frame: CGRectMake(0, 0, frame.size.width, frame.size.height))
        label.textAlignment = .Center
        label.textColor = UIColor.whiteColor()
        label.font = UIFont.systemFontOfSize(22)
        label.text = "An amazing view here!"
        addSubview(label)
    }
}
The code works perfect, but I want your opinion!




