Compare commits

..
44 Commits
Author SHA1 Message Date
Alex.k 01b09a94ea update podspec 2016-04-08 17:03:47 +03:00
Alex.k 8c234e4e0d fixing bug with corners 2016-04-08 17:02:56 +03:00
Alex.k 974ab5eed5 Merge branch 'master' of https://github.com/Ramotion/folding-cell 2016-04-08 16:42:50 +03:00
Alex.k 8e7bb1ee35 remove xcschemes 2016-04-08 16:42:43 +03:00
Alex 5d6c1b6dad Update README.md 2016-04-08 16:36:44 +03:00
Alex.k 982c9e1b30 update files 2016-04-08 16:32:29 +03:00
Alex.k 6956f385b3 remove ++ operator 2016-04-08 16:30:23 +03:00
Alex 4f641597d7 Update README.md 2016-03-09 12:07:44 +03:00
Alex.k 878a473b02 update podspec 2016-03-09 12:05:18 +03:00
Alex.k 1ebd9b3e6f Fixes #26 2016-03-09 12:00:55 +03:00
Alex.k b7dc1f1d75 podspec updated 2016-03-09 09:16:43 +03:00
Artem Kyslicyn 21e64f72c1 Merge pull request #24 from Ramotion/develop
upd
2016-02-26 12:07:15 +03:00
Artem Kislitsyn 33dfe08a96 upd 2016-02-26 12:02:34 +03:00
Alex 9d0982e62d Merge pull request #23 from Ramotion/develop
update doc
2016-02-26 11:48:39 +03:00
Artem Kislitsyn b1b564e1e9 update doc 2016-02-26 11:40:55 +03:00
Alex 3ca2172098 Update README.md 2016-02-24 10:22:58 +03:00
Alex.k 9ea71b64eb public properties: itemCount, backViewColor 2016-02-24 10:12:26 +03:00
Alex 306632b484 Update README.md 2016-02-15 14:47:02 +03:00
Alex.k def7ad435b update podspec 2016-02-15 14:45:30 +03:00
Alex.k 9db9073217 Merge branch 'master' of https://github.com/Ramotion/folding-cell 2016-02-15 14:42:33 +03:00
Alex.k a5efd73115 code improved 2016-02-15 14:42:26 +03:00
Juri Vasylenko 882ef88655 add header 2016-02-15 11:26:28 +03:00
Alex.k 216a62c6ab update podspec 2016-02-11 12:06:14 +03:00
Alex.k ce1d4cd8bd common code improves 2016-02-11 11:45:37 +03:00
Alex.k 0e87bcfc63 common code improves 2016-02-11 11:34:32 +03:00
Alex.k 3bc71e84ee common code fixed 2016-02-11 11:23:15 +03:00
Alex 4f5a0ca337 Update README.md 2016-02-11 10:11:42 +03:00
Alex ab8c7feee8 Update README.md
Fixes#12
2016-02-11 10:09:49 +03:00
Juri Vasylenko 27913fd179 Merge pull request #11 from grodowski/master
Add code quality badge from codebeat
2016-02-10 15:54:51 +03:00
Jan Grodowski 775c05a1d0 Update README.md 2016-02-10 13:30:17 +01:00
Alex 2953ca5342 Merge pull request #7 from radarhere/patch-1
Fixed typo
2016-02-09 14:10:26 +03:00
Andrew Murray 16ba4b27b0 Fixed typo 2016-02-09 21:52:13 +11:00
Juri Vasylenko 36c23cf714 Update README.md 2016-02-09 10:32:40 +03:00
Alex.k d6e37f7f01 Merge branch 'master' of https://github.com/Ramotion/folding-cell 2016-02-08 12:38:08 +03:00
Alex.k 38fa225507 update podspec 2016-02-08 12:38:01 +03:00
Alex 98352afdc7 Update README.md 2016-02-05 11:13:50 +03:00
Alex.k e5c63c9812 Fixes #5 2016-02-05 11:04:55 +03:00
Alex.k 4ec5646fa1 Revert "Fixes #45"
This reverts commit 20d7be5ca0.
2016-02-05 11:03:06 +03:00
Alex.k 20d7be5ca0 Fixes #45 2016-02-05 11:02:30 +03:00
Alex 0871b243b3 Update README.md 2016-02-04 17:11:35 +03:00
Alex.k d41c599568 update podspect 2016-02-04 17:08:45 +03:00
Alex.k e720eaf3f3 common improves 2016-02-04 17:07:20 +03:00
Alex 4c3d646349 Update .travis.yml 2016-02-03 15:41:06 +03:00
Alex.k 4d41164378 changed version 2016-02-03 14:14:27 +03:00
11 changed files with 468 additions and 544 deletions
+2 -2
View File
@@ -1,6 +1,6 @@
osx_image: xcode7.2
osx_image: xcode7.3
language: objective-c
xcode_project: FoldingCell/FoldingCell.xcodeproj
xcode_scheme: FoldingCell
xcode_sdk: iphonesimulator9.1
xcode_sdk: iphonesimulator
+1 -1
View File
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'FoldingCell'
s.version = '0.3'
s.version = '0.8.1'
s.summary = 'UITableViewCell with folding animation.'
s.homepage = 'https://github.com/Ramotion/folding-cell'
s.license = 'MIT'
@@ -225,7 +225,7 @@
TargetAttributes = {
847A58031C294F750028FB84 = {
CreatedOnToolsVersion = 7.2;
DevelopmentTeam = 34MUF9YXTA;
DevelopmentTeam = LEAZS7L33U;
};
8498513B1C5639F9006FA400 = {
CreatedOnToolsVersion = 7.2;
@@ -1,105 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0720"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "847A58031C294F750028FB84"
BuildableName = "FoldingCell.app"
BlueprintName = "FoldingCell"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "8498513B1C5639F9006FA400"
BuildableName = "FoldingCellTests.xctest"
BlueprintName = "FoldingCellTests"
ReferencedContainer = "container:">
</BuildableReference>
<LocationScenarioReference
identifier = "com.apple.dt.IDEFoundation.CurrentLocationScenarioIdentifier"
referenceType = "1">
</LocationScenarioReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "847A58031C294F750028FB84"
BuildableName = "FoldingCell.app"
BlueprintName = "FoldingCell"
ReferencedContainer = "container:">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "847A58031C294F750028FB84"
BuildableName = "FoldingCell.app"
BlueprintName = "FoldingCell"
ReferencedContainer = "container:">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "847A58031C294F750028FB84"
BuildableName = "FoldingCell.app"
BlueprintName = "FoldingCell"
ReferencedContainer = "container:">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
@@ -20,6 +20,20 @@
ReferencedContainer = "container:FoldingCell.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "NO"
buildForRunning = "NO"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "8498513B1C5639F9006FA400"
BuildableName = "FoldingCellTests.xctest"
BlueprintName = "FoldingCellTests"
ReferencedContainer = "container:FoldingCell.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
@@ -28,16 +42,6 @@
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "8498513B1C5639F9006FA400"
BuildableName = "FoldingCellTests.xctest"
BlueprintName = "FoldingCellTests"
ReferencedContainer = "container:FoldingCell.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
@@ -1,8 +1,8 @@
<?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>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9529"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9530"/>
</dependencies>
<customFonts key="customFonts">
<mutableArray key="OpenSans-Light.ttf">
+1 -2
View File
@@ -21,8 +21,7 @@ class DemoCell: FoldingCell {
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]
}
@@ -24,462 +24,482 @@
import UIKit
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
@IBOutlet weak var containerView: UIView!
@IBOutlet weak var foregroundView: RotatedView!
var animationView: UIView?
configureDefaultState()
@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]?
public enum AnimationType {
case Open
case Close
guard let foregroundConstraint = foregroundTopConstraint else {
fatalError("set identifier")
}
// MARK: life cicle
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)
guard let containerConstraint = containerViewTopConstraint else {
fatalError("set identifier")
}
func createAnimationItemView()->[RotatedView] {
var items = [RotatedView]()
items.append(foregroundView)
var rotatedViews = [RotatedView]()
for itemView in animationView!.subviews.filter({$0 is RotatedView}).sort({ $0.tag < $1.tag }) as! [RotatedView] {
rotatedViews.append(itemView)
if itemView.backView != nil {
rotatedViews.append(itemView.backView!)
}
}
items.appendContentsOf(rotatedViews)
return items
containerConstraint.constant = foregroundConstraint.constant
containerView.alpha = 0;
foregroundView.layer.anchorPoint = CGPoint.init(x: 0.5, y: 1)
foregroundConstraint.constant += foregroundView.bounds.height / 2
foregroundView.layer.transform = foregroundView.transform3d()
createAnimationView();
self.contentView.bringSubviewToFront(foregroundView)
}
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 {
for view in animationView!.subviews.filter({$0 is RotatedView}) {
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;
}
view.alpha = 0
} else {
if animated {
closeAnimation(completion: completion)
} else {
foregroundView.alpha = 1;
containerView.alpha = 0;
}
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 = 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)
newConstraints.append(newConstraint)
} else if let item: UIView = constraint.secondItem as? UIView where 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;
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 += 1;
}
public func isAnimating()->Bool {
guard animationItemViews != nil
else {
return false
}
for item in animationItemViews! {
if item.layer.animationKeys()?.count > 0 {
return true
}
}
if animationView?.alpha == 1 {
return true
}
return false
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() {
// MARK: animations
public func animationDuration(itemIndex:NSInteger, type:AnimationType)-> NSTimeInterval {
assert(false, "added this method to cell")
return 0
guard let animationView = self.animationView else {
return
}
animationView.subviews.forEach({ $0.removeFromSuperview() })
}
// MARK: public
public func selectedAnimation(isSelected: Bool, animated: Bool, completion: CompletionHandler?) {
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
addImageItemsToAnimationView()
}
animationView?.alpha = 1;
if isSelected {
if animated {
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)
for var index = 0; index < animationItemViews?.count; index++ {
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
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?()
}
openAnimation(completion: completion)
} else {
foregroundView.alpha = 0
containerView.alpha = 1;
}
} else {
if animated {
closeAnimation(completion: completion)
} else {
foregroundView.alpha = 1;
containerView.alpha = 0;
}
}
}
public func isAnimating()->Bool {
guard let animationItemViews = self.animationItemViews else {
return false
}
func closeAnimation(completion completion: CompletionHandler?) {
if animationView?.subviews.count == 0 { // added animation items if need
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
}
for item in animationItemViews {
if item.layer.animationKeys()?.count > 0 {
return true
}
}
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.cornerRadius = 0
if let durationLast = durations.last {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64((delay - durationLast - durationLast / 2.0) * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) { () -> Void in
firstItemView?.layer.cornerRadius = self.foregroundView.layer.cornerRadius
}
}
}
}
}
// MARK: RotatedView
public class RotatedView: UIView {
var hiddenAfterAnimation = false
var backView: RotatedView?
var hiddenAfterAnimation = false
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) {
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
view.addConstraint(NSLayoutConstraint(item: view,
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)
])
}
view.addConstraint(NSLayoutConstraint(item: view, 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 {
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) {
var allTransofrom = CATransform3DIdentity;
let rotateTransform = CATransform3DMakeRotation(angle, 1, 0, 0)
allTransofrom = CATransform3DConcat(allTransofrom, rotateTransform)
allTransofrom = CATransform3DConcat(allTransofrom, transform3d())
self.layer.transform = allTransofrom
}
let rotateAnimation = CABasicAnimation(keyPath: "transform.rotation.x")
rotateAnimation.timingFunction = CAMediaTimingFunction(name: timing)
rotateAnimation.fromValue = (from)
rotateAnimation.toValue = (to)
rotateAnimation.duration = duration
rotateAnimation.delegate = self;
rotateAnimation.fillMode = kCAFillModeForwards
rotateAnimation.removedOnCompletion = false;
rotateAnimation.beginTime = CACurrentMediaTime() + delay
func transform3d()-> CATransform3D {
var transform = CATransform3DIdentity
transform.m34 = 2.5 / -2000;
return transform
}
self.hiddenAfterAnimation = hidden
// MARK: animations
func foldingAnimation(timing: String, from: CGFloat, to: CGFloat, duration: NSTimeInterval, delay:NSTimeInterval, hidden:Bool) {
let rotateAnimation = CABasicAnimation(keyPath: "transform.rotation.x")
rotateAnimation.timingFunction = CAMediaTimingFunction(name: timing)
rotateAnimation.fromValue = (from)
rotateAnimation.toValue = (to)
rotateAnimation.duration = duration
rotateAnimation.delegate = self;
rotateAnimation.fillMode = kCAFillModeForwards;
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.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))
}
}
extension UIView {
func pb_takeSnapshot(frame: CGRect) -> UIImage {
UIGraphicsBeginImageContextWithOptions(frame.size, false, 0.0);
let context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, frame.origin.x * -1, frame.origin.y * -1);
self.layer.renderInContext(UIGraphicsGetCurrentContext()!);
let image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image
func pb_takeSnapshot(frame: CGRect) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(frame.size, false, 0.0)
let context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, frame.origin.x * -1, frame.origin.y * -1)
guard let currentContext = UIGraphicsGetCurrentContext() else {
return nil
}
self.layer.renderInContext(currentContext)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
@@ -94,7 +94,7 @@ class MainTableViewController: UITableViewController {
} else {// close cell
cellHeights[indexPath.row] = kCloseCellHeight
cell.selectedAnimation(false, animated: true, completion: nil)
duration = 1.1
duration = 0.8
}
UIView.animateWithDuration(duration, delay: 0, options: .CurveEaseOut, animations: { () -> Void in
+9 -3
View File
@@ -1,12 +1,16 @@
![header](./header.png)
# FoldingCell
[![CocoaPods](https://img.shields.io/cocoapods/p/FoldingCell.svg)](https://cocoapods.org/pods/FoldingCell)
[![CocoaPods](https://img.shields.io/cocoapods/v/FoldingCell.svg)](http://cocoapods.org/pods/FoldingCell)
[![Twitter](https://img.shields.io/badge/Twitter-@Ramotion-blue.svg?style=flat)](http://twitter.com/Ramotion)
[![Travis](https://img.shields.io/travis/Ramotion/folding-cell.svg)](https://travis-ci.org/Ramotion/folding-cell)
[![codebeat badge](https://codebeat.co/badges/6f67da5d-c416-4bac-9fb7-c2dc938feedc)](https://codebeat.co/projects/github-com-ramotion-folding-cell)
[shot on dribbble](https://dribbble.com/shots/2121350-Delivery-Card):
![Animation](Screenshots/folding-cell.gif)
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
- iOS 8.0+
@@ -18,7 +22,7 @@ Just add the FoldingCell.swift file to your project.
or use [CocoaPods](https://cocoapods.org) with Podfile:
``` ruby
pod 'FoldingCell', '~> 0.3'
pod 'FoldingCell', '~> 0.8.0'
```
@@ -47,7 +51,9 @@ property `containerView`. Add constraints from this view to the superview like i
Your result should be something like this picture:
![1.3](/Tutorial-resources/1.3.png)
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.
@@ -132,7 +138,7 @@ Ok, we've finished configuring the cell.
## Licence
Adaptive tab bar is released under the MIT license.
Folding cell is released under the MIT license.
See [LICENSE](./LICENSE) for details.
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB