Skip to content

Commit

Permalink
Create Project
Browse files Browse the repository at this point in the history
  • Loading branch information
corin8823 committed Aug 19, 2015
1 parent 9426b06 commit 771d9bd
Show file tree
Hide file tree
Showing 18 changed files with 598 additions and 427 deletions.
16 changes: 7 additions & 9 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,14 @@ profile
DerivedData
*.hmap
*.ipa
*.xcuserstate

# Bundler
.bundle

Carthage
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
#
# Note: if you ignore the Pods directory, make sure to uncomment
# `pod install` in .travis.yml
#
# Pods/
# Carthage
Carthage/Build/*
Carthage/Checkouts/*

# CocoaPods
Pods/
File renamed without changes.
296 changes: 296 additions & 0 deletions Classes/Popover.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,296 @@
//
// Popover.swift
// Popover
//
// Created by corin8823 on 8/16/15.
// Copyright (c) 2015 corin8823. All rights reserved.
//

import UIKit

public enum PopoverOption {
case ArrowSize(CGSize)
case AnimationIn(NSTimeInterval)
case AnimationOut(NSTimeInterval)
case CornerRadius(CGFloat)
case SideEdge(CGFloat)
case BlackOverlayColor(UIColor)
case Type(Popover.PopoverType)
}

public class Popover: UIView {

public enum PopoverType {
case Up
case Down
}

// custom property
private var arrowSize: CGSize = CGSize(width: 16.0, height: 10.0)
private var animationIn: NSTimeInterval = 0.6
private var animationOut: NSTimeInterval = 0.3
private var cornerRadius: CGFloat = 6.0
private var sideEdge: CGFloat = 20.0
private var popoverType: PopoverType = .Down
private var blackOverlayColor: UIColor = UIColor(white: 0.0, alpha: 0.2)

// custom closure
private var didShowHandler: (() -> ())?
private var didDismissHandler: (() -> ())?

private var blackOverlay: UIControl = UIControl()
private var containerView: UIView!
private var contentView: UIView!
private var contentViewFrame: CGRect!
private var arrowShowPoint: CGPoint!

public init() {
super.init(frame: CGRectZero)
self.backgroundColor = UIColor.clearColor()
}

public init(options: [PopoverOption]?) {
super.init(frame: CGRectZero)
self.backgroundColor = UIColor.clearColor()
self.setOptions(options)
}

public init(showHandler: (() -> ())?, dismissHandler: (() -> ())?) {
super.init(frame: CGRectZero)
self.backgroundColor = UIColor.clearColor()
self.didShowHandler = showHandler
self.didDismissHandler = dismissHandler
}

public init(options: [PopoverOption]?, showHandler: (() -> ())?, dismissHandler: (() -> ())?) {
super.init(frame: CGRectZero)
self.backgroundColor = UIColor.clearColor()
self.setOptions(options)
self.didShowHandler = showHandler
self.didDismissHandler = dismissHandler
}

private func setOptions(options: [PopoverOption]?){
if let options = options {
for option in options {
switch option {
case let .ArrowSize(value):
self.arrowSize = value
case let .AnimationIn(value):
self.animationIn = value
case let .AnimationOut(value):
self.animationOut = value
case let .CornerRadius(value):
self.cornerRadius = value
case let .SideEdge(value):
self.sideEdge = value
case let .BlackOverlayColor(value):
self.blackOverlayColor = value
case let .Type(value):
self.popoverType = value
}
}
}
}

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

override public func layoutSubviews() {
super.layoutSubviews()
self.create()
}

private func create() {
var frame = self.contentView.frame
frame.origin.x = self.arrowShowPoint.x - frame.size.width * 0.5

var sideEdge: CGFloat = 0.0
if frame.size.width < self.containerView.frame.size.width {
sideEdge = self.sideEdge
}

var outerSideEdge = CGRectGetMaxX(frame) - self.containerView.bounds.size.width
if outerSideEdge > 0 {
frame.origin.x -= (outerSideEdge + sideEdge)
} else {
if CGRectGetMinX(frame) < 0 {
frame.origin.x += abs(CGRectGetMinX(frame)) + sideEdge
}
}
self.frame = frame

var arrowPoint = self.containerView.convertPoint(self.arrowShowPoint, toView: self)
let anchorPoint: CGPoint
switch self.popoverType {
case .Up:
frame.origin.y = self.arrowShowPoint.y - frame.height - self.arrowSize.height
anchorPoint = CGPoint(x: arrowPoint.x / frame.size.width, y: 1)
case .Down:
frame.origin.y = self.arrowShowPoint.y
anchorPoint = CGPoint(x: arrowPoint.x / frame.size.width, y: 0)
}

var lastAnchor = self.layer.anchorPoint
self.layer.anchorPoint = anchorPoint
var x = self.layer.position.x + (anchorPoint.x - lastAnchor.x) * self.layer.bounds.size.width
var y = self.layer.position.y + (anchorPoint.y - lastAnchor.y) * self.layer.bounds.size.height
self.layer.position = CGPoint(x: x, y: y)

frame.size.height += self.arrowSize.height
self.frame = frame
}

public func show(contentView: UIView, fromView: UIView) {
let point: CGPoint
switch self.popoverType {
case .Up:
point = CGPoint(x: fromView.frame.origin.x + (fromView.frame.size.width / 2), y: fromView.frame.origin.y)
case .Down:
point = CGPoint(x: fromView.frame.origin.x + (fromView.frame.size.width / 2), y: fromView.frame.origin.y + fromView.frame.size.height)
}
self.show(contentView, point: point)
}

public func show(contentView: UIView, point: CGPoint) {
let inView = UIApplication.sharedApplication().keyWindow!
self.blackOverlay.autoresizingMask = .FlexibleWidth | .FlexibleHeight
self.blackOverlay.frame = inView.bounds
self.blackOverlay.backgroundColor = self.blackOverlayColor
inView.addSubview(self.blackOverlay)

self.blackOverlay.addTarget(self, action: "dismiss", forControlEvents: .TouchUpInside)

self.containerView = inView
self.contentView = contentView
self.contentView.backgroundColor = UIColor.clearColor()
self.contentView.layer.cornerRadius = self.cornerRadius
self.contentView.layer.masksToBounds = true
self.arrowShowPoint = point
self.show()
}

private func show() {
self.setNeedsDisplay()
switch self.popoverType {
case .Up:
self.contentView.frame.origin.y = 0.0
case .Down:
self.contentView.frame.origin.y = self.arrowSize.height
}
self.addSubview(self.contentView)
self.containerView.addSubview(self)

self.transform = CGAffineTransformMakeScale(0.0, 0.0)
UIView.animateWithDuration(self.animationIn, delay: 0,
usingSpringWithDamping: 0.7,
initialSpringVelocity: 3,
options: .CurveEaseInOut,
animations: {
self.transform = CGAffineTransformIdentity
}){ _ in
self.didShowHandler?()
}
}

public func dismiss() {
if self.superview != nil {
UIView.animateWithDuration(self.animationOut, delay: 0,
options: .CurveEaseInOut,
animations: {
self.transform = CGAffineTransformMakeScale(0.0001, 0.0001)
}){ _ in
self.contentView.removeFromSuperview()
self.blackOverlay.removeFromSuperview()
self.removeFromSuperview()
self.didDismissHandler?()
}
}
}

override public func drawRect(rect: CGRect) {
super.drawRect(rect)
var arrow = UIBezierPath()
var color = UIColor.whiteColor()
var arrowPoint = self.containerView.convertPoint(self.arrowShowPoint, toView: self)
switch self.popoverType {
case .Up:
arrow.moveToPoint(CGPoint(x: arrowPoint.x, y: self.bounds.height))
arrow.addLineToPoint(CGPoint(x: arrowPoint.x - self.arrowSize.width * 0.5, y: self.bounds.height - self.arrowSize.height))

arrow.addLineToPoint(CGPoint(x: self.cornerRadius, y: self.bounds.height - self.arrowSize.height))
arrow.addArcWithCenter(CGPoint(x: self.cornerRadius, y: self.bounds.height - self.arrowSize.height - self.cornerRadius),
radius: self.cornerRadius,
startAngle: self.radians(90),
endAngle: self.radians(180),
clockwise: true)

arrow.addLineToPoint(CGPoint(x: 0, y: self.cornerRadius))
arrow.addArcWithCenter(CGPoint(x: self.cornerRadius, y: self.cornerRadius),
radius: self.cornerRadius,
startAngle: self.radians(180),
endAngle: self.radians(270),
clockwise: true)

arrow.addLineToPoint(CGPoint(x: self.bounds.width - self.cornerRadius, y: 0))
arrow.addArcWithCenter(CGPoint(x: self.bounds.width - self.cornerRadius, y: self.cornerRadius),
radius: self.cornerRadius,
startAngle: self.radians(270),
endAngle: self.radians(0),
clockwise: true)

arrow.addLineToPoint(CGPoint(x: self.bounds.width, y: self.bounds.height - self.arrowSize.height - self.cornerRadius))
arrow.addArcWithCenter(CGPoint(x: self.bounds.width - self.cornerRadius, y: self.bounds.height - self.arrowSize.height - self.cornerRadius),
radius: self.cornerRadius,
startAngle: self.radians(0),
endAngle: self.radians(90),
clockwise: true)

arrow.addLineToPoint(CGPoint(x: arrowPoint.x + self.arrowSize.width * 0.5,
y: self.bounds.height - self.arrowSize.height))

case .Down:
arrow.moveToPoint(CGPoint(x: arrowPoint.x, y: 0))
arrow.addLineToPoint(CGPoint(x: arrowPoint.x + self.arrowSize.width * 0.5, y: self.arrowSize.height))

arrow.addLineToPoint(CGPoint(x: self.bounds.width - self.cornerRadius, y: self.arrowSize.height))
arrow.addArcWithCenter(CGPoint(x: self.bounds.width - self.cornerRadius, y: self.arrowSize.height + self.cornerRadius),
radius: self.cornerRadius,
startAngle: self.radians(270.0),
endAngle: self.radians(0),
clockwise: true)

arrow.addLineToPoint(CGPoint(x: self.bounds.width, y: self.bounds.height - self.cornerRadius))
arrow.addArcWithCenter(CGPoint(x: self.bounds.width - self.cornerRadius, y: self.bounds.height - self.cornerRadius),
radius: self.cornerRadius,
startAngle: self.radians(0),
endAngle: self.radians(90),
clockwise: true)

arrow.addLineToPoint(CGPoint(x: 0, y: self.bounds.height))
arrow.addArcWithCenter(CGPoint(x: self.cornerRadius, y: self.bounds.height - self.cornerRadius),
radius: self.cornerRadius,
startAngle: self.radians(90),
endAngle: self.radians(180),
clockwise: true)

arrow.addLineToPoint(CGPoint(x: 0, y: self.arrowSize.height + self.cornerRadius))
arrow.addArcWithCenter(CGPoint(x: self.cornerRadius, y: self.arrowSize.height + self.cornerRadius),
radius: self.cornerRadius,
startAngle: self.radians(180),
endAngle: self.radians(270),
clockwise: true)

arrow.addLineToPoint(CGPoint(x: arrowPoint.x - self.arrowSize.width * 0.5,
y: self.arrowSize.height))
}

color.setFill()
arrow.fill()
}

private func radians(degrees: CGFloat) -> CGFloat {
return (CGFloat(M_PI) * degrees / 180)
}
}
13 changes: 4 additions & 9 deletions Example/Podfile
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
use_frameworks!

target 'Popover_Example', :exclusive => true do
pod "Popover", :path => "../"
end

target 'Popover_Tests', :exclusive => true do
pod "Popover", :path => "../"

pod 'FBSnapshotTestCase'
end
target 'PopoverExample' do
pod 'Popover', :path => '..'
end
14 changes: 14 additions & 0 deletions Example/Podfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
PODS:
- Popover (0.1.0)

DEPENDENCIES:
- Popover (from `..`)

EXTERNAL SOURCES:
Popover:
:path: ..

SPEC CHECKSUMS:
Popover: 418c76f60ba6037a7a3b0b940d7247c0439388a0

COCOAPODS: 0.38.2
Loading

0 comments on commit 771d9bd

Please sign in to comment.