Compare commits
38
Commits
docs_update
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1ebd9b3e6f | ||
|
|
b7dc1f1d75 | ||
|
|
21e64f72c1 | ||
|
|
33dfe08a96 | ||
|
|
9d0982e62d | ||
|
|
b1b564e1e9 | ||
|
|
3ca2172098 | ||
|
|
9ea71b64eb | ||
|
|
306632b484 | ||
|
|
def7ad435b | ||
|
|
9db9073217 | ||
|
|
a5efd73115 | ||
|
|
882ef88655 | ||
|
|
216a62c6ab | ||
|
|
ce1d4cd8bd | ||
|
|
0e87bcfc63 | ||
|
|
3bc71e84ee | ||
|
|
4f5a0ca337 | ||
|
|
ab8c7feee8 | ||
|
|
27913fd179 | ||
|
|
775c05a1d0 | ||
|
|
2953ca5342 | ||
|
|
16ba4b27b0 | ||
|
|
36c23cf714 | ||
|
|
d6e37f7f01 | ||
|
|
38fa225507 | ||
|
|
98352afdc7 | ||
|
|
e5c63c9812 | ||
|
|
4ec5646fa1 | ||
|
|
20d7be5ca0 | ||
|
|
0871b243b3 | ||
|
|
d41c599568 | ||
|
|
e720eaf3f3 | ||
|
|
4c3d646349 | ||
|
|
4d41164378 | ||
|
|
aa490544c2 | ||
|
|
835ff54cbb | ||
|
|
f65b92ffdf |
+1
-1
@@ -3,4 +3,4 @@ language: objective-c
|
|||||||
|
|
||||||
xcode_project: FoldingCell/FoldingCell.xcodeproj
|
xcode_project: FoldingCell/FoldingCell.xcodeproj
|
||||||
xcode_scheme: FoldingCell
|
xcode_scheme: FoldingCell
|
||||||
xcode_sdk: iphonesimulator9.1
|
xcode_sdk: iphonesimulator
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
Pod::Spec.new do |s|
|
Pod::Spec.new do |s|
|
||||||
s.name = 'FoldingCell'
|
s.name = 'FoldingCell'
|
||||||
s.version = '0.3'
|
s.version = '0.7.2'
|
||||||
s.summary = 'UITableViewCell with folding animation.'
|
s.summary = 'UITableViewCell with folding animation.'
|
||||||
s.homepage = 'https://github.com/Ramotion/folding-cell'
|
s.homepage = 'https://github.com/Ramotion/folding-cell'
|
||||||
s.license = 'MIT'
|
s.license = 'MIT'
|
||||||
|
|||||||
@@ -225,7 +225,7 @@
|
|||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
847A58031C294F750028FB84 = {
|
847A58031C294F750028FB84 = {
|
||||||
CreatedOnToolsVersion = 7.2;
|
CreatedOnToolsVersion = 7.2;
|
||||||
DevelopmentTeam = 34MUF9YXTA;
|
DevelopmentTeam = LEAZS7L33U;
|
||||||
};
|
};
|
||||||
8498513B1C5639F9006FA400 = {
|
8498513B1C5639F9006FA400 = {
|
||||||
CreatedOnToolsVersion = 7.2;
|
CreatedOnToolsVersion = 7.2;
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="9531" systemVersion="15C50" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="0cn-rv-Emg">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="9532" systemVersion="15D21" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="0cn-rv-Emg">
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<deployment identifier="iOS"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9529"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9530"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<customFonts key="customFonts">
|
<customFonts key="customFonts">
|
||||||
<mutableArray key="OpenSans-Light.ttf">
|
<mutableArray key="OpenSans-Light.ttf">
|
||||||
|
|||||||
@@ -21,8 +21,7 @@ class DemoCell: FoldingCell {
|
|||||||
|
|
||||||
override func animationDuration(itemIndex:NSInteger, type:AnimationType)-> NSTimeInterval {
|
override func animationDuration(itemIndex:NSInteger, type:AnimationType)-> NSTimeInterval {
|
||||||
|
|
||||||
let durations = [0.33, 0.26, 0.26]
|
let durations = [0.26, 0.2, 0.2]
|
||||||
|
|
||||||
return durations[itemIndex]
|
return durations[itemIndex]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,457 +24,482 @@
|
|||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
public class FoldingCell: UITableViewCell {
|
public class FoldingCell: UITableViewCell {
|
||||||
|
|
||||||
|
public typealias CompletionHandler = () -> Void
|
||||||
|
|
||||||
|
@IBOutlet weak public var containerView: UIView!
|
||||||
|
@IBOutlet weak public var foregroundView: RotatedView!
|
||||||
|
var animationView: UIView?
|
||||||
|
|
||||||
|
@IBInspectable public var itemCount: NSInteger = 2 //count of folding
|
||||||
|
|
||||||
|
@IBInspectable public var backViewColor: UIColor = UIColor.brownColor()
|
||||||
|
|
||||||
|
var animationItemViews: [RotatedView]?
|
||||||
|
|
||||||
|
public enum AnimationType {
|
||||||
|
case Open
|
||||||
|
case Close
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: life cicle
|
||||||
|
|
||||||
|
override public func awakeFromNib() {
|
||||||
|
super.awakeFromNib()
|
||||||
|
|
||||||
public typealias CompletionHandler = () -> Void
|
configureDefaultState()
|
||||||
|
|
||||||
@IBOutlet weak var containerView: UIView!
|
|
||||||
@IBOutlet weak var foregroundView: RotatedView!
|
|
||||||
var animationView: UIView?
|
|
||||||
|
|
||||||
@IBInspectable var itemCount: NSInteger = 2 //count of folding
|
self.selectionStyle = .None
|
||||||
|
|
||||||
@IBInspectable var backViewColor: UIColor = UIColor.brownColor()
|
containerView.layer.cornerRadius = foregroundView.layer.cornerRadius
|
||||||
|
containerView.layer.masksToBounds = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: configure
|
||||||
|
|
||||||
|
func configureDefaultState() {
|
||||||
|
let foregroundTopConstraint = self.contentView.constraints.filter{ $0.identifier == "ForegroundViewTop"}.first
|
||||||
|
let containerViewTopConstraint = self.contentView.constraints.filter{ $0.identifier == "ContainerViewTop"}.first
|
||||||
|
|
||||||
var animationItemViews: [RotatedView]?
|
guard let foregroundConstraint = foregroundTopConstraint else {
|
||||||
|
fatalError("set identifier")
|
||||||
public enum AnimationType {
|
|
||||||
case Open
|
|
||||||
case Close
|
|
||||||
}
|
}
|
||||||
|
guard let containerConstraint = containerViewTopConstraint else {
|
||||||
// MARK: life cicle
|
fatalError("set identifier")
|
||||||
|
|
||||||
override public func awakeFromNib() {
|
|
||||||
super.awakeFromNib()
|
|
||||||
|
|
||||||
configureDefaultState()
|
|
||||||
|
|
||||||
self.selectionStyle = .None
|
|
||||||
|
|
||||||
containerView.layer.cornerRadius = foregroundView.layer.cornerRadius
|
|
||||||
containerView.layer.masksToBounds = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: configure
|
|
||||||
|
|
||||||
func configureDefaultState() {
|
|
||||||
let foregroundTopConstraint = self.contentView.constraints.filter{ $0.identifier == "ForegroundViewTop"}.first
|
|
||||||
let containerViewTopConstraint = self.contentView.constraints.filter{ $0.identifier == "ContainerViewTop"}.first
|
|
||||||
|
|
||||||
assert(foregroundTopConstraint != nil, "set identifier")
|
|
||||||
assert(containerViewTopConstraint != nil, "set identifier")
|
|
||||||
|
|
||||||
containerViewTopConstraint!.constant = foregroundTopConstraint!.constant
|
|
||||||
containerView.alpha = 0;
|
|
||||||
|
|
||||||
foregroundView.layer.anchorPoint = CGPoint.init(x: 0.5, y: 1)
|
|
||||||
foregroundTopConstraint!.constant += foregroundView.bounds.height / 2
|
|
||||||
foregroundView.layer.transform = foregroundView.transform3d()
|
|
||||||
|
|
||||||
createAnimationView();
|
|
||||||
self.contentView.bringSubviewToFront(foregroundView)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func createAnimationItemView()->[RotatedView] {
|
containerConstraint.constant = foregroundConstraint.constant
|
||||||
var items = [RotatedView]()
|
containerView.alpha = 0;
|
||||||
items.append(foregroundView)
|
|
||||||
var rotatedViews = [RotatedView]()
|
foregroundView.layer.anchorPoint = CGPoint.init(x: 0.5, y: 1)
|
||||||
for itemView in animationView!.subviews.filter({$0 is RotatedView}).sort({ $0.tag < $1.tag }) as! [RotatedView] {
|
foregroundConstraint.constant += foregroundView.bounds.height / 2
|
||||||
rotatedViews.append(itemView)
|
foregroundView.layer.transform = foregroundView.transform3d()
|
||||||
if itemView.backView != nil {
|
|
||||||
rotatedViews.append(itemView.backView!)
|
createAnimationView();
|
||||||
}
|
self.contentView.bringSubviewToFront(foregroundView)
|
||||||
}
|
}
|
||||||
items.appendContentsOf(rotatedViews)
|
|
||||||
return items
|
func createAnimationItemView()->[RotatedView] {
|
||||||
|
guard let animationView = self.animationView else {
|
||||||
|
fatalError()
|
||||||
}
|
}
|
||||||
|
|
||||||
func configureAnimationItems(animationType: AnimationType) {
|
var items = [RotatedView]()
|
||||||
|
items.append(foregroundView)
|
||||||
|
var rotatedViews = [RotatedView]()
|
||||||
|
for case let itemView as RotatedView in animationView.subviews.filter({$0 is RotatedView}).sort({ $0.tag < $1.tag }){
|
||||||
|
rotatedViews.append(itemView)
|
||||||
|
if let backView = itemView.backView {
|
||||||
|
rotatedViews.append(backView)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
items.appendContentsOf(rotatedViews)
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
|
||||||
|
func configureAnimationItems(animationType: AnimationType) {
|
||||||
|
|
||||||
|
guard let animationViewSuperView = animationView?.subviews else {
|
||||||
|
fatalError()
|
||||||
|
}
|
||||||
|
|
||||||
|
if animationType == .Open {
|
||||||
|
for view in animationViewSuperView.filter({$0 is RotatedView}) {
|
||||||
|
view.alpha = 0;
|
||||||
|
}
|
||||||
|
} else { // close
|
||||||
|
for case let view as RotatedView in animationViewSuperView.filter({$0 is RotatedView}) {
|
||||||
if animationType == .Open {
|
if animationType == .Open {
|
||||||
for view in animationView!.subviews.filter({$0 is RotatedView}) {
|
view.alpha = 0
|
||||||
view.alpha = 0;
|
|
||||||
}
|
|
||||||
} else { // close
|
|
||||||
for view: RotatedView in animationView!.subviews.filter({$0 is RotatedView}) as! [RotatedView] {
|
|
||||||
if animationType == .Open {
|
|
||||||
view.alpha = 0
|
|
||||||
} else {
|
|
||||||
view.alpha = 1
|
|
||||||
view.backView?.alpha = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func createAnimationView() {
|
|
||||||
|
|
||||||
let anAnimationView = UIView(frame: containerView.frame)
|
|
||||||
anAnimationView.layer.cornerRadius = foregroundView.layer.cornerRadius
|
|
||||||
anAnimationView.backgroundColor = UIColor.clearColor()
|
|
||||||
anAnimationView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
self.contentView.addSubview(anAnimationView)
|
|
||||||
|
|
||||||
// copy constraints from containerView
|
|
||||||
var newConstraints = [NSLayoutConstraint]()
|
|
||||||
for constraint in self.contentView.constraints {
|
|
||||||
if let item: UIView = constraint.firstItem as? UIView {
|
|
||||||
if item == containerView {
|
|
||||||
let newConstraint = NSLayoutConstraint(
|
|
||||||
item: anAnimationView,
|
|
||||||
attribute: constraint.firstAttribute,
|
|
||||||
relatedBy: constraint.relation,
|
|
||||||
toItem: constraint.secondItem,
|
|
||||||
attribute: constraint.secondAttribute,
|
|
||||||
multiplier: constraint.multiplier,
|
|
||||||
constant: constraint.constant)
|
|
||||||
|
|
||||||
newConstraints.append(newConstraint)
|
|
||||||
} else if let item: UIView = constraint.secondItem as? UIView {
|
|
||||||
if item == containerView {
|
|
||||||
let newConstraint = NSLayoutConstraint(
|
|
||||||
item: constraint.firstItem,
|
|
||||||
attribute: constraint.firstAttribute,
|
|
||||||
relatedBy: constraint.relation,
|
|
||||||
toItem: anAnimationView,
|
|
||||||
attribute: constraint.secondAttribute,
|
|
||||||
multiplier: constraint.multiplier,
|
|
||||||
constant: constraint.constant)
|
|
||||||
|
|
||||||
newConstraints.append(newConstraint)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.contentView.addConstraints(newConstraints)
|
|
||||||
|
|
||||||
for constraint in containerView.constraints { // added height constraint
|
|
||||||
if constraint.firstAttribute == .Height {
|
|
||||||
let newConstraint = NSLayoutConstraint(
|
|
||||||
item: anAnimationView,
|
|
||||||
attribute: constraint.firstAttribute,
|
|
||||||
relatedBy: constraint.relation,
|
|
||||||
toItem: nil,
|
|
||||||
attribute: constraint.secondAttribute,
|
|
||||||
multiplier: constraint.multiplier,
|
|
||||||
constant: constraint.constant)
|
|
||||||
|
|
||||||
anAnimationView.addConstraint(newConstraint)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
animationView = anAnimationView
|
|
||||||
}
|
|
||||||
|
|
||||||
func addImageItemsToAnimationView() {
|
|
||||||
containerView.alpha = 1;
|
|
||||||
|
|
||||||
// added first item
|
|
||||||
var image = containerView.pb_takeSnapshot(CGRect(x: 0, y: 0, width: containerView.bounds.size.width, height: foregroundView.bounds.size.height))
|
|
||||||
var imageView = UIImageView(image: image)
|
|
||||||
imageView.tag = 0
|
|
||||||
imageView.layer.cornerRadius = foregroundView.layer.cornerRadius
|
|
||||||
animationView?.addSubview(imageView)
|
|
||||||
|
|
||||||
// added secod item
|
|
||||||
|
|
||||||
image = containerView.pb_takeSnapshot(
|
|
||||||
CGRect(x: 0,
|
|
||||||
y: foregroundView.bounds.size.height,
|
|
||||||
width: containerView.bounds.size.width,
|
|
||||||
height: foregroundView.bounds.size.height))
|
|
||||||
|
|
||||||
imageView = UIImageView(image: image)
|
|
||||||
let rotatedView = RotatedView(frame: imageView.frame)
|
|
||||||
rotatedView.tag = 1
|
|
||||||
rotatedView.layer.anchorPoint = CGPoint.init(x: 0.5, y: 0)
|
|
||||||
rotatedView.layer.transform = rotatedView.transform3d()
|
|
||||||
|
|
||||||
rotatedView.addSubview(imageView)
|
|
||||||
animationView?.addSubview(rotatedView)
|
|
||||||
rotatedView.frame = CGRect(x: imageView.frame.origin.x,
|
|
||||||
y: foregroundView.bounds.size.height,
|
|
||||||
width: containerView.bounds.size.width,
|
|
||||||
height: foregroundView.bounds.size.height)
|
|
||||||
|
|
||||||
// added other views
|
|
||||||
let itemHeight = (containerView.bounds.size.height - 2 * foregroundView.bounds.size.height) / CGFloat(itemCount - 2)
|
|
||||||
|
|
||||||
if itemCount == 2 {
|
|
||||||
// decrease containerView height or increase itemCount
|
|
||||||
assert(containerView.bounds.size.height - 2 * foregroundView.bounds.size.height == 0, "contanerView.height too high")
|
|
||||||
}
|
|
||||||
// decrease containerView height or increase itemCount
|
|
||||||
assert(containerView.bounds.size.height - 2 * foregroundView.bounds.size.height >= itemHeight, "contanerView.height too high")
|
|
||||||
|
|
||||||
var yPosition = 2 * foregroundView.bounds.size.height
|
|
||||||
var tag = 2
|
|
||||||
for var index = 2; index < itemCount; index++ {
|
|
||||||
|
|
||||||
image = containerView.pb_takeSnapshot(CGRect(x: 0, y: yPosition, width: containerView.bounds.size.width, height: itemHeight))
|
|
||||||
|
|
||||||
imageView = UIImageView(image: image)
|
|
||||||
let rotatedView = RotatedView(frame: imageView.frame)
|
|
||||||
|
|
||||||
rotatedView.addSubview(imageView)
|
|
||||||
rotatedView.layer.anchorPoint = CGPoint.init(x: 0.5, y: 0)
|
|
||||||
rotatedView.layer.transform = rotatedView.transform3d()
|
|
||||||
animationView?.addSubview(rotatedView)
|
|
||||||
rotatedView.frame = CGRect(x: 0, y: yPosition, width: rotatedView.bounds.size.width, height: itemHeight)
|
|
||||||
rotatedView.tag = tag
|
|
||||||
|
|
||||||
yPosition += itemHeight
|
|
||||||
tag++;
|
|
||||||
}
|
|
||||||
|
|
||||||
containerView.alpha = 0;
|
|
||||||
|
|
||||||
// added back view
|
|
||||||
var previusView: RotatedView?
|
|
||||||
for contener in animationView!.subviews.sort({ $0.tag < $1.tag }) {
|
|
||||||
if contener is RotatedView && contener.tag > 0 && contener.tag < animationView!.subviews.count {
|
|
||||||
let rotatedView = contener as! RotatedView
|
|
||||||
previusView?.addBackView(rotatedView.bounds.size.height, color: backViewColor)
|
|
||||||
previusView = rotatedView
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
animationItemViews = createAnimationItemView()
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: public
|
|
||||||
|
|
||||||
public func selectedAnimation(isSelected: Bool, animated: Bool, completion: CompletionHandler?) {
|
|
||||||
|
|
||||||
if isSelected {
|
|
||||||
|
|
||||||
if animated {
|
|
||||||
containerView.alpha = 0;
|
|
||||||
openAnimation(completion: completion)
|
|
||||||
} else {
|
|
||||||
foregroundView.alpha = 0
|
|
||||||
containerView.alpha = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if animated {
|
view.alpha = 1
|
||||||
closeAnimation(completion: completion)
|
view.backView?.alpha = 0
|
||||||
} else {
|
|
||||||
foregroundView.alpha = 1;
|
|
||||||
containerView.alpha = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func createAnimationView() {
|
||||||
|
|
||||||
public func isAnimating()->Bool {
|
let anAnimationView = UIView(frame: containerView.frame)
|
||||||
guard animationItemViews != nil
|
anAnimationView.layer.cornerRadius = foregroundView.layer.cornerRadius
|
||||||
else {
|
anAnimationView.backgroundColor = UIColor.clearColor()
|
||||||
return false
|
anAnimationView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
}
|
self.contentView.addSubview(anAnimationView)
|
||||||
|
|
||||||
|
// copy constraints from containerView
|
||||||
|
var newConstraints = [NSLayoutConstraint]()
|
||||||
|
for constraint in self.contentView.constraints {
|
||||||
|
if let item = constraint.firstItem as? UIView where item == containerView {
|
||||||
|
let newConstraint = NSLayoutConstraint( item: anAnimationView, attribute: constraint.firstAttribute,
|
||||||
|
relatedBy: constraint.relation, toItem: constraint.secondItem, attribute: constraint.secondAttribute,
|
||||||
|
multiplier: constraint.multiplier, constant: constraint.constant)
|
||||||
|
|
||||||
for item in animationItemViews! {
|
newConstraints.append(newConstraint)
|
||||||
if item.layer.animationKeys()?.count > 0 {
|
} else if let item: UIView = constraint.secondItem as? UIView where item == containerView {
|
||||||
return true
|
let newConstraint = NSLayoutConstraint(item: constraint.firstItem, attribute: constraint.firstAttribute,
|
||||||
}
|
relatedBy: constraint.relation, toItem: anAnimationView, attribute: constraint.secondAttribute,
|
||||||
}
|
multiplier: constraint.multiplier, constant: constraint.constant)
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: animations
|
|
||||||
|
|
||||||
public func animationDuration(itemIndex:NSInteger, type:AnimationType)-> NSTimeInterval {
|
|
||||||
assert(false, "added this method to cell")
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func durationSequence(type: AnimationType)-> [NSTimeInterval] {
|
|
||||||
var durations = [NSTimeInterval]()
|
|
||||||
for var index = 0; index < itemCount-1; index++ {
|
|
||||||
let duration = animationDuration(index, type: .Open)
|
|
||||||
durations.append(NSTimeInterval(duration / 2.0))
|
|
||||||
durations.append(NSTimeInterval(duration / 2.0))
|
|
||||||
}
|
|
||||||
return durations
|
|
||||||
}
|
|
||||||
|
|
||||||
func openAnimation(completion completion: CompletionHandler?) {
|
|
||||||
|
|
||||||
if animationView?.subviews.count == 0 { // added animation items if need
|
newConstraints.append(newConstraint)
|
||||||
addImageItemsToAnimationView()
|
}
|
||||||
}
|
}
|
||||||
|
self.contentView.addConstraints(newConstraints)
|
||||||
|
|
||||||
|
for constraint in containerView.constraints { // added height constraint
|
||||||
|
if constraint.firstAttribute == .Height {
|
||||||
|
let newConstraint = NSLayoutConstraint(item: anAnimationView, attribute: constraint.firstAttribute,
|
||||||
|
relatedBy: constraint.relation, toItem: nil, attribute: constraint.secondAttribute,
|
||||||
|
multiplier: constraint.multiplier, constant: constraint.constant)
|
||||||
|
|
||||||
animationView?.alpha = 1;
|
anAnimationView.addConstraint(newConstraint)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
animationView = anAnimationView
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func addImageItemsToAnimationView() {
|
||||||
|
containerView.alpha = 1;
|
||||||
|
let contSize = containerView.bounds.size
|
||||||
|
let forgSize = foregroundView.bounds.size
|
||||||
|
|
||||||
|
// added first item
|
||||||
|
var image = containerView.pb_takeSnapshot(CGRect(x: 0, y: 0, width: contSize.width, height: forgSize.height))
|
||||||
|
var imageView = UIImageView(image: image)
|
||||||
|
imageView.tag = 0
|
||||||
|
imageView.layer.cornerRadius = foregroundView.layer.cornerRadius
|
||||||
|
animationView?.addSubview(imageView)
|
||||||
|
|
||||||
|
// added secod item
|
||||||
|
image = containerView.pb_takeSnapshot(CGRect(x: 0, y: forgSize.height, width: contSize.width, height: forgSize.height))
|
||||||
|
|
||||||
|
imageView = UIImageView(image: image)
|
||||||
|
let rotatedView = RotatedView(frame: imageView.frame)
|
||||||
|
rotatedView.tag = 1
|
||||||
|
rotatedView.layer.anchorPoint = CGPoint.init(x: 0.5, y: 0)
|
||||||
|
rotatedView.layer.transform = rotatedView.transform3d()
|
||||||
|
|
||||||
|
rotatedView.addSubview(imageView)
|
||||||
|
animationView?.addSubview(rotatedView)
|
||||||
|
rotatedView.frame = CGRect(x: imageView.frame.origin.x, y: forgSize.height, width: contSize.width, height: forgSize.height)
|
||||||
|
|
||||||
|
// added other views
|
||||||
|
let itemHeight = (contSize.height - 2 * forgSize.height) / CGFloat(itemCount - 2)
|
||||||
|
|
||||||
|
if itemCount == 2 {
|
||||||
|
// decrease containerView height or increase itemCount
|
||||||
|
assert(contSize.height - 2 * forgSize.height == 0, "contanerView.height too high")
|
||||||
|
}
|
||||||
|
// decrease containerView height or increase itemCount
|
||||||
|
assert(contSize.height - 2 * forgSize.height >= itemHeight, "contanerView.height too high")
|
||||||
|
|
||||||
|
var yPosition = 2 * forgSize.height
|
||||||
|
var tag = 2
|
||||||
|
for _ in 2..<itemCount {
|
||||||
|
image = containerView.pb_takeSnapshot(CGRect(x: 0, y: yPosition, width: contSize.width, height: itemHeight))
|
||||||
|
|
||||||
|
imageView = UIImageView(image: image)
|
||||||
|
let rotatedView = RotatedView(frame: imageView.frame)
|
||||||
|
|
||||||
|
rotatedView.addSubview(imageView)
|
||||||
|
rotatedView.layer.anchorPoint = CGPoint.init(x: 0.5, y: 0)
|
||||||
|
rotatedView.layer.transform = rotatedView.transform3d()
|
||||||
|
animationView?.addSubview(rotatedView)
|
||||||
|
rotatedView.frame = CGRect(x: 0, y: yPosition, width: rotatedView.bounds.size.width, height: itemHeight)
|
||||||
|
rotatedView.tag = tag
|
||||||
|
|
||||||
|
yPosition += itemHeight
|
||||||
|
tag++;
|
||||||
|
}
|
||||||
|
|
||||||
|
containerView.alpha = 0;
|
||||||
|
|
||||||
|
if let animationView = self.animationView {
|
||||||
|
// added back view
|
||||||
|
var previusView: RotatedView?
|
||||||
|
for case let contener as RotatedView in animationView.subviews.sort({ $0.tag < $1.tag })
|
||||||
|
where contener.tag > 0 && contener.tag < animationView.subviews.count {
|
||||||
|
previusView?.addBackView(contener.bounds.size.height, color: backViewColor)
|
||||||
|
previusView = contener
|
||||||
|
}
|
||||||
|
}
|
||||||
|
animationItemViews = createAnimationItemView()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func removeImageItemsFromAnimationView() {
|
||||||
|
|
||||||
|
guard let animationView = self.animationView else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
animationView.subviews.forEach({ $0.removeFromSuperview() })
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: public
|
||||||
|
|
||||||
|
public func selectedAnimation(isSelected: Bool, animated: Bool, completion: CompletionHandler?) {
|
||||||
|
|
||||||
|
if isSelected {
|
||||||
|
|
||||||
|
if animated {
|
||||||
containerView.alpha = 0;
|
containerView.alpha = 0;
|
||||||
|
openAnimation(completion: completion)
|
||||||
let durations = durationSequence(.Open)
|
} else {
|
||||||
|
foregroundView.alpha = 0
|
||||||
var delay: NSTimeInterval = 0
|
containerView.alpha = 1;
|
||||||
var timing = kCAMediaTimingFunctionEaseIn
|
}
|
||||||
var from: CGFloat = 0.0;
|
|
||||||
var to: CGFloat = CGFloat(-M_PI / 2)
|
} else {
|
||||||
var hidden = true
|
if animated {
|
||||||
configureAnimationItems(.Open)
|
closeAnimation(completion: completion)
|
||||||
for var index = 0; index < animationItemViews?.count; index++ {
|
} else {
|
||||||
let animatedView = animationItemViews![index]
|
foregroundView.alpha = 1;
|
||||||
|
containerView.alpha = 0;
|
||||||
animatedView.foldingAnimation(timing, from: from, to: to, duration: durations[index], delay: delay, hidden: hidden)
|
}
|
||||||
|
}
|
||||||
from = from == 0.0 ? CGFloat(M_PI / 2) : 0.0;
|
}
|
||||||
to = to == 0.0 ? CGFloat(-M_PI / 2) : 0.0;
|
|
||||||
timing = timing == kCAMediaTimingFunctionEaseIn ? kCAMediaTimingFunctionEaseOut : kCAMediaTimingFunctionEaseIn;
|
public func isAnimating()->Bool {
|
||||||
hidden = !hidden
|
guard let animationItemViews = self.animationItemViews else {
|
||||||
delay += durations[index]
|
return false
|
||||||
}
|
|
||||||
|
|
||||||
let firstItemView = animationView!.subviews.filter{$0.tag == 0}.first
|
|
||||||
firstItemView!.layer.masksToBounds = true
|
|
||||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(durations[0] * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) { () -> Void in
|
|
||||||
firstItemView!.layer.cornerRadius = 0
|
|
||||||
}
|
|
||||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) { () -> Void in
|
|
||||||
self.animationView?.alpha = 0
|
|
||||||
self.containerView.alpha = 1
|
|
||||||
completion?()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func closeAnimation(completion completion: CompletionHandler?) {
|
for item in animationItemViews {
|
||||||
|
if item.layer.animationKeys()?.count > 0 {
|
||||||
if animationView?.subviews.count == 0 { // added animation items if need
|
return true
|
||||||
addImageItemsToAnimationView()
|
}
|
||||||
}
|
|
||||||
|
|
||||||
animationView?.alpha = 1;
|
|
||||||
containerView.alpha = 0;
|
|
||||||
|
|
||||||
var durations = durationSequence(.Close)
|
|
||||||
durations = durations.reverse()
|
|
||||||
|
|
||||||
var delay: NSTimeInterval = 0
|
|
||||||
var timing = kCAMediaTimingFunctionEaseIn
|
|
||||||
var from: CGFloat = 0.0;
|
|
||||||
var to: CGFloat = CGFloat(M_PI / 2)
|
|
||||||
var hidden = true
|
|
||||||
configureAnimationItems(.Close)
|
|
||||||
for var index = 0; index < animationItemViews?.count; index++ {
|
|
||||||
let animatedView = animationItemViews?.reverse()[index]
|
|
||||||
|
|
||||||
animatedView!.foldingAnimation(timing, from: from, to: to, duration: durations[index], delay: delay, hidden: hidden)
|
|
||||||
|
|
||||||
to = to == 0.0 ? CGFloat(M_PI / 2) : 0.0;
|
|
||||||
from = from == 0.0 ? CGFloat(-M_PI / 2) : 0.0;
|
|
||||||
timing = timing == kCAMediaTimingFunctionEaseIn ? kCAMediaTimingFunctionEaseOut : kCAMediaTimingFunctionEaseIn;
|
|
||||||
hidden = !hidden
|
|
||||||
delay += durations[index]
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) { () -> Void in
|
|
||||||
self.animationView!.alpha = 0
|
|
||||||
completion?()
|
|
||||||
}
|
|
||||||
|
|
||||||
let firstItemView = animationView!.subviews.filter{$0.tag == 0}.first
|
|
||||||
firstItemView!.layer.masksToBounds = false
|
|
||||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64((delay - durations.last! * 1.5) * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) { () -> Void in
|
|
||||||
firstItemView!.layer.cornerRadius = self.foregroundView.layer.cornerRadius
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if animationView?.alpha == 1 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: animations
|
||||||
|
|
||||||
|
public func animationDuration(itemIndex:NSInteger, type:AnimationType)-> NSTimeInterval {
|
||||||
|
assert(false, "added this method to cell")
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func durationSequence(type: AnimationType)-> [NSTimeInterval] {
|
||||||
|
var durations = [NSTimeInterval]()
|
||||||
|
for index in 0..<itemCount-1 {
|
||||||
|
let duration = animationDuration(index, type: .Open)
|
||||||
|
durations.append(NSTimeInterval(duration / 2.0))
|
||||||
|
durations.append(NSTimeInterval(duration / 2.0))
|
||||||
|
}
|
||||||
|
return durations
|
||||||
|
}
|
||||||
|
|
||||||
|
func openAnimation(completion completion: CompletionHandler?) {
|
||||||
|
|
||||||
|
removeImageItemsFromAnimationView()
|
||||||
|
addImageItemsToAnimationView()
|
||||||
|
|
||||||
|
guard let animationView = self.animationView else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
animationView.alpha = 1;
|
||||||
|
containerView.alpha = 0;
|
||||||
|
|
||||||
|
let durations = durationSequence(.Open)
|
||||||
|
|
||||||
|
var delay: NSTimeInterval = 0
|
||||||
|
var timing = kCAMediaTimingFunctionEaseIn
|
||||||
|
var from: CGFloat = 0.0;
|
||||||
|
var to: CGFloat = CGFloat(-M_PI / 2)
|
||||||
|
var hidden = true
|
||||||
|
configureAnimationItems(.Open)
|
||||||
|
|
||||||
|
guard let animationItemViews = self.animationItemViews else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for index in 0..<animationItemViews.count {
|
||||||
|
let animatedView = animationItemViews[index]
|
||||||
|
|
||||||
|
animatedView.foldingAnimation(timing, from: from, to: to, duration: durations[index], delay: delay, hidden: hidden)
|
||||||
|
|
||||||
|
from = from == 0.0 ? CGFloat(M_PI / 2) : 0.0;
|
||||||
|
to = to == 0.0 ? CGFloat(-M_PI / 2) : 0.0;
|
||||||
|
timing = timing == kCAMediaTimingFunctionEaseIn ? kCAMediaTimingFunctionEaseOut : kCAMediaTimingFunctionEaseIn;
|
||||||
|
hidden = !hidden
|
||||||
|
delay += durations[index]
|
||||||
|
}
|
||||||
|
|
||||||
|
let firstItemView = animationView.subviews.filter{$0.tag == 0}.first
|
||||||
|
|
||||||
|
if let first = firstItemView {
|
||||||
|
first.layer.masksToBounds = true
|
||||||
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(durations[0] * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) { () -> Void in
|
||||||
|
first.layer.cornerRadius = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) { () -> Void in
|
||||||
|
self.animationView?.alpha = 0
|
||||||
|
self.containerView.alpha = 1
|
||||||
|
completion?()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func closeAnimation(completion completion: CompletionHandler?) {
|
||||||
|
|
||||||
|
removeImageItemsFromAnimationView()
|
||||||
|
addImageItemsToAnimationView()
|
||||||
|
|
||||||
|
guard let animationItemViews = self.animationItemViews else {
|
||||||
|
fatalError()
|
||||||
|
}
|
||||||
|
|
||||||
|
animationView?.alpha = 1;
|
||||||
|
containerView.alpha = 0;
|
||||||
|
|
||||||
|
var durations: [NSTimeInterval] = durationSequence(.Close).reverse()
|
||||||
|
|
||||||
|
var delay: NSTimeInterval = 0
|
||||||
|
var timing = kCAMediaTimingFunctionEaseIn
|
||||||
|
var from: CGFloat = 0.0;
|
||||||
|
var to: CGFloat = CGFloat(M_PI / 2)
|
||||||
|
var hidden = true
|
||||||
|
configureAnimationItems(.Close)
|
||||||
|
|
||||||
|
if durations.count < animationItemViews.count {
|
||||||
|
fatalError("wrong override func animationDuration(itemIndex:NSInteger, type:AnimationType)-> NSTimeInterval")
|
||||||
|
}
|
||||||
|
for index in 0..<animationItemViews.count {
|
||||||
|
let animatedView = animationItemViews.reverse()[index]
|
||||||
|
|
||||||
|
animatedView.foldingAnimation(timing, from: from, to: to, duration: durations[index], delay: delay, hidden: hidden)
|
||||||
|
|
||||||
|
to = to == 0.0 ? CGFloat(M_PI / 2) : 0.0;
|
||||||
|
from = from == 0.0 ? CGFloat(-M_PI / 2) : 0.0;
|
||||||
|
timing = timing == kCAMediaTimingFunctionEaseIn ? kCAMediaTimingFunctionEaseOut : kCAMediaTimingFunctionEaseIn;
|
||||||
|
hidden = !hidden
|
||||||
|
delay += durations[index]
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) { () -> Void in
|
||||||
|
if let animationView = self.animationView {
|
||||||
|
animationView.alpha = 0
|
||||||
|
}
|
||||||
|
completion?()
|
||||||
|
}
|
||||||
|
|
||||||
|
if let animationView = self.animationView {
|
||||||
|
let firstItemView = animationView.subviews.filter{$0.tag == 0}.first
|
||||||
|
firstItemView?.layer.masksToBounds = false
|
||||||
|
if let durationLast = durations.last {
|
||||||
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64((delay - durationLast * 1.5) * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) { () -> Void in
|
||||||
|
firstItemView?.layer.cornerRadius = self.foregroundView.layer.cornerRadius
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: RotatedView
|
// MARK: RotatedView
|
||||||
|
|
||||||
public class RotatedView: UIView {
|
public class RotatedView: UIView {
|
||||||
var hiddenAfterAnimation = false
|
var hiddenAfterAnimation = false
|
||||||
var backView: RotatedView?
|
var backView: RotatedView?
|
||||||
|
|
||||||
|
func addBackView(height: CGFloat, color:UIColor) {
|
||||||
|
let view = RotatedView(frame: CGRect.zero)
|
||||||
|
view.backgroundColor = color
|
||||||
|
view.layer.anchorPoint = CGPoint.init(x: 0.5, y: 1)
|
||||||
|
view.layer.transform = view.transform3d()
|
||||||
|
view.translatesAutoresizingMaskIntoConstraints = false;
|
||||||
|
self.addSubview(view)
|
||||||
|
backView = view
|
||||||
|
|
||||||
func addBackView(height: CGFloat, color:UIColor) {
|
view.addConstraint(NSLayoutConstraint(item: view, attribute: .Height, relatedBy: .Equal, toItem: nil,attribute: .Height,
|
||||||
let view = RotatedView(frame: CGRect.zero)
|
multiplier: 1, constant: height))
|
||||||
view.backgroundColor = color
|
|
||||||
view.layer.anchorPoint = CGPoint.init(x: 0.5, y: 1)
|
self.addConstraints([
|
||||||
view.layer.transform = view.transform3d()
|
NSLayoutConstraint(item: view, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1,
|
||||||
view.translatesAutoresizingMaskIntoConstraints = false;
|
constant: self.bounds.size.height - height + height / 2),
|
||||||
self.addSubview(view)
|
NSLayoutConstraint(item: view, attribute: .Leading, relatedBy: .Equal, toItem: self, attribute: .Leading,
|
||||||
backView = view
|
multiplier: 1, constant: 0),
|
||||||
|
NSLayoutConstraint(item: view, attribute: .Trailing, relatedBy: .Equal, toItem: self, attribute: .Trailing,
|
||||||
view.addConstraint(NSLayoutConstraint(item: view,
|
multiplier: 1, constant: 0)
|
||||||
attribute: .Height,
|
])
|
||||||
relatedBy: .Equal,
|
}
|
||||||
toItem: nil,
|
|
||||||
attribute: .Height,
|
|
||||||
multiplier: 1,
|
|
||||||
constant: height))
|
|
||||||
|
|
||||||
self.addConstraints([
|
|
||||||
NSLayoutConstraint(item: view, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1, constant: self.bounds.size.height - height + height / 2),
|
|
||||||
NSLayoutConstraint(item: view, attribute: .Leading, relatedBy: .Equal, toItem: self, attribute: .Leading, multiplier: 1, constant: 0),
|
|
||||||
NSLayoutConstraint(item: view, attribute: .Trailing, relatedBy: .Equal, toItem: self, attribute: .Trailing, multiplier: 1, constant: 0)
|
|
||||||
])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
extension RotatedView {
|
extension RotatedView {
|
||||||
|
|
||||||
|
func rotatedX(angle : CGFloat) {
|
||||||
|
var allTransofrom = CATransform3DIdentity;
|
||||||
|
let rotateTransform = CATransform3DMakeRotation(angle, 1, 0, 0)
|
||||||
|
allTransofrom = CATransform3DConcat(allTransofrom, rotateTransform)
|
||||||
|
allTransofrom = CATransform3DConcat(allTransofrom, transform3d())
|
||||||
|
self.layer.transform = allTransofrom
|
||||||
|
}
|
||||||
|
|
||||||
|
func transform3d() -> CATransform3D {
|
||||||
|
var transform = CATransform3DIdentity
|
||||||
|
transform.m34 = 2.5 / -2000;
|
||||||
|
return transform
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: animations
|
||||||
|
|
||||||
|
func foldingAnimation(timing: String, from: CGFloat, to: CGFloat, duration: NSTimeInterval, delay:NSTimeInterval, hidden:Bool) {
|
||||||
|
|
||||||
func rotatedX(angle : CGFloat) {
|
let rotateAnimation = CABasicAnimation(keyPath: "transform.rotation.x")
|
||||||
var allTransofrom = CATransform3DIdentity;
|
rotateAnimation.timingFunction = CAMediaTimingFunction(name: timing)
|
||||||
let rotateTransform = CATransform3DMakeRotation(angle, 1, 0, 0)
|
rotateAnimation.fromValue = (from)
|
||||||
allTransofrom = CATransform3DConcat(allTransofrom, rotateTransform)
|
rotateAnimation.toValue = (to)
|
||||||
allTransofrom = CATransform3DConcat(allTransofrom, transform3d())
|
rotateAnimation.duration = duration
|
||||||
self.layer.transform = allTransofrom
|
rotateAnimation.delegate = self;
|
||||||
}
|
rotateAnimation.fillMode = kCAFillModeForwards
|
||||||
|
rotateAnimation.removedOnCompletion = false;
|
||||||
|
rotateAnimation.beginTime = CACurrentMediaTime() + delay
|
||||||
|
|
||||||
func transform3d()-> CATransform3D {
|
self.hiddenAfterAnimation = hidden
|
||||||
var transform = CATransform3DIdentity
|
|
||||||
transform.m34 = 2.5 / -2000;
|
|
||||||
return transform
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: animations
|
self.layer.addAnimation(rotateAnimation, forKey: "rotation.x")
|
||||||
|
}
|
||||||
func foldingAnimation(timing: String, from: CGFloat, to: CGFloat, duration: NSTimeInterval, delay:NSTimeInterval, hidden:Bool) {
|
|
||||||
|
override public func animationDidStart(anim: CAAnimation) {
|
||||||
let rotateAnimation = CABasicAnimation(keyPath: "transform.rotation.x")
|
self.layer.shouldRasterize = true
|
||||||
rotateAnimation.timingFunction = CAMediaTimingFunction(name: timing)
|
self.alpha = 1
|
||||||
rotateAnimation.fromValue = (from)
|
}
|
||||||
rotateAnimation.toValue = (to)
|
|
||||||
rotateAnimation.duration = duration
|
override public func animationDidStop(anim: CAAnimation, finished flag: Bool) {
|
||||||
rotateAnimation.delegate = self;
|
if hiddenAfterAnimation {
|
||||||
rotateAnimation.fillMode = kCAFillModeForwards;
|
self.alpha = 0
|
||||||
rotateAnimation.removedOnCompletion = false;
|
|
||||||
rotateAnimation.beginTime = CACurrentMediaTime() + delay
|
|
||||||
|
|
||||||
self.hiddenAfterAnimation = hidden
|
|
||||||
|
|
||||||
self.layer.addAnimation(rotateAnimation, forKey: "rotation.x")
|
|
||||||
}
|
|
||||||
|
|
||||||
override public func animationDidStart(anim: CAAnimation) {
|
|
||||||
self.layer.shouldRasterize = true
|
|
||||||
self.alpha = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
override public func animationDidStop(anim: CAAnimation, finished flag: Bool) {
|
|
||||||
if hiddenAfterAnimation {
|
|
||||||
self.alpha = 0
|
|
||||||
}
|
|
||||||
self.layer.removeAllAnimations()
|
|
||||||
self.layer.shouldRasterize = false
|
|
||||||
self.rotatedX(CGFloat(0))
|
|
||||||
}
|
}
|
||||||
|
self.layer.removeAllAnimations()
|
||||||
|
self.layer.shouldRasterize = false
|
||||||
|
self.rotatedX(CGFloat(0))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension UIView {
|
extension UIView {
|
||||||
func pb_takeSnapshot(frame: CGRect) -> UIImage {
|
func pb_takeSnapshot(frame: CGRect) -> UIImage? {
|
||||||
UIGraphicsBeginImageContextWithOptions(frame.size, false, 0.0);
|
UIGraphicsBeginImageContextWithOptions(frame.size, false, 0.0)
|
||||||
|
|
||||||
let context = UIGraphicsGetCurrentContext();
|
let context = UIGraphicsGetCurrentContext();
|
||||||
CGContextTranslateCTM(context, frame.origin.x * -1, frame.origin.y * -1);
|
CGContextTranslateCTM(context, frame.origin.x * -1, frame.origin.y * -1)
|
||||||
|
|
||||||
self.layer.renderInContext(UIGraphicsGetCurrentContext()!);
|
guard let currentContext = UIGraphicsGetCurrentContext() else {
|
||||||
let image = UIGraphicsGetImageFromCurrentImageContext();
|
return nil
|
||||||
UIGraphicsEndImageContext();
|
|
||||||
|
|
||||||
return image
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.layer.renderInContext(currentContext)
|
||||||
|
let image = UIGraphicsGetImageFromCurrentImageContext()
|
||||||
|
UIGraphicsEndImageContext()
|
||||||
|
|
||||||
|
return image
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -94,7 +94,7 @@ class MainTableViewController: UITableViewController {
|
|||||||
} else {// close cell
|
} else {// close cell
|
||||||
cellHeights[indexPath.row] = kCloseCellHeight
|
cellHeights[indexPath.row] = kCloseCellHeight
|
||||||
cell.selectedAnimation(false, animated: true, completion: nil)
|
cell.selectedAnimation(false, animated: true, completion: nil)
|
||||||
duration = 1.1
|
duration = 0.8
|
||||||
}
|
}
|
||||||
|
|
||||||
UIView.animateWithDuration(duration, delay: 0, options: .CurveEaseOut, animations: { () -> Void in
|
UIView.animateWithDuration(duration, delay: 0, options: .CurveEaseOut, animations: { () -> Void in
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
|

|
||||||
# FoldingCell
|
# FoldingCell
|
||||||
[](https://cocoapods.org/pods/FoldingCell)
|
[](https://cocoapods.org/pods/FoldingCell)
|
||||||
[](http://cocoapods.org/pods/FoldingCell)
|
[](http://cocoapods.org/pods/FoldingCell)
|
||||||
[](http://twitter.com/Ramotion)
|
[](http://twitter.com/Ramotion)
|
||||||
[](https://travis-ci.org/Ramotion/folding-cell)
|
[](https://travis-ci.org/Ramotion/folding-cell)
|
||||||
|
[](https://codebeat.co/projects/github-com-ramotion-folding-cell)
|
||||||
|
|
||||||
[shot on dribbble](https://dribbble.com/shots/2121350-Delivery-Card):
|
[shot on dribbble](https://dribbble.com/shots/2121350-Delivery-Card):
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
|
The [iPhone mockup](https://store.ramotion.com/product/iphone-6-mockups?utm_source=gthb&utm_medium=special&utm_campaign=folding-cell) available [here](https://store.ramotion.com/product/iphone-6-mockups?utm_source=gthb&utm_medium=special&utm_campaign=folding-cell).
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- iOS 8.0+
|
- iOS 8.0+
|
||||||
@@ -18,7 +22,7 @@ Just add the FoldingCell.swift file to your project.
|
|||||||
|
|
||||||
or use [CocoaPods](https://cocoapods.org) with Podfile:
|
or use [CocoaPods](https://cocoapods.org) with Podfile:
|
||||||
``` ruby
|
``` ruby
|
||||||
pod 'FoldingCell', '~> 0.3'
|
pod 'FoldingCell', '~> 0.7.2'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
@@ -47,7 +51,9 @@ property `containerView`. Add constraints from this view to the superview like i
|
|||||||
Your result should be something like this picture:
|
Your result should be something like this picture:
|
||||||

|

|
||||||
|
|
||||||
4) Set ``` @IBInspectable var itemCount: NSInteger ``` property is a count of folding (it IBInspectable you can set in storyborad). range 2 or greater. Default value is 2
|
[Demonstration adding constraints for foregroundView, containerView](https://vimeo.com/154954299)
|
||||||
|
|
||||||
|
4) Set ``` @IBInspectable var itemCount: NSInteger ``` property is a count of folding (it IBInspectable you can set in storyboard). range 2 or greater. Default value is 2
|
||||||
|
|
||||||
Ok, we've finished configuring the cell.
|
Ok, we've finished configuring the cell.
|
||||||
|
|
||||||
@@ -132,13 +138,13 @@ Ok, we've finished configuring the cell.
|
|||||||
|
|
||||||
## Licence
|
## Licence
|
||||||
|
|
||||||
Adaptive tab bar is released under the MIT license.
|
Folding cell is released under the MIT license.
|
||||||
See [LICENSE](./LICENSE) for details.
|
See [LICENSE](./LICENSE) for details.
|
||||||
|
|
||||||
|
|
||||||
## About
|
## About
|
||||||
The project maintained by [app development agency](http://ramotion.com?utm_source=gthb&utm_medium=special&utm_campaign=foolding-cell) [Ramotion Inc.](http://ramotion.com?utm_source=gthb&utm_medium=special&utm_campaign=foolding-cell)
|
The project maintained by [app development agency](https://ramotion.com?utm_source=gthb&utm_medium=special&utm_campaign=foolding-cell) [Ramotion Inc.](https://ramotion.com?utm_source=gthb&utm_medium=special&utm_campaign=foolding-cell)
|
||||||
See our other [open-source projects](https://github.com/ramotion) or [hire](http://ramotion.com?utm_source=gthb&utm_medium=special&utm_campaign=foolding-cell) us to design, develop, and grow your product.
|
See our other [open-source projects](https://github.com/ramotion) or [hire](https://ramotion.com?utm_source=gthb&utm_medium=special&utm_campaign=foolding-cell) us to design, develop, and grow your product.
|
||||||
|
|
||||||
[](https://twitter.com/intent/tweet?text=https://github.com/ramotion/foolding-cell)
|
[](https://twitter.com/intent/tweet?text=https://github.com/ramotion/foolding-cell)
|
||||||
[](https://twitter.com/ramotion)
|
[](https://twitter.com/ramotion)
|
||||||
|
|||||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
Reference in New Issue
Block a user