29 Commits

Author SHA1 Message Date
Ramotion cb471b2295 Update README.md 2020-04-06 10:00:09 +03:00
igor.k 0ae093ea75 support swift package manager 2019-11-12 03:13:39 +03:00
Ramotion 7bec499be2 Update README.md 2019-10-12 21:08:34 +03:00
Alex K 74f93c36d5 bump version 2019-04-03 16:04:09 +03:00
Alex K 4deca2d95b converted to swift 5 2019-04-03 16:02:57 +03:00
Alex K e15d420969 Merge branch 'master' of github.com:Ramotion/preview-transition 2019-04-03 15:58:22 +03:00
Alex K e08f300ebe no message 2019-04-03 15:58:09 +03:00
Ramotion 643469a4b4 Update README.md 2018-12-29 16:53:45 +03:00
Ramotion 2f8f77fb5c Update README.md 2018-12-10 12:13:28 +03:00
Alex K 2f8eb0632e update deployment target 2018-09-17 10:28:45 +03:00
Alex K f494d7f185 update podspec 2018-09-17 09:49:34 +03:00
Alex K 4f8b51b5bc convert to swift 4.2 2018-09-17 09:44:19 +03:00
Ramotion 79537b624f Update README.md 2018-06-29 14:22:43 +03:00
Ramotion 3271e28008 Update README.md 2018-06-26 11:17:19 +03:00
Ramotion 01fdcfd333 Update README.md 2018-05-29 12:01:14 +03:00
Alex K c0c3d33058 update demo project 2018-05-18 17:15:50 +03:00
Ramotion 9bae1297b2 Update README.md 2018-04-27 12:17:33 +03:00
Ramotion 13d845634a Add files via upload 2018-04-27 02:16:25 -07:00
Ramotion 226b67b654 Update README.md 2018-04-23 09:32:49 +03:00
Ramotion d3f4abfee8 Update README.md 2018-03-12 11:03:27 +03:00
Alex Mikhnev 3edf6223f7 Update README.md 2018-02-21 14:52:26 +03:00
i.kolpachkov be9990001f fixed #4 (Inspectable foregroundAlpha not working) 2018-01-18 20:19:07 +03:00
i.kolpachkov 4f143e39c5 config swift version 2018-01-18 19:38:42 +03:00
i.kolpachkov 1790d05c1d add demo icon, configure travis CI 2018-01-18 19:35:20 +03:00
i.kolpachkov cfd8a8349c fixed #15 (Image Content Mode) 2018-01-16 20:37:48 +03:00
i.kolpachkov fa277edea0 bump pod version 2018-01-16 20:17:21 +03:00
i.kolpachkov a9f62a47b8 update code format 2018-01-16 20:15:58 +03:00
i.kolpachkov 37440b4029 source code cleanup, iphone X layout adaptation, common improvements
fixed #17 (Problem with top border on iPhone X)
2018-01-16 20:12:46 +03:00
Alex K 55c93633af update readme and podspec 2017-11-27 15:54:32 +03:00
43 changed files with 1368 additions and 1387 deletions
+1
View File
@@ -0,0 +1 @@
4.2
+7 -2
View File
@@ -1,6 +1,11 @@
osx_image: xcode7.3
osx_image: xcode9.2
language: objective-c
xcode_project: PreviewTransitionDemo/PreviewTransitionDemo.xcodeproj
xcode_scheme: PreviewTransition
xcode_sdk: iphonesimulator
xcode_sdk: iphonesimulator11.2
# whitelist
branches:
only:
- master
+43
View File
@@ -0,0 +1,43 @@
// swift-tools-version:5.1
//
// Package.swift
//
// Copyright (c) Ramotion Inc. (https://www.ramotion.com/)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
import PackageDescription
let package = Package(
name: "PreviewTransition",
platforms: [
.iOS(.v9)
],
products: [
.library(name: "PreviewTransition",
targets: ["PreviewTransition"]),
],
targets: [
.target(name: "PreviewTransition",
path: "PreviewTransition")
],
swiftLanguageVersions: [.v5]
)
+1 -1
View File
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'PreviewTransition'
s.version = '2.0.1'
s.version = '4.1.0'
s.summary = 'Transition animation'
s.license = 'MIT'
s.homepage = 'https://github.com/Ramotion/preview-transition'
@@ -25,113 +25,96 @@ import UIKit
/// Base UIViewController for preview transition
open class PTDetailViewController: UIViewController {
var bgImage: UIImage?
var titleText: String?
fileprivate var backgroundImageView: UIImageView?
var bgImage: UIImage?
var titleText: String?
fileprivate var backgroundImageView: UIImageView?
}
// MARK: life cicle
extension PTDetailViewController {
open override func viewDidLoad() {
super.viewDidLoad()
backgroundImageView = createBackgroundImage(bgImage)
view.backgroundColor = .black
if let titleText = self.titleText {
title = titleText
extension PTDetailViewController {
open override func viewDidLoad() {
super.viewDidLoad()
backgroundImageView = createBackgroundImage(bgImage)
view.backgroundColor = .black
if let titleText = self.titleText {
title = titleText
}
// hack
if let navigationController = self.navigationController {
for case let label as UILabel in navigationController.view.subviews {
label.isHidden = true
}
}
_ = createNavBar(UIColor(red: 0, green: 0, blue: 0, alpha: 0.5))
}
// hack
if let navigationController = self.navigationController {
for case let label as UILabel in navigationController.view.subviews {
label.isHidden = true
}
}
let _ = createNavBar(UIColor(red: 0, green: 0, blue: 0, alpha: 0.5))
}
open override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
}
// MARK: public
extension PTDetailViewController {
/**
Pops the top view controller from the navigation stack and updates the display with custom animation.
*/
public func popViewController() {
if let navigationController = self.navigationController {
for case let label as UILabel in navigationController.view.subviews {
label.isHidden = false
}
/**
Pops the top view controller from the navigation stack and updates the display with custom animation.
*/
public func popViewController() {
if let navigationController = self.navigationController {
for case let label as UILabel in navigationController.view.subviews {
label.isHidden = false
}
}
_ = navigationController?.popViewController(animated: false)
}
let _ = navigationController?.popViewController(animated: false)
}
}
// MARK: create
extension PTDetailViewController {
fileprivate func createBackgroundImage(_ image: UIImage?) -> UIImageView {
// add constraint closures
let addConstraint: (_ imageView: UIImageView, _ toView: UIView, _ attribute: NSLayoutAttribute) -> () = {
(imageView, toView, attribute) in
let constraint = NSLayoutConstraint(item: imageView,
attribute: attribute,
relatedBy: .equal,
toItem: toView,
attribute: attribute,
multiplier: 1,
constant: 0)
toView.addConstraint(constraint)
}
// crate imageView
let imageView = UIImageView(frame: CGRect.zero)
imageView.image = image
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .center
view.insertSubview(imageView, at: 0)
// added constraints
for attribute in [NSLayoutAttribute.leading, NSLayoutAttribute.trailing, NSLayoutAttribute.top, NSLayoutAttribute.bottom] {
addConstraint(imageView, view, attribute)
}
return imageView
}
fileprivate func createNavBar(_ color: UIColor) -> UIView {
let navBar = UIView(frame: CGRect.zero)
navBar.backgroundColor = color
navBar.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(navBar)
for attributes: NSLayoutAttribute in [.left, .right, .top] {
(view, navBar) >>>- {
$0.attribute = attributes
return
}
}
navBar >>>- {
$0.attribute = .height
$0.constant = 64
return
}
return navBar
}
fileprivate func createBackgroundImage(_ image: UIImage?) -> UIImageView {
let imageView = UIImageView(frame: CGRect.zero)
imageView.image = image
imageView.frame = view.bounds
imageView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
imageView.contentMode = UIView.ContentMode.scaleAspectFill
view.insertSubview(imageView, at: 0)
return imageView
}
fileprivate func createNavBar(_ color: UIColor) -> UIView {
let navBar = UIView(frame: CGRect.zero)
navBar.backgroundColor = color
navBar.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(navBar)
for attributes: NSLayoutConstraint.Attribute in [.left, .right, .top] {
(view, navBar) >>>- {
$0.attribute = attributes
return
}
}
navBar >>>- {
$0.attribute = .height
var constant: CGFloat = 64
if #available(iOS 11.0, *) {
if let topPadding = UIApplication.shared.keyWindow?.safeAreaInsets.top {
constant += topPadding
}
}
$0.constant = constant
return
}
return navBar
}
}
@@ -24,392 +24,409 @@
import UIKit
fileprivate struct C {
struct Constraints {
static let bottom = "Bottom"
static let height = "Height"
}
struct Constraints {
static let bottom = "Bottom"
static let height = "Height"
}
}
/// UITableViewCell with parallax background
open class ParallaxCell: UITableViewCell {
/// Custom separator view
open var separatorView: UIView?
var topSeparator: UIView? // only for animation
enum Direction {
case up
case down
}
var bgImageY: NSLayoutConstraint?
var parallaxTitleY: NSLayoutConstraint?
/// parallax offset
@IBInspectable open var difference: CGFloat = 100 // image parallax
var bgImage: UIImageView?
var parallaxTitle: UILabel?
/// The foreground views background color.
@IBInspectable open var foregroundColor = UIColor.black
/// The foreground views alpha.
@IBInspectable open var foregroundAlpha: CGFloat = 0.5
var foregroundView: UIView?
var isMovedHidden: Bool = false
fileprivate var closedBgImageYConstant: CGFloat = 0
fileprivate var closedYPosition: CGFloat = 0
fileprivate var damping: CGFloat = 0.78
/**
Initializes a view from data in a given unarchiver.
- parameter aDecoder: An unarchiver object.
- returns: An initialized UITableViewCell object.
*/
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
/**
Initializes a table cell with a style and a reuse identifier and returns it to the caller.
- parameter style: A constant indicating a cell style. See UITableViewCellStyle for descriptions of these constants.
- parameter reuseIdentifier: A string used to identify the cell object if it is to be reused for drawing multiple rows of a table view. Pass nil if the cell object is not to be reused. You should use the same reuse identifier for all cells of the same form.
- returns: an initialized UITableViewCell object or nil if the object could not be created.
*/
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
commonInit()
}
/// Custom separator view
open var separatorView: UIView?
var topSeparator: UIView? // only for animation
enum Direction {
case up
case down
}
private var bgImageY: NSLayoutConstraint?
private var bgImageHeight: NSLayoutConstraint?
private var parallaxTitleY: NSLayoutConstraint?
/// parallax offset
@IBInspectable open var difference: CGFloat = 100 // image parallax
var bgImage: UIImageView?
var parallaxTitle: UILabel?
/// The foreground views background color.
@IBInspectable open var foregroundColor: UIColor = UIColor.black {
didSet {
foregroundView?.backgroundColor = foregroundColor
}
}
/// The foreground views alpha.
@IBInspectable open var foregroundAlpha: CGFloat = 0.5 {
didSet {
foregroundView?.alpha = foregroundAlpha
}
}
var foregroundView: UIView?
var isMovedHidden: Bool = false
fileprivate var closedBgImageYConstant: CGFloat = 0
fileprivate var closedYPosition: CGFloat = 0
fileprivate var closedHeight: CGFloat = 0
fileprivate var damping: CGFloat = 0.78
/**
Initializes a view from data in a given unarchiver.
- parameter aDecoder: An unarchiver object.
- returns: An initialized UITableViewCell object.
*/
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
/**
Initializes a table cell with a style and a reuse identifier and returns it to the caller.
- parameter style: A constant indicating a cell style. See UITableViewCellStyle for descriptions of these constants.
- parameter reuseIdentifier: A string used to identify the cell object if it is to be reused for drawing multiple rows of a table view. Pass nil if the cell object is not to be reused. You should use the same reuse identifier for all cells of the same form.
- returns: an initialized UITableViewCell object or nil if the object could not be created.
*/
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
commonInit()
}
}
// MARK: life cicle
extension ParallaxCell {
func commonInit() {
layer.masksToBounds = false
selectionStyle = .none
// create background image view
let backgroundImageView = createBckgroundImage()
// add constraints
if let bgSuperView = backgroundImageView.superview {
for attribute: NSLayoutAttribute in [.leading, .trailing] {
(bgSuperView, backgroundImageView) >>>- {
$0.attribute = attribute
return
func commonInit() {
layer.masksToBounds = false
selectionStyle = .none
// create background image view
let backgroundImageView = createBckgroundImage()
// add constraints
if let bgSuperView = backgroundImageView.superview {
for attribute: NSLayoutConstraint.Attribute in [.leading, .trailing] {
(bgSuperView, backgroundImageView) >>>- {
$0.attribute = attribute
return
}
}
bgImageY = (bgSuperView, backgroundImageView) >>>- {
$0.attribute = .centerY
return
}
bgImageHeight = backgroundImageView >>>- {
$0.attribute = .height
$0.constant = bounds.height + difference
return
}
}
}
bgImageY = (bgSuperView, backgroundImageView) >>>- {
$0.attribute = .centerY
return
}
backgroundImageView >>>- {
$0.attribute = .height
$0.constant = bounds.height + difference
return
}
bgImage = backgroundImageView
foregroundView = createForegroundView(foregroundColor)
contentView.backgroundColor = UIColor.black
// create title label
let titleLabel = createTitleLable()
for attribute: NSLayoutConstraint.Attribute in [.left, .right] {
(contentView, titleLabel) >>>- {
$0.attribute = attribute
return
}
}
parallaxTitleY = (contentView, titleLabel) >>>- {
$0.attribute = .centerY
return
}
titleLabel >>>- {
$0.attribute = .height
$0.constant = bounds.height + difference
return
}
parallaxTitle = titleLabel
separatorView = createSeparator(.black, height: 2.0, verticalAttribure: .bottom, verticalConstant: 0.0)
}
bgImage = backgroundImageView
foregroundView = createForegroundView(foregroundColor)
contentView.backgroundColor = UIColor.black
// create title label
let titleLabel = createTitleLable()
for attribute: NSLayoutAttribute in [.left, .right] {
(contentView, titleLabel) >>>- {
$0.attribute = attribute
return
}
}
parallaxTitleY = (contentView, titleLabel) >>>- {
$0.attribute = .centerY
return
open override func prepareForReuse() {
if topSeparator?.superview != nil {
topSeparator?.removeFromSuperview()
topSeparator = nil
}
}
titleLabel >>>- {
$0.attribute = .height
$0.constant = bounds.height + difference
return
}
parallaxTitle = titleLabel
separatorView = createSeparator(.black, height: 2.0, verticalAttribure: .bottom, verticalConstant: 0.0)
}
open override func prepareForReuse() {
if topSeparator?.superview != nil {
topSeparator?.removeFromSuperview()
topSeparator = nil
}
}
}
// MARK: Methods
public extension ParallaxCell {
/**
Sets the contents of the background image and title label
- parameter image: The image object which set to the backgroundImageView
- parameter title: The text to be displayed in the Cell
*/
public func setImage(_ image: UIImage, title: String) {
bgImage?.image = image
parallaxTitle?.text = title
}
/**
Sets the contents of the background image and title label
- parameter image: The image object which set to the backgroundImageView
- parameter title: The text to be displayed in the Cell
*/
func setImage(_ image: UIImage, title: String) {
bgImage?.image = image
parallaxTitle?.text = title
}
}
// MARK: internal
extension ParallaxCell {
func parallaxOffset(_ tableView: UITableView) {
guard let bgImageY = self.bgImageY , isMovedHidden == false else {
return
}
var deltaY = (frame.origin.y + frame.height/2) - tableView.contentOffset.y
deltaY = min(tableView.bounds.height, max(deltaY, 0)) // range
var move : CGFloat = (deltaY / tableView.bounds.height) * difference
move = move / 2.0 - move
bgImageY.constant = move
}
func openCell(_ tableView: UITableView, duration: Double) {
guard let superview = self.superview,
let bgImageY = self.bgImageY else {
return
}
closedBgImageYConstant = bgImageY.constant
closedYPosition = center.y
let offsetY = tableView.contentOffset.y
let cellY = frame.origin.y - offsetY + frame.size.height / 2.0 + offsetY - tableView.frame.size.height / 2.0
let cellFrame = CGRect(x: 0, y: cellY, width: tableView.frame.size.width, height: tableView.frame.size.height)
frame = cellFrame
superview.sendSubview(toBack: self)
// animation
moveToCenter(duration , offset: offsetY)
parallaxTitle?.isHidden = true
foregroundHidden(true, duration: duration)
}
func closeCell(_ duration: Double, tableView: UITableView, completion: @escaping () -> Void) {
bgImageY?.constant = closedBgImageYConstant
UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: damping, initialSpringVelocity: 0, options: UIViewAnimationOptions(), animations: { [weak self] () in
guard let `self` = self else { return }
self.bgImage?.superview?.layoutIfNeeded()
self.center = CGPoint(x: self.center.x, y: self.closedYPosition)
}, completion: {[weak self] finished in
self?.parallaxTitle?.isHidden = false
completion()
})
foregroundHidden(false, duration: duration / 2.0)
}
func parallaxOffset(_ tableView: UITableView) {
func animationMoveCell(_ direction: Direction, duration: Double, tableView: UITableView, selectedIndexPaht: IndexPath, close: Bool) {
let selfYPosition = close == false ? frame.origin.y : closedYPosition
let selectedCellFrame = tableView.rectForRow(at: selectedIndexPaht)
var dy: CGFloat = 0
if selfYPosition < selectedCellFrame.origin.y {
dy = selectedCellFrame.origin.y - tableView.contentOffset.y
} else {
dy = tableView.frame.size.height - (selectedCellFrame.origin.y - tableView.contentOffset.y + selectedCellFrame.size.height)
guard let bgImageY = self.bgImageY, isMovedHidden == false else {
return
}
var deltaY = (frame.origin.y + frame.height / 2) - tableView.contentOffset.y
deltaY = min(tableView.bounds.height, max(deltaY, 0)) // range
var move: CGFloat = (deltaY / tableView.bounds.height) * difference
move = move / 2.0 - move
bgImageY.constant = move
}
dy = direction == .down ? dy * -1 : dy
if close == false {
closedYPosition = center.y
} else {
center.y = closedYPosition - dy
func openCell(_ tableView: UITableView, duration: Double) {
guard let superview = self.superview,
let bgImageY = self.bgImageY,
let bgImageHeight = self.bgImageHeight else {
return
}
closedBgImageYConstant = bgImageY.constant
closedYPosition = center.y
closedHeight = bgImageHeight.constant
let offsetY = tableView.contentOffset.y
let cellY = frame.origin.y - offsetY + frame.size.height / 2.0 + offsetY - tableView.frame.size.height / 2.0
let cellFrame = CGRect(x: 0, y: cellY, width: tableView.frame.size.width, height: tableView.frame.size.height)
frame = cellFrame
superview.sendSubviewToBack(self)
// animation
bgImageHeight.constant = cellFrame.height
moveToCenter(duration, offset: offsetY)
parallaxTitle?.isHidden = true
foregroundHidden(true, duration: duration)
}
func closeCell(_ duration: Double, tableView _: UITableView, completion: @escaping () -> Void) {
bgImageY?.constant = closedBgImageYConstant
bgImageHeight?.constant = closedHeight
UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: damping, initialSpringVelocity: 0, options: UIView.AnimationOptions(), animations: { [weak self] () in
guard let `self` = self else { return }
self.bgImage?.superview?.layoutIfNeeded()
self.center = CGPoint(x: self.center.x, y: self.closedYPosition)
}, completion: { [weak self] _ in
self?.parallaxTitle?.isHidden = false
completion()
})
foregroundHidden(false, duration: duration / 2.0)
}
func animationMoveCell(_ direction: Direction, duration: Double, tableView: UITableView, selectedIndexPaht: IndexPath, close: Bool) {
let selfYPosition = close == false ? frame.origin.y : closedYPosition
let selectedCellFrame = tableView.rectForRow(at: selectedIndexPaht)
var dy: CGFloat = 0
if selfYPosition < selectedCellFrame.origin.y {
dy = selectedCellFrame.origin.y - tableView.contentOffset.y
} else {
dy = tableView.frame.size.height - (selectedCellFrame.origin.y - tableView.contentOffset.y + selectedCellFrame.size.height)
}
dy = direction == .down ? dy * -1 : dy
if close == false {
closedYPosition = center.y
} else {
center.y = closedYPosition - dy
}
superview?.bringSubviewToFront(self)
UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: damping, initialSpringVelocity: 0, options: UIView.AnimationOptions(), animations: { () -> Void in
self.center.y = self.center.y + dy
}, completion: nil)
}
func showTopSeparator() {
topSeparator = createSeparator(.black, height: 2, verticalAttribure: .top, verticalConstant: -2)
}
superview?.bringSubview(toFront: self)
UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: damping, initialSpringVelocity: 0, options: UIViewAnimationOptions(), animations: { () -> Void in
self.center.y = self.center.y + dy
}, completion: nil)
}
func showTopSeparator() {
topSeparator = createSeparator(.black, height: 2, verticalAttribure: .top, verticalConstant: -2)
}
}
// MARK: animation
extension ParallaxCell {
fileprivate func moveToCenter(_ duration: Double, offset: CGFloat) {
bgImageY?.constant = 0
UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: 0.78, initialSpringVelocity: 0, options: UIViewAnimationOptions(), animations: { () -> Void in
self.frame.origin.y = offset
self.bgImage?.superview?.layoutIfNeeded()
}, completion: nil)
}
fileprivate func foregroundHidden(_ hidden: Bool, duration: Double) {
guard let foregroundView = self.foregroundView else {
return
fileprivate func moveToCenter(_ duration: Double, offset: CGFloat) {
bgImageY?.constant = 0
UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: 0.78, initialSpringVelocity: 0, options: UIView.AnimationOptions(), animations: { () -> Void in
self.frame.origin.y = offset
self.bgImage?.superview?.layoutIfNeeded()
}, completion: nil)
}
if hidden == true {
let currentConstrant = contentView.constraints.filter{return $0.identifier == C.Constraints.bottom ? true : false}
contentView.removeConstraints(currentConstrant)
foregroundView >>>- {
$0.attribute = .height
$0.constant = 64
$0.identifier = C.Constraints.height
return
}
} else {
let currentConstrant = foregroundView.constraints.filter{return $0.identifier == C.Constraints.height ? true : false}
foregroundView.removeConstraints(currentConstrant)
(contentView, foregroundView) >>>- {
$0.attribute = .bottom
$0.identifier = C.Constraints.bottom
return
}
fileprivate func foregroundHidden(_ hidden: Bool, duration: Double) {
guard let foregroundView = self.foregroundView else {
return
}
if hidden == true {
let currentConstrant = contentView.constraints.filter { return $0.identifier == C.Constraints.bottom ? true : false }
contentView.removeConstraints(currentConstrant)
foregroundView >>>- {
$0.attribute = .height
var constant: CGFloat = 64
if #available(iOS 11.0, *) {
if let topPadding = UIApplication.shared.keyWindow?.safeAreaInsets.top {
constant += topPadding
}
}
$0.constant = constant
$0.identifier = C.Constraints.height
return
}
} else {
let currentConstrant = foregroundView.constraints.filter { return $0.identifier == C.Constraints.height ? true : false }
foregroundView.removeConstraints(currentConstrant)
(contentView, foregroundView) >>>- {
$0.attribute = .bottom
$0.identifier = C.Constraints.bottom
return
}
}
UIView.animate(withDuration: duration,
delay: 0,
usingSpringWithDamping: damping * 2.0,
initialSpringVelocity: 0,
options: UIView.AnimationOptions(),
animations: { () -> Void in
foregroundView.superview?.layoutIfNeeded()
}, completion: nil)
}
UIView.animate(withDuration: duration,
delay: 0,
usingSpringWithDamping: damping * 2.0,
initialSpringVelocity: 0,
options: UIViewAnimationOptions(),
animations: { () -> Void in
foregroundView.superview?.layoutIfNeeded()
}, completion: nil)
}
}
// MARK: create
extension ParallaxCell {
fileprivate func createBckgroundImage() -> UIImageView {
let container = createImageContainer()
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .center
container.addSubview(imageView)
return imageView
}
fileprivate func createImageContainer() -> UIView {
let view = UIView(frame: CGRect.zero)
view.translatesAutoresizingMaskIntoConstraints = false
view.layer.masksToBounds = true
contentView.addSubview(view)
// added constraints
for attribute: NSLayoutAttribute in [.left, .right, .top, .bottom] {
(contentView, view) >>>- {
$0.attribute = attribute
return
}
}
return view
}
// MARK: create
fileprivate func createTitleLable() -> UILabel {
let label = UILabel()
label.backgroundColor = .clear
label.translatesAutoresizingMaskIntoConstraints = false
label.textAlignment = .center
if case let font as UIFont = UINavigationBar.appearance().titleTextAttributes?[NSAttributedStringKey.font] {
label.font = font
extension ParallaxCell {
fileprivate func createBckgroundImage() -> UIImageView {
let container = UIView(frame: contentView.bounds)
container.translatesAutoresizingMaskIntoConstraints = false
container.backgroundColor = .clear
container.clipsToBounds = true
contentView.addSubview(container)
for attribute: NSLayoutConstraint.Attribute in [.left, .right, .top, .bottom] {
(contentView, container) >>>- {
$0.attribute = attribute
return
}
}
let imageView = UIImageView(frame: container.bounds)
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFill
container.addSubview(imageView)
return imageView
}
if case let textColor as UIColor = UINavigationBar.appearance().titleTextAttributes?[NSAttributedStringKey.foregroundColor] {
label.textColor = textColor
fileprivate func createTitleLable() -> UILabel {
let label = UILabel()
label.backgroundColor = .clear
label.translatesAutoresizingMaskIntoConstraints = false
label.textAlignment = .center
if case let font as UIFont = UINavigationBar.appearance().titleTextAttributes?[NSAttributedString.Key.font] {
label.font = font
}
if case let textColor as UIColor = UINavigationBar.appearance().titleTextAttributes?[NSAttributedString.Key.foregroundColor] {
label.textColor = textColor
}
contentView.addSubview(label)
return label
}
contentView.addSubview(label)
return label
}
}
// MARK: cofigure
extension ParallaxCell {
fileprivate func createForegroundView(_ color: UIColor) -> UIView {
guard let bgImage = self.bgImage else {
fatalError("set bgImage")
fileprivate func createForegroundView(_ color: UIColor) -> UIView {
guard let bgImage = self.bgImage else {
fatalError("set bgImage")
}
let foregroundView = UIView()
foregroundView.alpha = foregroundAlpha
foregroundView.backgroundColor = color
foregroundView.translatesAutoresizingMaskIntoConstraints = false
contentView.insertSubview(foregroundView, aboveSubview: bgImage)
// add constraints
for attribute: NSLayoutConstraint.Attribute in [.left, .right, .top] {
(contentView, foregroundView) >>>- {
$0.attribute = attribute
return
}
}
(contentView, foregroundView) >>>- {
$0.attribute = .bottom
$0.identifier = C.Constraints.bottom
return
}
return foregroundView
}
let foregroundView = UIView()
foregroundView.alpha = foregroundAlpha
foregroundView.backgroundColor = color
foregroundView.translatesAutoresizingMaskIntoConstraints = false
contentView.insertSubview(foregroundView, aboveSubview: bgImage)
// add constraints
for attribute: NSLayoutAttribute in [.left, .right, .top] {
(contentView, foregroundView) >>>- {
$0.attribute = attribute
return
}
// return bottom constraint
fileprivate func createSeparator(_ color: UIColor, height: CGFloat, verticalAttribure: NSLayoutConstraint.Attribute, verticalConstant: CGFloat) -> UIView {
let separator = UIView(frame: CGRect.zero)
separator.backgroundColor = color
separator.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(separator)
for attribute: NSLayoutConstraint.Attribute in [.leading, .trailing] {
(contentView, separator) >>>- {
$0.attribute = attribute
return
}
}
(contentView, separator) >>>- {
$0.attribute = verticalAttribure
$0.constant = verticalConstant
return
}
// height constraint
separator >>>- {
$0.attribute = .height
$0.constant = height
return
}
return separator
}
(contentView, foregroundView) >>>- {
$0.attribute = .bottom
$0.identifier = C.Constraints.bottom
return
}
return foregroundView
}
// return bottom constraint
fileprivate func createSeparator(_ color: UIColor, height: CGFloat, verticalAttribure: NSLayoutAttribute, verticalConstant: CGFloat) -> UIView {
let separator = UIView(frame: CGRect.zero)
separator.backgroundColor = color
separator.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(separator)
for attribute: NSLayoutAttribute in [.leading, .trailing] {
(contentView, separator) >>>- {
$0.attribute = attribute
return
}
}
(contentView, separator) >>>- {
$0.attribute = verticalAttribure
$0.constant = verticalConstant
return
}
// height constraint
separator >>>- {
$0.attribute = .height
$0.constant = height
return
}
return separator
}
}
@@ -23,7 +23,7 @@
import Foundation
func delay(_ delay:Double, closure:@escaping ()->()) {
func delay(_ delay: Double, closure: @escaping () -> Void) {
DispatchQueue.main.asyncAfter(
deadline: DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC), execute: closure)
deadline: DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC), execute: closure)
}
@@ -1,5 +1,5 @@
//
// ConstraintsHalper.swift
// ConstraintsHelper.swift
// AnimatedPageView
//
// Created by Alex K. on 13/04/16.
@@ -9,70 +9,69 @@
import UIKit
struct ConstraintInfo {
var attribute: NSLayoutAttribute = .left
var secondAttribute: NSLayoutAttribute = .notAnAttribute
var constant: CGFloat = 0
var identifier: String?
var relation: NSLayoutRelation = .equal
var attribute: NSLayoutConstraint.Attribute = .left
var secondAttribute: NSLayoutConstraint.Attribute = .notAnAttribute
var constant: CGFloat = 0
var identifier: String?
var relation: NSLayoutConstraint.Relation = .equal
}
precedencegroup constOp {
associativity: left
higherThan: AssignmentPrecedence
associativity: left
higherThan: AssignmentPrecedence
}
infix operator >>>- : constOp
infix operator >>>-: constOp
@discardableResult
func >>>- <T: UIView> (left: (T, T), block: (inout ConstraintInfo) -> Void) -> NSLayoutConstraint {
var info = ConstraintInfo()
block(&info)
info.secondAttribute = info.secondAttribute == .notAnAttribute ? info.attribute : info.secondAttribute
let constraint = NSLayoutConstraint(item: left.1,
attribute: info.attribute,
relatedBy: info.relation,
toItem: left.0,
attribute: info.secondAttribute,
multiplier: 1,
constant: info.constant)
constraint.identifier = info.identifier
left.0.addConstraint(constraint)
return constraint
func >>>- <T: UIView>(left: (T, T), block: (inout ConstraintInfo) -> Void) -> NSLayoutConstraint {
var info = ConstraintInfo()
block(&info)
info.secondAttribute = info.secondAttribute == .notAnAttribute ? info.attribute : info.secondAttribute
let constraint = NSLayoutConstraint(item: left.1,
attribute: info.attribute,
relatedBy: info.relation,
toItem: left.0,
attribute: info.secondAttribute,
multiplier: 1,
constant: info.constant)
constraint.identifier = info.identifier
left.0.addConstraint(constraint)
return constraint
}
@discardableResult
func >>>- <T: UIView> (left: T, block: (inout ConstraintInfo) -> Void) -> NSLayoutConstraint {
var info = ConstraintInfo()
block(&info)
let constraint = NSLayoutConstraint(item: left,
attribute: info.attribute,
relatedBy: info.relation,
toItem: nil,
attribute: info.attribute,
multiplier: 1,
constant: info.constant)
constraint.identifier = info.identifier
left.addConstraint(constraint)
return constraint
func >>>- <T: UIView>(left: T, block: (inout ConstraintInfo) -> Void) -> NSLayoutConstraint {
var info = ConstraintInfo()
block(&info)
let constraint = NSLayoutConstraint(item: left,
attribute: info.attribute,
relatedBy: info.relation,
toItem: nil,
attribute: info.attribute,
multiplier: 1,
constant: info.constant)
constraint.identifier = info.identifier
left.addConstraint(constraint)
return constraint
}
@discardableResult
func >>>- <T: UIView> (left: (T, T, T), block: (inout ConstraintInfo) -> Void) -> NSLayoutConstraint {
var info = ConstraintInfo()
block(&info)
info.secondAttribute = info.secondAttribute == .notAnAttribute ? info.attribute : info.secondAttribute
let constraint = NSLayoutConstraint(item: left.1,
attribute: info.attribute,
relatedBy: info.relation,
toItem: left.2,
attribute: info.secondAttribute,
multiplier: 1,
constant: info.constant)
constraint.identifier = info.identifier
left.0.addConstraint(constraint)
return constraint
}
func >>>- <T: UIView>(left: (T, T, T), block: (inout ConstraintInfo) -> Void) -> NSLayoutConstraint {
var info = ConstraintInfo()
block(&info)
info.secondAttribute = info.secondAttribute == .notAnAttribute ? info.attribute : info.secondAttribute
let constraint = NSLayoutConstraint(item: left.1,
attribute: info.attribute,
relatedBy: info.relation,
toItem: left.2,
attribute: info.secondAttribute,
multiplier: 1,
constant: info.constant)
constraint.identifier = info.identifier
left.0.addConstraint(constraint)
return constraint
}
@@ -29,53 +29,58 @@ internal enum MovingDirection {
}
internal protocol Moving: class {
var defaultYPosition: CGFloat {get set}
func move(_ duration: Double, direction: MovingDirection, completion: ((Bool) -> Void)?)
var defaultYPosition: CGFloat { get set }
func move(_ duration: Double, direction: MovingDirection, completion: ((Bool) -> Void)?)
}
extension Moving where Self: UIView {
func move(_ duration: Double, direction: MovingDirection, completion: ((Bool) -> Void)?) {
UIView.animate(withDuration: duration,
delay: 0,
usingSpringWithDamping: 0.78,
initialSpringVelocity: 0,
options: UIViewAnimationOptions(),
animations: { [weak self] () -> Void in
guard let `self` = self else { return }
var toYPosition = self.defaultYPosition
if direction == .up {
self.defaultYPosition = self.frame.origin.y
toYPosition = 20
}
self.frame = CGRect(x: 0, y: toYPosition, width: self.frame.size.width, height: self.frame.size.height)
}, completion: completion)
}
func move(_ duration: Double, direction: MovingDirection, completion: ((Bool) -> Void)?) {
UIView.animate(withDuration: duration,
delay: 0,
usingSpringWithDamping: 0.78,
initialSpringVelocity: 0,
options: UIView.AnimationOptions(),
animations: { [weak self] () -> Void in
guard let `self` = self else { return }
var toYPosition = self.defaultYPosition
if direction == .up {
self.defaultYPosition = self.frame.origin.y
var position: CGFloat = 20
if #available(iOS 11.0, *) {
if let topPadding = UIApplication.shared.keyWindow?.safeAreaInsets.top {
position = topPadding
}
}
toYPosition = position
}
self.frame = CGRect(x: 0, y: toYPosition, width: self.frame.size.width, height: self.frame.size.height)
}, completion: completion)
}
}
internal class MovingLabel: UILabel, Moving {
var defaultYPosition: CGFloat = 0
var defaultYPosition: CGFloat = 0
}
internal class MovingView: UIView {
var defaultYPosition: CGFloat = 0
internal func move(_ duration: Double, direction: MovingDirection, distance: CGFloat, completion: ((Bool) -> Void)? = nil) {
var yPosition = defaultYPosition - 2
if direction == .down {
defaultYPosition = frame.origin.y
yPosition = distance
}
UIView.animate(withDuration: duration,
delay: 0,
usingSpringWithDamping: 0.78,
initialSpringVelocity: 0,
options: UIViewAnimationOptions(),
animations: { () -> Void in
self.frame.origin.y = yPosition
}, completion: completion)
}
var defaultYPosition: CGFloat = 0
internal func move(_ duration: Double, direction: MovingDirection, distance: CGFloat, completion: ((Bool) -> Void)? = nil) {
var yPosition = defaultYPosition - 2
if direction == .down {
defaultYPosition = frame.origin.y
yPosition = distance
}
UIView.animate(withDuration: duration,
delay: 0,
usingSpringWithDamping: 0.78,
initialSpringVelocity: 0,
options: UIView.AnimationOptions(),
animations: { () -> Void in
self.frame.origin.y = yPosition
}, completion: completion)
}
}
@@ -22,214 +22,216 @@
// THE SOFTWARE.
import UIKit
fileprivate func < <T : Comparable>(lhs: T?, rhs: T?) -> Bool {
switch (lhs, rhs) {
case let (l?, r?):
return l < r
case (nil, _?):
return true
default:
return false
}
fileprivate func < <T: Comparable>(lhs: T?, rhs: T?) -> Bool {
switch (lhs, rhs) {
case let (l?, r?):
return l < r
case (nil, _?):
return true
default:
return false
}
}
/// Base UITableViewController for preview transition
open class PTTableViewController: UITableViewController {
internal var currentCell: ParallaxCell?
fileprivate var duration: Double = 0.65
fileprivate var currentTextLabel: MovingLabel?
internal var currentCell: ParallaxCell?
fileprivate var duration: Double = 0.8
fileprivate var currentTextLabel: MovingLabel?
}
// MARK: public
public extension PTTableViewController {
/**
Pushes a view controller onto the receivers stack and updates the display whith custom animation.
- parameter viewController: The view controller to push onto the stack.
*/
public func pushViewController(_ viewController: PTDetailViewController) {
guard let currentCell = currentCell,
let navigationController = self.navigationController else {
fatalError("current cell is empty or add navigationController")
/**
Pushes a view controller onto the receivers stack and updates the display whith custom animation.
- parameter viewController: The view controller to push onto the stack.
*/
func pushViewController(_ viewController: PTDetailViewController) {
guard let currentCell = currentCell,
let navigationController = self.navigationController else {
fatalError("current cell is empty or add navigationController")
}
if let currentIndex = tableView.indexPath(for: currentCell) {
let nextIndex = IndexPath(row: (currentIndex as NSIndexPath).row + 1, section: (currentIndex as NSIndexPath).section)
if case let nextCell as ParallaxCell = tableView.cellForRow(at: nextIndex) {
nextCell.showTopSeparator()
nextCell.superview?.bringSubviewToFront(nextCell)
}
}
currentTextLabel = createTitleLable(currentCell)
currentTextLabel?.move(duration, direction: .up, completion: nil)
currentCell.openCell(tableView, duration: duration)
moveCells(tableView, currentCell: currentCell, duration: duration)
if let bgImage = currentCell.bgImage?.image {
viewController.bgImage = bgImage
}
if let text = currentCell.parallaxTitle?.text {
viewController.titleText = text
}
delay(duration) {
navigationController.pushViewController(viewController, animated: false)
}
}
if let currentIndex = tableView.indexPath(for: currentCell) {
let nextIndex = IndexPath(row: (currentIndex as NSIndexPath).row + 1, section: (currentIndex as NSIndexPath).section)
if case let nextCell as ParallaxCell = tableView.cellForRow(at: nextIndex) {
nextCell.showTopSeparator()
nextCell.superview?.bringSubview(toFront: nextCell)
}
}
self.currentTextLabel = createTitleLable(currentCell)
currentTextLabel?.move(duration, direction: .up, completion: nil)
currentCell.openCell(tableView, duration: duration)
moveCells(tableView, currentCell: currentCell, duration: duration)
if let bgImage = currentCell.bgImage?.image {
viewController.bgImage = bgImage
}
if let text = currentCell.parallaxTitle?.text {
viewController.titleText = text
}
delay(duration) {
navigationController.pushViewController(viewController, animated: false)
}
}
}
// MARK: life cicle
extension PTTableViewController {
open override func viewDidLoad() {
super.viewDidLoad()
tableView.contentInset = UIEdgeInsetsMake(-64, 0, 0, 0);
tableView.separatorStyle = .none
}
open override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
moveCellsBackIfNeed(duration) {
self.tableView.reloadData()
open override func viewDidLoad() {
super.viewDidLoad()
tableView.separatorStyle = .none
if #available(iOS 11.0, *) {
tableView.contentInsetAdjustmentBehavior = .never
} else {
tableView.contentInset = UIEdgeInsets.init(top: -64, left: 0, bottom: 0, right: 0)
}
}
open override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
moveCellsBackIfNeed(duration) {
self.tableView.reloadData()
}
closeCurrentCellIfNeed(duration)
moveDownCurrentLabelIfNeed()
}
closeCurrentCellIfNeed(duration)
moveDownCurrentLabelIfNeed()
}
}
// MARK: create
extension PTTableViewController {
fileprivate func createTitleLable(_ cell: ParallaxCell) -> MovingLabel {
let yPosition = cell.frame.origin.y + cell.frame.size.height / 2.0 - 22 - tableView.contentOffset.y
let label = MovingLabel(frame: CGRect(x: 0, y: yPosition, width: UIScreen.main.bounds.size.width, height: 44))
label.textAlignment = .center
label.backgroundColor = .clear
if let font = cell.parallaxTitle?.font,
let text = cell.parallaxTitle?.text,
let textColor = cell.parallaxTitle?.textColor {
label.font = font
label.text = text
label.textColor = textColor
fileprivate func createTitleLable(_ cell: ParallaxCell) -> MovingLabel {
let yPosition = cell.frame.origin.y + cell.frame.size.height / 2.0 - 22 - tableView.contentOffset.y
let label = MovingLabel(frame: CGRect(x: 0, y: yPosition, width: UIScreen.main.bounds.size.width, height: 44))
label.textAlignment = .center
label.backgroundColor = .clear
if let font = cell.parallaxTitle?.font,
let text = cell.parallaxTitle?.text,
let textColor = cell.parallaxTitle?.textColor {
label.font = font
label.text = text
label.textColor = textColor
}
navigationController?.view.addSubview(label)
return label
}
navigationController?.view.addSubview(label)
return label
}
fileprivate func createSeparator(_ color: UIColor?, height: CGFloat, cell: UITableViewCell) -> MovingView {
let yPosition = cell.frame.origin.y + cell.frame.size.height - tableView.contentOffset.y
let separator = MovingView(frame: CGRect(x:0.0, y: yPosition, width: tableView.bounds.size.width, height: height))
if let color = color {
separator.backgroundColor = color
fileprivate func createSeparator(_ color: UIColor?, height: CGFloat, cell: UITableViewCell) -> MovingView {
let yPosition = cell.frame.origin.y + cell.frame.size.height - tableView.contentOffset.y
let separator = MovingView(frame: CGRect(x: 0.0, y: yPosition, width: tableView.bounds.size.width, height: height))
if let color = color {
separator.backgroundColor = color
}
separator.translatesAutoresizingMaskIntoConstraints = false
navigationController?.view.addSubview(separator)
return separator
}
separator.translatesAutoresizingMaskIntoConstraints = false
navigationController?.view.addSubview(separator)
return separator
}
}
// MARK: tableView dataSource
extension PTTableViewController {
final public override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
guard let currentCell = tableView.cellForRow(at: indexPath) as? ParallaxCell else {
return indexPath
public final override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
guard let currentCell = tableView.cellForRow(at: indexPath) as? ParallaxCell else {
return indexPath
}
self.currentCell = currentCell
return indexPath
}
self.currentCell = currentCell
return indexPath
}
}
// MARK: helpers
extension PTTableViewController {
fileprivate func parallaxOffsetDidChange(_ offset: CGFloat) {
let _ = tableView.visibleCells
.filter{$0 != currentCell }
.forEach { if case let cell as ParallaxCell = $0 { cell.parallaxOffset(tableView) } }
}
fileprivate func moveCellsBackIfNeed(_ duration: Double, completion: @escaping () -> Void) {
guard let currentCell = self.currentCell,
let currentIndex = tableView.indexPath(for: currentCell) else {
return
fileprivate func parallaxOffsetDidChange(_: CGFloat) {
_ = tableView.visibleCells
.filter { $0 != currentCell }
.forEach { if case let cell as ParallaxCell = $0 { cell.parallaxOffset(tableView) } }
}
for case let cell as ParallaxCell in tableView.visibleCells where cell != currentCell {
if cell.isMovedHidden == false {continue}
if let index = tableView.indexPath(for: cell) {
let direction = (index as NSIndexPath).row < (currentIndex as NSIndexPath).row ? ParallaxCell.Direction .up : ParallaxCell.Direction.down
cell.animationMoveCell(direction, duration: duration, tableView: tableView, selectedIndexPaht: currentIndex, close: true)
cell.isMovedHidden = false
}
fileprivate func moveCellsBackIfNeed(_ duration: Double, completion: @escaping () -> Void) {
guard let currentCell = self.currentCell,
let currentIndex = tableView.indexPath(for: currentCell) else {
return
}
for case let cell as ParallaxCell in tableView.visibleCells where cell != currentCell {
if cell.isMovedHidden == false { continue }
if let index = tableView.indexPath(for: cell) {
let direction = (index as NSIndexPath).row < (currentIndex as NSIndexPath).row ? ParallaxCell.Direction.up : ParallaxCell.Direction.down
cell.animationMoveCell(direction, duration: duration, tableView: tableView, selectedIndexPaht: currentIndex, close: true)
cell.isMovedHidden = false
}
}
delay(duration, closure: completion)
}
delay(duration, closure: completion)
}
fileprivate func closeCurrentCellIfNeed(_ duration: Double) {
guard let currentCell = self.currentCell else {
return
fileprivate func closeCurrentCellIfNeed(_ duration: Double) {
guard let currentCell = self.currentCell else {
return
}
currentCell.closeCell(duration, tableView: tableView) { () -> Void in
self.currentCell = nil
}
}
currentCell.closeCell(duration, tableView: tableView) { () -> Void in
self.currentCell = nil
fileprivate func moveDownCurrentLabelIfNeed() {
guard let currentTextLabel = self.currentTextLabel else {
return
}
currentTextLabel.move(duration, direction: .down) { _ in
currentTextLabel.removeFromSuperview()
self.currentTextLabel = nil
}
}
}
fileprivate func moveDownCurrentLabelIfNeed() {
guard let currentTextLabel = self.currentTextLabel else {
return
// animtaions
fileprivate func moveCells(_ tableView: UITableView, currentCell: ParallaxCell, duration: Double) {
guard let currentIndex = tableView.indexPath(for: currentCell) else {
return
}
for case let cell as ParallaxCell in tableView.visibleCells where cell != currentCell {
cell.isMovedHidden = true
let row = (tableView.indexPath(for: cell) as NSIndexPath?)?.row
let direction = row < (currentIndex as NSIndexPath).row ? ParallaxCell.Direction.down : ParallaxCell.Direction.up
cell.animationMoveCell(direction, duration: duration, tableView: tableView, selectedIndexPaht: currentIndex, close: false)
}
}
currentTextLabel.move(duration, direction: .down) { (finished) in
currentTextLabel.removeFromSuperview()
self.currentTextLabel = nil
}
}
// animtaions
fileprivate func moveCells(_ tableView: UITableView, currentCell: ParallaxCell, duration: Double) {
guard let currentIndex = tableView.indexPath(for: currentCell) else {
return
}
for case let cell as ParallaxCell in tableView.visibleCells where cell != currentCell {
cell.isMovedHidden = true
let row = (tableView.indexPath(for: cell) as NSIndexPath?)?.row
let direction = row < (currentIndex as NSIndexPath).row ? ParallaxCell.Direction .down : ParallaxCell.Direction.up
cell.animationMoveCell(direction, duration: duration, tableView: tableView, selectedIndexPaht: currentIndex, close: false)
}
}
}
// MARK: ScroolViewDelegate
extension PTTableViewController {
override open func scrollViewDidScroll(_ scrollView: UIScrollView) {
parallaxOffsetDidChange(scrollView.contentOffset.y)
}
open override func scrollViewDidScroll(_ scrollView: UIScrollView) {
parallaxOffsetDidChange(scrollView.contentOffset.y)
}
}
@@ -1,61 +0,0 @@
//
// LayerAnimationHalper.swift
// PreviewTransitionDemo
//
// Created by Alex K. on 03/05/16.
// Copyright © 2016 Alex K. All rights reserved.
//
import UIKit
extension UIView {
private func createAnimationFromKey(key: String, duration: Double, from: CGFloat, to: CGFloat, delay: Double = 0, remove: Bool = true) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: key)
animation.duration = duration
animation.toValue = to
animation.fromValue = from
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
animation.beginTime = CACurrentMediaTime() + delay
if remove == false {
animation.isRemovedOnCompletion = remove
animation.fillMode = kCAFillModeForwards
}
return animation
}
func rotateDuration(duration: Double, from: CGFloat, to: CGFloat, delay: Double = 0, remove: Bool = true) {
let animation = createAnimationFromKey(key: "transform.rotation.z",
duration: duration,
from: from,
to: to,
delay: delay,
remove: remove)
layer.add(animation, forKey: nil)
}
func scaleDuration(duration: Double, from: CGFloat, to: CGFloat, delay: Double = 0, remove: Bool = true) {
let animation = createAnimationFromKey(key: "transform.scale",
duration: duration,
from: from,
to: to,
delay: delay,
remove: remove)
layer.add(animation, forKey: nil)
}
func opacityDuration(duration: Double, from: CGFloat, to: CGFloat, delay: Double = 0, remove: Bool = true) {
let animation = createAnimationFromKey(key: "opacity",
duration: duration,
from: from,
to: to,
delay: delay,
remove: remove)
layer.add(animation, forKey: nil)
}
}
@@ -0,0 +1,58 @@
//
// LayerAnimationHelper.swift
// PreviewTransitionDemo
//
// Created by Alex K. on 03/05/16.
// Copyright © 2016 Alex K. All rights reserved.
//
import UIKit
extension UIView {
private func createAnimationFromKey(key: String, duration: Double, from: CGFloat, to: CGFloat, delay: Double = 0, remove: Bool = true) -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: key)
animation.duration = duration
animation.toValue = to
animation.fromValue = from
animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeOut)
animation.beginTime = CACurrentMediaTime() + delay
if remove == false {
animation.isRemovedOnCompletion = remove
animation.fillMode = CAMediaTimingFillMode.forwards
}
return animation
}
func rotateDuration(duration: Double, from: CGFloat, to: CGFloat, delay: Double = 0, remove: Bool = true) {
let animation = createAnimationFromKey(key: "transform.rotation.z",
duration: duration,
from: from,
to: to,
delay: delay,
remove: remove)
layer.add(animation, forKey: nil)
}
func scaleDuration(duration: Double, from: CGFloat, to: CGFloat, delay: Double = 0, remove: Bool = true) {
let animation = createAnimationFromKey(key: "transform.scale",
duration: duration,
from: from,
to: to,
delay: delay,
remove: remove)
layer.add(animation, forKey: nil)
}
func opacityDuration(duration: Double, from: CGFloat, to: CGFloat, delay: Double = 0, remove: Bool = true) {
let animation = createAnimationFromKey(key: "opacity",
duration: duration,
from: from,
to: to,
delay: delay,
remove: remove)
layer.add(animation, forKey: nil)
}
}
+17 -17
View File
@@ -4,24 +4,24 @@ import Foundation
import UIKit
extension UIImage {
enum Asset: String {
case _1 = "1"
case _2 = "2"
case _3 = "3"
case _4 = "4"
case _5 = "5"
case Back = "back"
case HertIcon = "HertIcon"
case PlusIcon = "PlusIcon"
case ShareIcon = "ShareIcon"
case TransparentPixel = "TransparentPixel"
enum Asset: String {
case _1 = "1"
case _2 = "2"
case _3 = "3"
case _4 = "4"
case _5 = "5"
case Back = "back"
case HertIcon
case PlusIcon
case ShareIcon
case TransparentPixel
var image: UIImage {
return UIImage(asset: self)
var image: UIImage {
return UIImage(asset: self)
}
}
}
convenience init!(asset: Asset) {
self.init(named: asset.rawValue)
}
convenience init!(asset: Asset) {
self.init(named: asset.rawValue)
}
}
@@ -11,36 +11,32 @@ import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var window: UIWindow?
func application(application _: UIApplication, didFinishLaunchingWithOptions _: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
return true
}
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
return true
}
func applicationWillResignActive(application _: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
func applicationWillResignActive(application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
func applicationDidEnterBackground(application _: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationDidEnterBackground(application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(application: UIApplication) {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
func applicationWillEnterForeground(application _: UIApplication) {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(application _: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(application _: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}
@@ -10,31 +10,28 @@ import UIKit
class ViewController: UIViewController {
@IBOutlet weak var lableText: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let animation = CABasicAnimation(keyPath: "fontSize")
animation.toValue = 10
animation.duration = 3
let textLayer = CATextLayer()
textLayer.font = UIFont.systemFontOfSize(50)
textLayer.fontSize = 50
textLayer.string = "text"
textLayer.foregroundColor = UIColor.redColor().CGColor
textLayer.backgroundColor = UIColor.blackColor().CGColor
textLayer.frame = CGRect(x: 100, y: 100, width: 100, height: 100)
view.layer.addSublayer(textLayer)
lableText.layer.addAnimation(animation, forKey: nil)
}
@IBOutlet var lableText: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let animation = CABasicAnimation(keyPath: "fontSize")
animation.toValue = 10
animation.duration = 3
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
let textLayer = CATextLayer()
textLayer.font = UIFont.systemFontOfSize(50)
textLayer.fontSize = 50
textLayer.string = "text"
textLayer.foregroundColor = UIColor.redColor().CGColor
textLayer.backgroundColor = UIColor.blackColor().CGColor
textLayer.frame = CGRect(x: 100, y: 100, width: 100, height: 100)
view.layer.addSublayer(textLayer)
lableText.layer.addAnimation(animation, forKey: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
@@ -8,30 +8,19 @@
/* Begin PBXBuildFile section */
8416D9EA1CB28E2600BB599D /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8416D9E91CB28E2600BB599D /* Extensions.swift */; };
8416D9EB1CB28E2600BB599D /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8416D9E91CB28E2600BB599D /* Extensions.swift */; };
84204DFD1CB2869E001FC263 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84204DFC1CB2869E001FC263 /* AppDelegate.swift */; };
84204E021CB2869E001FC263 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 84204E001CB2869E001FC263 /* Main.storyboard */; };
84204E041CB2869E001FC263 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 84204E031CB2869E001FC263 /* Assets.xcassets */; };
84204E071CB2869E001FC263 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 84204E051CB2869E001FC263 /* LaunchScreen.storyboard */; };
84204E121CB2869E001FC263 /* PreviewTransitionDemoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84204E111CB2869E001FC263 /* PreviewTransitionDemoTests.swift */; };
84204E1F1CB289B3001FC263 /* PTDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84204E1E1CB289B3001FC263 /* PTDetailViewController.swift */; };
84204E281CB289DC001FC263 /* ParallaxCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84204E221CB289DC001FC263 /* ParallaxCell.swift */; };
84204E291CB289DC001FC263 /* TimeExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84204E241CB289DC001FC263 /* TimeExtensions.swift */; };
84204E2A1CB289DC001FC263 /* MovingViews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84204E261CB289DC001FC263 /* MovingViews.swift */; };
84204E2B1CB289DC001FC263 /* PTTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84204E271CB289DC001FC263 /* PTTableViewController.swift */; };
84204E2F1CB28B5B001FC263 /* DemoDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84204E2D1CB28B5B001FC263 /* DemoDetailViewController.swift */; };
84204E301CB28B5B001FC263 /* DemoDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84204E2D1CB28B5B001FC263 /* DemoDetailViewController.swift */; };
84204E311CB28B5B001FC263 /* DemoTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84204E2E1CB28B5B001FC263 /* DemoTableViewController.swift */; };
84204E321CB28B5B001FC263 /* DemoTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84204E2E1CB28B5B001FC263 /* DemoTableViewController.swift */; };
842D7E9B1CB395C800DE59DE /* ParallaxCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84204E221CB289DC001FC263 /* ParallaxCell.swift */; };
842D7E9C1CB395D900DE59DE /* PTTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84204E271CB289DC001FC263 /* PTTableViewController.swift */; };
842D7E9D1CB395FC00DE59DE /* TimeExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84204E241CB289DC001FC263 /* TimeExtensions.swift */; };
842D7E9E1CB3960200DE59DE /* MovingViews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84204E261CB289DC001FC263 /* MovingViews.swift */; };
842D7E9F1CB3960A00DE59DE /* PTDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84204E1E1CB289B3001FC263 /* PTDetailViewController.swift */; };
848526521CD39CFB0052BEAD /* Images.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848526511CD39CFB0052BEAD /* Images.swift */; };
848526531CD39CFB0052BEAD /* Images.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848526511CD39CFB0052BEAD /* Images.swift */; };
848BD7E51CCF54620046DC13 /* ConstraintsHalper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848BD7E41CCF54620046DC13 /* ConstraintsHalper.swift */; };
848BD7E61CCF54620046DC13 /* ConstraintsHalper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848BD7E41CCF54620046DC13 /* ConstraintsHalper.swift */; };
8499D8BA1D006020004B5B37 /* PreivewTransition.h in Headers */ = {isa = PBXBuildFile; fileRef = 8499D8B91D006020004B5B37 /* PreivewTransition.h */; settings = {ATTRIBUTES = (Public, ); }; };
8499D8BE1D006020004B5B37 /* PreviewTransition.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8499D8B71D006020004B5B37 /* PreviewTransition.framework */; };
8499D8BF1D006020004B5B37 /* PreviewTransition.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 8499D8B71D006020004B5B37 /* PreviewTransition.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
@@ -41,20 +30,11 @@
8499D8C71D006082004B5B37 /* MovingViews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84204E261CB289DC001FC263 /* MovingViews.swift */; };
8499D8C81D006085004B5B37 /* PTTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84204E271CB289DC001FC263 /* PTTableViewController.swift */; };
8499D8C91D00608B004B5B37 /* PTDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84204E1E1CB289B3001FC263 /* PTDetailViewController.swift */; };
84A36E0E1CD88EEA00AEC2F2 /* LayerAnimationHalper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A36E0D1CD88EEA00AEC2F2 /* LayerAnimationHalper.swift */; };
84A36E0F1CD88EEA00AEC2F2 /* LayerAnimationHalper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A36E0D1CD88EEA00AEC2F2 /* LayerAnimationHalper.swift */; };
84A36E0E1CD88EEA00AEC2F2 /* LayerAnimationHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A36E0D1CD88EEA00AEC2F2 /* LayerAnimationHelper.swift */; };
84A36E141CD8C70F00AEC2F2 /* ScreenShot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A36E131CD8C70F00AEC2F2 /* ScreenShot.swift */; };
84A36E151CD8C70F00AEC2F2 /* ScreenShot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A36E131CD8C70F00AEC2F2 /* ScreenShot.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
84204E0E1CB2869E001FC263 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 84204DF11CB2869E001FC263 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 84204DF81CB2869E001FC263;
remoteInfo = PreviewTransitionDemo;
};
8499D8BC1D006020004B5B37 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 84204DF11CB2869E001FC263 /* Project object */;
@@ -86,9 +66,6 @@
84204E031CB2869E001FC263 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
84204E061CB2869E001FC263 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
84204E081CB2869E001FC263 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
84204E0D1CB2869E001FC263 /* PreviewTransitionDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PreviewTransitionDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
84204E111CB2869E001FC263 /* PreviewTransitionDemoTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewTransitionDemoTests.swift; sourceTree = "<group>"; };
84204E131CB2869E001FC263 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
84204E1E1CB289B3001FC263 /* PTDetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PTDetailViewController.swift; sourceTree = "<group>"; };
84204E221CB289DC001FC263 /* ParallaxCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParallaxCell.swift; sourceTree = "<group>"; };
84204E241CB289DC001FC263 /* TimeExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimeExtensions.swift; sourceTree = "<group>"; };
@@ -101,7 +78,7 @@
8499D8B71D006020004B5B37 /* PreviewTransition.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = PreviewTransition.framework; sourceTree = BUILT_PRODUCTS_DIR; };
8499D8B91D006020004B5B37 /* PreivewTransition.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PreivewTransition.h; sourceTree = "<group>"; };
8499D8BB1D006020004B5B37 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
84A36E0D1CD88EEA00AEC2F2 /* LayerAnimationHalper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LayerAnimationHalper.swift; sourceTree = "<group>"; };
84A36E0D1CD88EEA00AEC2F2 /* LayerAnimationHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LayerAnimationHelper.swift; sourceTree = "<group>"; };
84A36E131CD8C70F00AEC2F2 /* ScreenShot.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScreenShot.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
@@ -114,13 +91,6 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
84204E0A1CB2869E001FC263 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
8499D8B31D006020004B5B37 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@@ -142,11 +112,10 @@
84204DF01CB2869E001FC263 = {
isa = PBXGroup;
children = (
84A36E111CD8C31C00AEC2F2 /* Halpers */,
84A36E111CD8C31C00AEC2F2 /* Helpers */,
848526501CD39CDD0052BEAD /* Constants */,
84204E1C1CB286DD001FC263 /* PreviewTransition */,
84204DFB1CB2869E001FC263 /* PreviewTransitionDemo */,
84204E101CB2869E001FC263 /* PreviewTransitionDemoTests */,
8499D8B81D006020004B5B37 /* PreivewTransition */,
84204DFA1CB2869E001FC263 /* Products */,
);
@@ -156,7 +125,6 @@
isa = PBXGroup;
children = (
84204DF91CB2869E001FC263 /* PreviewTransitionDemo.app */,
84204E0D1CB2869E001FC263 /* PreviewTransitionDemoTests.xctest */,
8499D8B71D006020004B5B37 /* PreviewTransition.framework */,
);
name = Products;
@@ -176,15 +144,6 @@
path = PreviewTransitionDemo;
sourceTree = "<group>";
};
84204E101CB2869E001FC263 /* PreviewTransitionDemoTests */ = {
isa = PBXGroup;
children = (
84204E111CB2869E001FC263 /* PreviewTransitionDemoTests.swift */,
84204E131CB2869E001FC263 /* Info.plist */,
);
path = PreviewTransitionDemoTests;
sourceTree = "<group>";
};
84204E1C1CB286DD001FC263 /* PreviewTransition */ = {
isa = PBXGroup;
children = (
@@ -274,21 +233,21 @@
path = PreivewTransition;
sourceTree = "<group>";
};
84A36E0C1CD88EB200AEC2F2 /* AnimationHalpers */ = {
84A36E0C1CD88EB200AEC2F2 /* AnimationHelpers */ = {
isa = PBXGroup;
children = (
84A36E0D1CD88EEA00AEC2F2 /* LayerAnimationHalper.swift */,
84A36E0D1CD88EEA00AEC2F2 /* LayerAnimationHelper.swift */,
);
path = AnimationHalpers;
path = AnimationHelpers;
sourceTree = "<group>";
};
84A36E111CD8C31C00AEC2F2 /* Halpers */ = {
84A36E111CD8C31C00AEC2F2 /* Helpers */ = {
isa = PBXGroup;
children = (
84A36E121CD8C32600AEC2F2 /* ScreenShot */,
84A36E0C1CD88EB200AEC2F2 /* AnimationHalpers */,
84A36E0C1CD88EB200AEC2F2 /* AnimationHelpers */,
);
name = Halpers;
name = Helpers;
sourceTree = "<group>";
};
84A36E121CD8C32600AEC2F2 /* ScreenShot */ = {
@@ -321,7 +280,6 @@
84204DF51CB2869E001FC263 /* Sources */,
84204DF61CB2869E001FC263 /* Frameworks */,
84204DF71CB2869E001FC263 /* Resources */,
8485264F1CD39C880052BEAD /* image enum gen */,
8499D8C31D006020004B5B37 /* Embed Frameworks */,
);
buildRules = (
@@ -334,24 +292,6 @@
productReference = 84204DF91CB2869E001FC263 /* PreviewTransitionDemo.app */;
productType = "com.apple.product-type.application";
};
84204E0C1CB2869E001FC263 /* PreviewTransitionDemoTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 84204E191CB2869E001FC263 /* Build configuration list for PBXNativeTarget "PreviewTransitionDemoTests" */;
buildPhases = (
84204E091CB2869E001FC263 /* Sources */,
84204E0A1CB2869E001FC263 /* Frameworks */,
84204E0B1CB2869E001FC263 /* Resources */,
);
buildRules = (
);
dependencies = (
84204E0F1CB2869E001FC263 /* PBXTargetDependency */,
);
name = PreviewTransitionDemoTests;
productName = PreviewTransitionDemoTests;
productReference = 84204E0D1CB2869E001FC263 /* PreviewTransitionDemoTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
8499D8B61D006020004B5B37 /* PreviewTransition */ = {
isa = PBXNativeTarget;
buildConfigurationList = 8499D8C21D006020004B5B37 /* Build configuration list for PBXNativeTarget "PreviewTransition" */;
@@ -377,28 +317,24 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0730;
LastUpgradeCheck = 0900;
LastUpgradeCheck = 1020;
ORGANIZATIONNAME = "Alex K.";
TargetAttributes = {
84204DF81CB2869E001FC263 = {
CreatedOnToolsVersion = 7.3;
DevelopmentTeam = 34MUF9YXTA;
LastSwiftMigration = 0900;
};
84204E0C1CB2869E001FC263 = {
CreatedOnToolsVersion = 7.3;
TestTargetID = 84204DF81CB2869E001FC263;
LastSwiftMigration = 1020;
};
8499D8B61D006020004B5B37 = {
CreatedOnToolsVersion = 7.3.1;
DevelopmentTeam = LEAZS7L33U;
LastSwiftMigration = 0900;
LastSwiftMigration = 1020;
};
};
};
buildConfigurationList = 84204DF41CB2869E001FC263 /* Build configuration list for PBXProject "PreviewTransitionDemo" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
@@ -410,7 +346,6 @@
projectRoot = "";
targets = (
84204DF81CB2869E001FC263 /* PreviewTransitionDemo */,
84204E0C1CB2869E001FC263 /* PreviewTransitionDemoTests */,
8499D8B61D006020004B5B37 /* PreviewTransition */,
);
};
@@ -427,13 +362,6 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
84204E0B1CB2869E001FC263 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
8499D8B51D006020004B5B37 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
@@ -443,23 +371,6 @@
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
8485264F1CD39C880052BEAD /* image enum gen */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "image enum gen";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "if which swiftgen >/dev/null; then\nswiftgen images \"$PROJECT_DIR/PreviewTransitionDemo/Assets.xcassets\" --output \"$PROJECT_DIR/Constants/Images.swift\"\nelse\necho \"warning: SwiftGen not installed, download it from https://github.com/AliSoftware/SwiftGen\"\nfi";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
84204DF51CB2869E001FC263 /* Sources */ = {
isa = PBXSourcesBuildPhase;
@@ -476,31 +387,11 @@
848BD7E51CCF54620046DC13 /* ConstraintsHalper.swift in Sources */,
84204E2B1CB289DC001FC263 /* PTTableViewController.swift in Sources */,
84204DFD1CB2869E001FC263 /* AppDelegate.swift in Sources */,
84A36E0E1CD88EEA00AEC2F2 /* LayerAnimationHalper.swift in Sources */,
84A36E0E1CD88EEA00AEC2F2 /* LayerAnimationHelper.swift in Sources */,
84204E2F1CB28B5B001FC263 /* DemoDetailViewController.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
84204E091CB2869E001FC263 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
842D7E9B1CB395C800DE59DE /* ParallaxCell.swift in Sources */,
84204E301CB28B5B001FC263 /* DemoDetailViewController.swift in Sources */,
842D7E9E1CB3960200DE59DE /* MovingViews.swift in Sources */,
848526531CD39CFB0052BEAD /* Images.swift in Sources */,
84204E121CB2869E001FC263 /* PreviewTransitionDemoTests.swift in Sources */,
842D7E9F1CB3960A00DE59DE /* PTDetailViewController.swift in Sources */,
84A36E151CD8C70F00AEC2F2 /* ScreenShot.swift in Sources */,
84204E321CB28B5B001FC263 /* DemoTableViewController.swift in Sources */,
848BD7E61CCF54620046DC13 /* ConstraintsHalper.swift in Sources */,
8416D9EB1CB28E2600BB599D /* Extensions.swift in Sources */,
842D7E9C1CB395D900DE59DE /* PTTableViewController.swift in Sources */,
84A36E0F1CD88EEA00AEC2F2 /* LayerAnimationHalper.swift in Sources */,
842D7E9D1CB395FC00DE59DE /* TimeExtensions.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
8499D8B21D006020004B5B37 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@@ -517,11 +408,6 @@
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
84204E0F1CB2869E001FC263 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 84204DF81CB2869E001FC263 /* PreviewTransitionDemo */;
targetProxy = 84204E0E1CB2869E001FC263 /* PBXContainerItemProxy */;
};
8499D8BD1D006020004B5B37 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 8499D8B61D006020004B5B37 /* PreviewTransition */;
@@ -553,6 +439,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
@@ -562,12 +449,14 @@
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
@@ -594,7 +483,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -606,6 +495,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
@@ -615,12 +505,14 @@
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
@@ -641,7 +533,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
@@ -663,8 +555,7 @@
PRODUCT_BUNDLE_IDENTIFIER = com.ramotion.dev;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "";
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 4.0;
SWIFT_VERSION = 5.0;
};
name = Debug;
};
@@ -682,34 +573,7 @@
PRODUCT_BUNDLE_IDENTIFIER = com.ramotion.dev;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "";
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 4.0;
};
name = Release;
};
84204E1A1CB2869E001FC263 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
INFOPLIST_FILE = PreviewTransitionDemoTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.ramotion.PreviewTransitionDemoTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/PreviewTransitionDemo.app/PreviewTransitionDemo";
};
name = Debug;
};
84204E1B1CB2869E001FC263 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
INFOPLIST_FILE = PreviewTransitionDemoTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.ramotion.PreviewTransitionDemoTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/PreviewTransitionDemo.app/PreviewTransitionDemo";
SWIFT_VERSION = 5.0;
};
name = Release;
};
@@ -730,8 +594,7 @@
PRODUCT_BUNDLE_IDENTIFIER = com.ramotion.PreivewTransition;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = NO;
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 4.0;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
@@ -755,8 +618,7 @@
PRODUCT_BUNDLE_IDENTIFIER = com.ramotion.PreivewTransition;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = NO;
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 4.0;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
@@ -784,15 +646,6 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
84204E191CB2869E001FC263 /* Build configuration list for PBXNativeTarget "PreviewTransitionDemoTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
84204E1A1CB2869E001FC263 /* Debug */,
84204E1B1CB2869E001FC263 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
8499D8C21D006020004B5B37 /* Build configuration list for PBXNativeTarget "PreviewTransition" */ = {
isa = XCConfigurationList;
buildConfigurations = (
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0900"
LastUpgradeVersion = "1020"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -26,7 +26,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
@@ -37,7 +36,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
@@ -11,30 +11,26 @@ import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var window: UIWindow?
func applicationDidFinishLaunching(_ application: UIApplication) {
configureNavigationBar()
}
func applicationDidFinishLaunching(_: UIApplication) {
configureNavigationBar()
}
}
extension AppDelegate {
fileprivate func configureNavigationBar() {
//transparent background
UINavigationBar.appearance().setBackgroundImage(UIImage(), for: .default)
UINavigationBar.appearance().shadowImage = UIImage()
UINavigationBar.appearance().isTranslucent = true
if let font = UIFont(name: "Avenir-medium" , size: 18) {
UINavigationBar.appearance().titleTextAttributes = [
NSAttributedStringKey.foregroundColor : UIColor.white,
NSAttributedStringKey.font : font
]
}
}
}
fileprivate func configureNavigationBar() {
//transparent background
UINavigationBar.appearance().setBackgroundImage(UIImage(), for: .default)
UINavigationBar.appearance().shadowImage = UIImage()
UINavigationBar.appearance().isTranslucent = true
if let font = UIFont(name: "Avenir-medium", size: 18) {
UINavigationBar.appearance().titleTextAttributes = [
NSAttributedString.Key.foregroundColor: UIColor.white,
NSAttributedString.Key.font: font,
]
}
}
}
@@ -1,48 +1,119 @@
{
"images" : [
{
"idiom" : "iphone",
"size" : "20x20",
"idiom" : "iphone",
"filename" : "icon-40.png",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "20x20",
"idiom" : "iphone",
"filename" : "icon-60.png",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"idiom" : "iphone",
"filename" : "icon-58.png",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"idiom" : "iphone",
"filename" : "icon-87.png",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"idiom" : "iphone",
"filename" : "icon-80.png",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"idiom" : "iphone",
"filename" : "icon-120.png",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"idiom" : "iphone",
"filename" : "icon-120.png",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"idiom" : "iphone",
"filename" : "icon-180.png",
"scale" : "3x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "icon-20.png",
"scale" : "1x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "icon-40.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "icon-29.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "icon-58.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "icon-40.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "icon-80.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "icon-76.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "icon-152.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "icon-167.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Ramotion.png",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"pre-rendered" : true
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 475 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 620 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 792 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

@@ -1,8 +1,13 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10116" systemVersion="15E65" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" initialViewController="01J-lp-oVM">
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
@@ -14,14 +19,35 @@
<viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright (c) 2018 Ramotion. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fcf-sN-ku0">
<rect key="frame" x="16" y="630" width="343" height="17"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Preview Transition" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bCd-3b-lHA">
<rect key="frame" x="111.5" y="323" width="152" height="21"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="fcf-sN-ku0" firstAttribute="leading" secondItem="Ze5-6b-2t3" secondAttribute="leadingMargin" id="811-hI-Egq"/>
<constraint firstItem="bCd-3b-lHA" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="T4x-O3-JqD"/>
<constraint firstItem="bCd-3b-lHA" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="VFr-tp-sPw"/>
<constraint firstItem="fcf-sN-ku0" firstAttribute="trailing" secondItem="Ze5-6b-2t3" secondAttribute="trailingMargin" id="dS9-pv-ebe"/>
<constraint firstItem="xb3-aO-Qok" firstAttribute="top" secondItem="fcf-sN-ku0" secondAttribute="bottom" constant="20" id="kbD-dX-t3N"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
<point key="canvasLocation" x="52" y="374.66266866566718"/>
</scene>
</scenes>
</document>
@@ -1,24 +1,33 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11201" systemVersion="15G1004" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="rNz-sP-Qod">
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="rNz-sP-Qod">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11161"/>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<customFonts key="customFonts">
<array key="Avenir.ttc">
<string>Avenir-Medium</string>
</array>
</customFonts>
<scenes>
<!--Demo Table View Controller-->
<scene sceneID="TS0-JK-FG8">
<objects>
<tableViewController storyboardIdentifier="DemoTableViewController" id="R4r-KK-4wR" customClass="DemoTableViewController" customModule="PreviewTransitionDemo" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="240" sectionHeaderHeight="28" sectionFooterHeight="28" id="bOE-4i-fSR">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="240" sectionHeaderHeight="28" sectionFooterHeight="28" id="bOE-4i-fSR">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="ParallaxCell" id="AII-q7-Txi" customClass="ParallaxCell" customModule="PreviewTransitionDemo" customModuleProvider="target">
<rect key="frame" x="0.0" y="92" width="375" height="240"/>
<rect key="frame" x="0.0" y="28" width="375" height="240"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="AII-q7-Txi" id="dOL-VB-4JN">
<frame key="frameInset" width="375" height="239"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="239.5"/>
<autoresizingMask key="autoresizingMask"/>
</tableViewCellContentView>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
@@ -48,63 +57,80 @@
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<view key="view" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="bep-Nt-aTe" userLabel="BottomView">
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="e87-Lw-D6d" userLabel="ControlsViewContainer">
<rect key="frame" x="0.0" y="592" width="375" height="75"/>
<subviews>
<imageView userInteractionEnabled="NO" alpha="0.65000000000000002" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="PlusIcon" translatesAutoresizingMaskIntoConstraints="NO" id="cNu-DQ-KVS">
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="bep-Nt-aTe" userLabel="ControlsView">
<rect key="frame" x="0.0" y="0.0" width="375" height="75"/>
<subviews>
<imageView userInteractionEnabled="NO" alpha="0.65000000000000002" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="PlusIcon" translatesAutoresizingMaskIntoConstraints="NO" id="cNu-DQ-KVS">
<rect key="frame" x="26" y="23.5" width="28" height="28"/>
<constraints>
<constraint firstAttribute="width" constant="28" id="Oez-4a-Ajf"/>
<constraint firstAttribute="height" constant="28" id="dVU-d2-hQD"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" alpha="0.65000000000000002" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="UPLOAD" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="of2-Mb-6dK">
<rect key="frame" x="72" y="26.5" width="65.5" height="22"/>
<fontDescription key="fontDescription" name="Avenir-Medium" family="Avenir" pointSize="16"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<imageView userInteractionEnabled="NO" alpha="0.65000000000000002" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="HertIcon" translatesAutoresizingMaskIntoConstraints="NO" id="qf5-7H-m8I">
<rect key="frame" x="329" y="27.5" width="20" height="20"/>
<constraints>
<constraint firstAttribute="width" constant="20" id="7vC-Kj-Xhh"/>
<constraint firstAttribute="height" constant="20" id="y9j-Rr-ADZ"/>
</constraints>
</imageView>
<imageView userInteractionEnabled="NO" alpha="0.65000000000000002" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="ShareIcon" translatesAutoresizingMaskIntoConstraints="NO" id="fYq-Bm-C3g">
<rect key="frame" x="278" y="27.5" width="20" height="20"/>
<constraints>
<constraint firstAttribute="width" constant="20" id="AdG-0M-DE8"/>
<constraint firstAttribute="height" constant="20" id="npa-OF-Phw"/>
</constraints>
</imageView>
</subviews>
<color key="backgroundColor" red="0.2418571412563324" green="0.17698898911476135" blue="0.1230514720082283" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="width" constant="28" id="Oez-4a-Ajf"/>
<constraint firstAttribute="height" constant="28" id="dVU-d2-hQD"/>
<constraint firstItem="qf5-7H-m8I" firstAttribute="centerY" secondItem="bep-Nt-aTe" secondAttribute="centerY" id="7Sl-Yf-TPT"/>
<constraint firstItem="qf5-7H-m8I" firstAttribute="leading" secondItem="fYq-Bm-C3g" secondAttribute="trailing" constant="31" id="CbF-3f-1Rz"/>
<constraint firstItem="fYq-Bm-C3g" firstAttribute="centerY" secondItem="bep-Nt-aTe" secondAttribute="centerY" id="Q7R-nz-kDO"/>
<constraint firstItem="cNu-DQ-KVS" firstAttribute="centerY" secondItem="bep-Nt-aTe" secondAttribute="centerY" id="VSr-aL-49x"/>
<constraint firstAttribute="trailing" secondItem="qf5-7H-m8I" secondAttribute="trailing" constant="26" id="dyM-CD-2Xy"/>
<constraint firstItem="of2-Mb-6dK" firstAttribute="centerY" secondItem="bep-Nt-aTe" secondAttribute="centerY" id="ndt-gV-UNC"/>
<constraint firstItem="cNu-DQ-KVS" firstAttribute="leading" secondItem="bep-Nt-aTe" secondAttribute="leading" constant="26" id="sM2-by-tp2"/>
<constraint firstItem="of2-Mb-6dK" firstAttribute="leading" secondItem="cNu-DQ-KVS" secondAttribute="trailing" constant="18" id="u48-EN-PaD"/>
<constraint firstAttribute="height" constant="75" id="y5q-xC-6PW"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" alpha="0.65000000000000002" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="UPLOAD" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="of2-Mb-6dK">
<fontDescription key="fontDescription" name="Avenir-Medium" family="Avenir" pointSize="16"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<imageView userInteractionEnabled="NO" alpha="0.65000000000000002" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="HertIcon" translatesAutoresizingMaskIntoConstraints="NO" id="qf5-7H-m8I">
<constraints>
<constraint firstAttribute="width" constant="29" id="7vC-Kj-Xhh"/>
<constraint firstAttribute="height" constant="29" id="y9j-Rr-ADZ"/>
</constraints>
</imageView>
<imageView userInteractionEnabled="NO" alpha="0.65000000000000002" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="ShareIcon" translatesAutoresizingMaskIntoConstraints="NO" id="fYq-Bm-C3g">
<constraints>
<constraint firstAttribute="width" constant="29" id="AdG-0M-DE8"/>
<constraint firstAttribute="height" constant="29" id="npa-OF-Phw"/>
</constraints>
</imageView>
</view>
</subviews>
<color key="backgroundColor" red="0.2418571412563324" green="0.17698898911476135" blue="0.1230514720082283" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="qf5-7H-m8I" firstAttribute="centerY" secondItem="bep-Nt-aTe" secondAttribute="centerY" id="7Sl-Yf-TPT"/>
<constraint firstItem="qf5-7H-m8I" firstAttribute="leading" secondItem="fYq-Bm-C3g" secondAttribute="trailing" constant="31" id="CbF-3f-1Rz"/>
<constraint firstItem="fYq-Bm-C3g" firstAttribute="centerY" secondItem="bep-Nt-aTe" secondAttribute="centerY" id="Q7R-nz-kDO"/>
<constraint firstItem="cNu-DQ-KVS" firstAttribute="centerY" secondItem="bep-Nt-aTe" secondAttribute="centerY" id="VSr-aL-49x"/>
<constraint firstAttribute="trailing" secondItem="qf5-7H-m8I" secondAttribute="trailing" constant="26" id="dyM-CD-2Xy"/>
<constraint firstItem="of2-Mb-6dK" firstAttribute="centerY" secondItem="bep-Nt-aTe" secondAttribute="centerY" id="ndt-gV-UNC"/>
<constraint firstItem="cNu-DQ-KVS" firstAttribute="leading" secondItem="bep-Nt-aTe" secondAttribute="leading" constant="26" id="sM2-by-tp2"/>
<constraint firstItem="of2-Mb-6dK" firstAttribute="leading" secondItem="cNu-DQ-KVS" secondAttribute="trailing" constant="18" id="u48-EN-PaD"/>
<constraint firstAttribute="height" constant="75" id="y5q-xC-6PW"/>
<constraint firstItem="bep-Nt-aTe" firstAttribute="top" secondItem="e87-Lw-D6d" secondAttribute="top" id="AQh-Mt-Zu0"/>
<constraint firstAttribute="trailing" secondItem="bep-Nt-aTe" secondAttribute="trailing" id="R5F-Ml-C1h"/>
<constraint firstItem="bep-Nt-aTe" firstAttribute="leading" secondItem="e87-Lw-D6d" secondAttribute="leading" id="e33-px-zT6"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="bep-Nt-aTe" firstAttribute="leading" secondItem="8bC-Xf-vdC" secondAttribute="leading" id="HoE-lK-c1w"/>
<constraint firstItem="wfy-db-euE" firstAttribute="top" secondItem="bep-Nt-aTe" secondAttribute="bottom" id="Ye7-fc-GvE"/>
<constraint firstAttribute="trailing" secondItem="bep-Nt-aTe" secondAttribute="trailing" id="fVz-GY-Jz2"/>
<constraint firstItem="e87-Lw-D6d" firstAttribute="leading" secondItem="8bC-Xf-vdC" secondAttribute="leading" id="WtK-eJ-Evt"/>
<constraint firstAttribute="trailing" secondItem="e87-Lw-D6d" secondAttribute="trailing" id="Xfw-qN-wKE"/>
<constraint firstAttribute="bottom" secondItem="e87-Lw-D6d" secondAttribute="bottom" id="Z1u-Zc-6Gx"/>
<constraint firstItem="wfy-db-euE" firstAttribute="top" secondItem="bep-Nt-aTe" secondAttribute="bottom" id="qoN-F2-pl4"/>
</constraints>
</view>
<connections>
<outlet property="controlBottomConstrant" destination="Ye7-fc-GvE" id="Z4z-3v-JPd"/>
<outlet property="controlHeightConstraint" destination="y5q-xC-6PW" id="bj2-EN-9sN"/>
<outlet property="controlBottomConstrant" destination="qoN-F2-pl4" id="7vP-GT-O7y"/>
<outlet property="controlTextLabel" destination="of2-Mb-6dK" id="8VW-Qx-njJ"/>
<outlet property="controlTextLableLending" destination="u48-EN-PaD" id="THf-Gf-6Oe"/>
<outlet property="controlView" destination="bep-Nt-aTe" id="lB6-d4-1rx"/>
<outlet property="controlsViewContainer" destination="e87-Lw-D6d" id="vqd-db-r0q"/>
<outlet property="hertIconView" destination="qf5-7H-m8I" id="LUd-B6-aY7"/>
<outlet property="plusImageView" destination="cNu-DQ-KVS" id="xQY-UZ-Bve"/>
<outlet property="shareImageView" destination="fYq-Bm-C3g" id="mW0-7l-wPb"/>
@@ -112,7 +138,7 @@
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1609" y="484"/>
<point key="canvasLocation" x="1608.8" y="483.50824587706148"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="cXS-jQ-bIr">
@@ -121,7 +147,7 @@
<toolbarItems/>
<simulatedStatusBarMetrics key="simulatedStatusBarMetrics" statusBarStyle="lightContent"/>
<navigationBar key="navigationBar" contentMode="scaleToFill" id="crh-l4-DmE">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<rect key="frame" x="0.0" y="20" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<textAttributes key="titleTextAttributes">
<color key="textColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
@@ -26,65 +26,64 @@ import UIKit
// MARK: tableview
extension UITableView {
func getReusableCellWithIdentifier<T: UITableViewCell>(indexPath: IndexPath) -> T {
guard let cell = self.dequeueReusableCell(withIdentifier: T.cellIdentifier, for: indexPath as IndexPath) as? T else {
fatalError("Couldn't instantiate view controller with identifier \(T.cellIdentifier) ")
func getReusableCellWithIdentifier<T: UITableViewCell>(indexPath: IndexPath) -> T {
guard let cell = self.dequeueReusableCell(withIdentifier: T.cellIdentifier, for: indexPath as IndexPath) as? T else {
fatalError("Couldn't instantiate view controller with identifier \(T.cellIdentifier) ")
}
return cell
}
return cell
}
}
// MARK: UITableViewCell
protocol TableViewCellIdentifiable {
static var cellIdentifier: String { get }
static var cellIdentifier: String { get }
}
extension TableViewCellIdentifiable where Self: UITableViewCell {
static var cellIdentifier: String {
return String(describing: self)
}
static var cellIdentifier: String {
return String(describing: self)
}
}
extension UITableViewCell : TableViewCellIdentifiable { }
extension UITableViewCell: TableViewCellIdentifiable {}
// MARK: storyboard
extension UIStoryboard {
enum Storyboard : String {
case Main
}
convenience init(storyboard: Storyboard, bundle: Bundle? = nil) {
self.init(name: storyboard.rawValue, bundle: bundle)
}
class func storyboard(storyboard: Storyboard, bundle: Bundle? = nil) -> UIStoryboard {
return UIStoryboard(name: storyboard.rawValue, bundle: bundle)
}
func instantiateViewController<T: UIViewController>() -> T {
guard let viewController = self.instantiateViewController(withIdentifier: T.storyboardIdentifier) as? T else {
fatalError("Couldn't instantiate view controller with identifier \(T.storyboardIdentifier) ")
enum Storyboard: String {
case Main
}
convenience init(storyboard: Storyboard, bundle: Bundle? = nil) {
self.init(name: storyboard.rawValue, bundle: bundle)
}
class func storyboard(storyboard: Storyboard, bundle: Bundle? = nil) -> UIStoryboard {
return UIStoryboard(name: storyboard.rawValue, bundle: bundle)
}
func instantiateViewController<T: UIViewController>() -> T {
guard let viewController = self.instantiateViewController(withIdentifier: T.storyboardIdentifier) as? T else {
fatalError("Couldn't instantiate view controller with identifier \(T.storyboardIdentifier) ")
}
return viewController
}
return viewController
}
}
extension UIViewController : StoryboardIdentifiable { }
extension UIViewController: StoryboardIdentifiable {}
// MARK: identifiable
protocol StoryboardIdentifiable {
static var storyboardIdentifier: String { get }
static var storyboardIdentifier: String { get }
}
extension StoryboardIdentifiable where Self: UIViewController {
static var storyboardIdentifier: String {
return String(describing: self)
}
static var storyboardIdentifier: String {
return String(describing: self)
}
}
@@ -21,157 +21,150 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import UIKit
public class DemoDetailViewController: PTDetailViewController {
@IBOutlet weak var controlHeightConstraint: NSLayoutConstraint!
@IBOutlet weak var controlBottomConstrant: NSLayoutConstraint!
// bottom control icons
@IBOutlet weak var controlView: UIView!
@IBOutlet weak var plusImageView: UIImageView!
@IBOutlet weak var controlTextLabel: UILabel!
@IBOutlet weak var controlTextLableLending: NSLayoutConstraint!
@IBOutlet weak var shareImageView: UIImageView!
@IBOutlet weak var hertIconView: UIImageView!
var backButton: UIButton?
@IBOutlet var controlBottomConstrant: NSLayoutConstraint!
// bottom control icons
@IBOutlet var controlsViewContainer: UIView!
@IBOutlet var controlView: UIView!
@IBOutlet var plusImageView: UIImageView!
@IBOutlet var controlTextLabel: UILabel!
@IBOutlet var controlTextLableLending: NSLayoutConstraint!
@IBOutlet var shareImageView: UIImageView!
@IBOutlet var hertIconView: UIImageView!
var backButton: UIButton?
var bottomSafeArea: CGFloat {
var result: CGFloat = 0
if #available(iOS 11.0, *) {
result = UIApplication.shared.keyWindow?.safeAreaInsets.bottom ?? 0
}
return result
}
}
// MARK: life cicle
extension DemoDetailViewController {
public override func viewDidLoad() {
super.viewDidLoad()
backButton = createBackButton()
let _ = createNavigationBarBackItem(button: backButton)
// animations
showBackButtonDuration(duration: 0.3)
showControlViewDuration(duration: 0.3)
let _ = createBlurView()
}
public override func viewDidLoad() {
super.viewDidLoad()
backButton = createBackButton()
_ = createNavigationBarBackItem(button: backButton)
// animations
showBackButtonDuration(duration: 0.3)
showControlViewDuration(duration: 0.3)
_ = createBlurView()
}
}
// MARK: helpers
extension DemoDetailViewController {
fileprivate func createBackButton() -> UIButton {
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 22, height: 44))
button.setImage(UIImage.Asset.Back.image, for: .normal)
button.addTarget(self, action: #selector(DemoDetailViewController.backButtonHandler) , for: .touchUpInside)
return button
}
fileprivate func createNavigationBarBackItem(button: UIButton?) -> UIBarButtonItem? {
guard let button = button else {
return nil
}
let buttonItem = UIBarButtonItem(customView: button)
navigationItem.leftBarButtonItem = buttonItem
return buttonItem
}
fileprivate func createBlurView() -> UIView {
let imageFrame = CGRect(x: 0, y: view.frame.size.height - controlHeightConstraint.constant, width: view.frame.width, height: controlHeightConstraint.constant)
let image = view.makeScreenShotFromFrame(frame: imageFrame)
let screnShotImageView = UIImageView(image: image)
screnShotImageView.translatesAutoresizingMaskIntoConstraints = false
screnShotImageView.blurViewValue(value: 5)
controlView.insertSubview(screnShotImageView, at: 0)
// added constraints
[NSLayoutAttribute.left, .right, .bottom, .top].forEach { attribute in
(self.controlView, screnShotImageView) >>>- {
$0.attribute = attribute
return
}
}
createMaskView(onView: screnShotImageView)
return screnShotImageView
}
fileprivate func createMaskView(onView: UIView) {
let blueView = UIView(frame: CGRect.zero)
blueView.backgroundColor = .black
blueView.translatesAutoresizingMaskIntoConstraints = false
blueView.alpha = 0.4
onView.addSubview(blueView)
// add constraints
[NSLayoutAttribute.left, .right, .bottom, .top].forEach { attribute in
(onView, blueView) >>>- {
$0.attribute = attribute
return
}
fileprivate func createBackButton() -> UIButton {
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 22, height: 44))
button.setImage(UIImage.Asset.Back.image, for: .normal)
button.addTarget(self, action: #selector(DemoDetailViewController.backButtonHandler), for: .touchUpInside)
return button
}
fileprivate func createNavigationBarBackItem(button: UIButton?) -> UIBarButtonItem? {
guard let button = button else {
return nil
}
let buttonItem = UIBarButtonItem(customView: button)
navigationItem.leftBarButtonItem = buttonItem
return buttonItem
}
fileprivate func createBlurView() -> UIView {
let height = controlView.bounds.height + bottomSafeArea
let imageFrame = CGRect(x: 0, y: view.frame.size.height - height, width: view.frame.width, height: height)
let image = view.makeScreenShotFromFrame(frame: imageFrame)
let screnShotImageView = UIImageView(image: image)
screnShotImageView.blurViewValue(value: 5)
screnShotImageView.frame = controlsViewContainer.bounds
screnShotImageView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
controlsViewContainer.insertSubview(screnShotImageView, at: 0)
addOverlay(toView: screnShotImageView)
return screnShotImageView
}
fileprivate func addOverlay(toView view: UIView) {
let overlayView = UIView(frame: view.bounds)
overlayView.backgroundColor = .black
overlayView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
overlayView.alpha = 0.4
view.addSubview(overlayView)
}
}
}
// MARK: animations
extension DemoDetailViewController {
fileprivate func showBackButtonDuration(duration: Double) {
backButton?.rotateDuration(duration: duration, from: -CGFloat.pi / 4, to: 0)
backButton?.scaleDuration(duration: duration, from: 0.5, to: 1)
backButton?.opacityDuration(duration: duration, from: 0, to: 1)
}
fileprivate func showControlViewDuration(duration: Double) {
moveUpControllerDuration(duration: duration)
showControlButtonsDuration(duration: duration)
showControlLabelDuration(duration: duration)
}
fileprivate func moveUpControllerDuration(duration: Double) {
controlBottomConstrant.constant = -controlHeightConstraint.constant
view.layoutIfNeeded()
controlBottomConstrant.constant = 0
UIView.animate(withDuration: duration, delay: 0, options: .curveEaseOut, animations: {
self.view.layoutIfNeeded()
}, completion: nil)
}
fileprivate func showControlButtonsDuration(duration: Double) {
[plusImageView, shareImageView, hertIconView].forEach {
$0?.rotateDuration(duration: duration, from: CGFloat.pi / 4, to: 0, delay: duration)
$0?.scaleDuration(duration: duration, from: 0.5, to: 1, delay: duration)
$0?.alpha = 0
$0?.opacityDuration(duration: duration, from: 0, to: 1, delay: duration, remove: false)
fileprivate func showBackButtonDuration(duration: Double) {
backButton?.rotateDuration(duration: duration, from: -CGFloat.pi / 4, to: 0)
backButton?.scaleDuration(duration: duration, from: 0.5, to: 1)
backButton?.opacityDuration(duration: duration, from: 0, to: 1)
}
}
fileprivate func showControlLabelDuration(duration: Double) {
controlTextLabel.alpha = 0
controlTextLabel.opacityDuration(duration: duration, from: 0, to: 1, delay: duration, remove: false)
// move rigth
let offSet: CGFloat = 20
controlTextLableLending.constant -= offSet
view.layoutIfNeeded()
controlTextLableLending.constant += offSet
UIView.animate(withDuration: duration * 2, delay: 0, options: .curveEaseOut, animations: {
self.view.layoutIfNeeded()
}, completion: nil)
}
fileprivate func showControlViewDuration(duration: Double) {
moveUpControllerDuration(duration: duration)
showControlButtonsDuration(duration: duration)
showControlLabelDuration(duration: duration)
}
fileprivate func moveUpControllerDuration(duration: Double) {
controlBottomConstrant.constant = -controlsViewContainer.bounds.height
view.layoutIfNeeded()
controlBottomConstrant.constant = 0
UIView.animate(withDuration: duration, delay: 0, options: .curveEaseOut, animations: {
self.view.layoutIfNeeded()
}, completion: nil)
}
fileprivate func showControlButtonsDuration(duration: Double) {
[plusImageView, shareImageView, hertIconView].forEach {
$0?.rotateDuration(duration: duration, from: CGFloat.pi / 4, to: 0, delay: duration)
$0?.scaleDuration(duration: duration, from: 0.5, to: 1, delay: duration)
$0?.alpha = 0
$0?.opacityDuration(duration: duration, from: 0, to: 1, delay: duration, remove: false)
}
}
fileprivate func showControlLabelDuration(duration: Double) {
controlTextLabel.alpha = 0
controlTextLabel.opacityDuration(duration: duration, from: 0, to: 1, delay: duration, remove: false)
// move rigth
let offSet: CGFloat = 20
controlTextLableLending.constant -= offSet
view.layoutIfNeeded()
controlTextLableLending.constant += offSet
UIView.animate(withDuration: duration * 2, delay: 0, options: .curveEaseOut, animations: {
self.view.layoutIfNeeded()
}, completion: nil)
}
}
// MARK: actions
extension DemoDetailViewController {
@objc func backButtonHandler() {
popViewController()
}
@objc func backButtonHandler() {
popViewController()
}
}
@@ -24,38 +24,38 @@
import UIKit
public class DemoTableViewController: PTTableViewController {
fileprivate let items = [("1", "River cruise"), ("2", "North Island"), ("3", "Mountain trail"), ("4", "Southern Coast"), ("5", "Fishing place")] // image names
fileprivate let items = [("1", "River cruise"), ("2", "North Island"), ("3", "Mountain trail"), ("4", "Southern Coast"), ("5", "Fishing place")] // image names
}
// MARK: UITableViewDelegate
extension DemoTableViewController {
public override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 100
}
public override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
guard let cell = cell as? ParallaxCell else { return }
let index = indexPath.row % items.count
let imageName = items[index].0
let title = items[index].1
if let image = UIImage(named: imageName) {
cell.setImage(image, title: title)
}
}
public override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: ParallaxCell = tableView.getReusableCellWithIdentifier(indexPath: indexPath)
return cell
}
public override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let storyboard = UIStoryboard.storyboard(storyboard: .Main)
let detaleViewController: DemoDetailViewController = storyboard.instantiateViewController()
pushViewController(detaleViewController)
}
extension DemoTableViewController {
public override func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int {
return 100
}
public override func tableView(_: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
guard let cell = cell as? ParallaxCell else { return }
let index = indexPath.row % items.count
let imageName = items[index].0
let title = items[index].1
if let image = UIImage(named: imageName) {
cell.setImage(image, title: title)
}
}
public override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: ParallaxCell = tableView.getReusableCellWithIdentifier(indexPath: indexPath)
return cell
}
public override func tableView(_: UITableView, didSelectRowAt _: IndexPath) {
let storyboard = UIStoryboard.storyboard(storyboard: .Main)
let detaleViewController: DemoDetailViewController = storyboard.instantiateViewController()
pushViewController(detaleViewController)
}
}
@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>
@@ -1,30 +0,0 @@
//
// PreviewTransitionDemoTests.swift
// PreviewTransitionDemoTests
//
// Created by Alex K. on 04/04/16.
// Copyright © 2016 Alex K. All rights reserved.
//
import XCTest
@testable import PreviewTransitionDemo
class PreviewTransitionDemoTests: XCTestCase {
override func setUp() {
super.setUp()
}
override func tearDown() {
super.tearDown()
}
func testExample() {
}
func testPerformanceExample() {
self.measureBlock {
}
}
}
@@ -9,43 +9,41 @@
import UIKit
extension UIView {
func makeScreenShotFromFrame(frame: CGRect) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(frame.size, false, 0.0)
let context = UIGraphicsGetCurrentContext();
context!.translateBy(x: frame.origin.x * -1, y: frame.origin.y * -1)
guard let currentContext = UIGraphicsGetCurrentContext() else {
return nil
}
self.layer.render(in: currentContext)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
func makeScreenShotFromFrame(frame: CGRect) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(frame.size, false, 0.0)
let context = UIGraphicsGetCurrentContext()
context!.translateBy(x: frame.origin.x * -1, y: frame.origin.y * -1)
guard let currentContext = UIGraphicsGetCurrentContext() else {
return nil
}
layer.render(in: currentContext)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
extension UIImageView {
func blurViewValue(value: CGFloat) {
guard let image = self.image,
let blurfilter = CIFilter(name: "CIGaussianBlur"),
let imageToBlur = CIImage(image: image)
else {
return
}
blurfilter.setValue(value, forKey: kCIInputRadiusKey)
blurfilter.setValue(imageToBlur, forKey: "inputImage")
let resultImage = blurfilter.value(forKey: "outputImage") as! CIImage
var blurredImage = UIImage(ciImage: resultImage)
let cropped:CIImage=resultImage.cropped(to: CGRect(x: 0, y: 0, width: imageToBlur.extent.size.width, height: imageToBlur.extent.size.height))
blurredImage = UIImage(ciImage: cropped)
self.image = blurredImage
}
func blurViewValue(value: CGFloat) {
guard let image = self.image,
let blurfilter = CIFilter(name: "CIGaussianBlur"),
let imageToBlur = CIImage(image: image)
else {
return
}
blurfilter.setValue(value, forKey: kCIInputRadiusKey)
blurfilter.setValue(imageToBlur, forKey: "inputImage")
let resultImage = blurfilter.value(forKey: "outputImage") as! CIImage
var blurredImage = UIImage(ciImage: resultImage)
let cropped: CIImage = resultImage.cropped(to: CGRect(x: 0, y: 0, width: imageToBlur.extent.size.width, height: imageToBlur.extent.size.height))
blurredImage = UIImage(ciImage: cropped)
self.image = blurredImage
}
}
+42 -20
View File
@@ -1,12 +1,34 @@
[![header](./header.png)](https://ramotion.com?utm_source=gthb&utm_medium=special&utm_campaign=preview-transition-logo)
![Animation](./preview.gif)
# Preview-transition
<a href="https://www.ramotion.com/agency/app-development/?utm_source=gthb&utm_medium=repo&utm_campaign=preview-transition"><img src="https://github.com/Ramotion/folding-cell/blob/master/header.png"></a>
<a href="https://github.com/Ramotion/fpreview-transition">
<img align="left" src="https://github.com/Ramotion/preview-transition/blob/master/preview-transition.gif" width="480" height="360" /></a>
<p><h1 align="left">PREVIEW TRANSITION</h1></p>
<h4>Preview Transition is a simple preview gallery UI controller with animated tranisitions</h4>
___
<p><h6>We specialize in the designing and coding of custom UI for Mobile Apps and Websites.</h6>
<a href="https://www.ramotion.com/agency/app-development/?utm_source=gthb&utm_medium=repo&utm_campaign=preview-transition">
<img src="https://github.com/ramotion/gliding-collection/raw/master/contact_our_team@2x.png" width="187" height="34"></a>
</p>
<p><h6>Stay tuned for the latest updates:</h6>
<a href="https://goo.gl/rPFpid" >
<img src="https://i.imgur.com/ziSqeSo.png/" width="156" height="28"></a></p>
</br>
[![Twitter](https://img.shields.io/badge/Twitter-@Ramotion-blue.svg?style=flat)](http://twitter.com/Ramotion)
[![Travis](https://img.shields.io/travis/Ramotion/preview-transition.svg)](https://travis-ci.org/Ramotion/preview-transition.svg?branch=master)
[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Ramotion/preview-transition)
[![CocoaPods](https://img.shields.io/cocoapods/p/PreviewTransition.svg)](https://cocoapods.org/pods/PreviewTransition)
[![CocoaPods](https://img.shields.io/cocoapods/v/PreviewTransition.svg)](http://cocoapods.org/pods/PreviewTransition)
[![codebeat badge](https://codebeat.co/badges/b99f71fe-b7e7-4a08-94bd-d98307d176ea)](https://codebeat.co/projects/github-com-ramotion-preview-transition)
[![Donate](https://img.shields.io/badge/Donate-PayPal-blue.svg)](https://paypal.me/Ramotion)
## About
@@ -16,15 +38,13 @@ We specialize in the designing and coding of custom UI for Mobile Apps and Websi
**Looking for developers for your project?**<br>
This project is maintained by Ramotion, Inc. We specialize in the designing and coding of custom UI for Mobile Apps and Websites.
<a href="https://ramotion.com/?utm_source=gthb&utm_medium=special&utm_campaign=preview-transition-contact-us/#Get_in_Touch">
<a href="https://www.ramotion.com/agency/app-development/?utm_source=gthb&utm_medium=repo&utm_campaign=preview-transition">
<img src="https://github.com/ramotion/gliding-collection/raw/master/contact_our_team@2x.png" width="187" height="34"></a> <br>
The [iPhone mockup](https://store.ramotion.com?utm_source=gthb&utm_medium=special&utm_campaign=preview-transition) available [here](https://store.ramotion.com?utm_source=gthb&utm_medium=special&utm_campaign=preview-transition).
## Requirements
- iOS 9.0+
- Xcode 8
- Xcode 9
## Licence
@@ -35,9 +55,7 @@ See [LICENSE](./LICENSE) for details.
Just add the Source folder to your project or use [CocoaPods](https://cocoapods.org) like this:
``` ruby
pod "PreviewTransition", "~> 2.0.1" swift 3
pod "PreviewTransition", "~> 1.1.5" swift 2
pod "PreviewTransition"
```
or [Carthage](https://github.com/Carthage/Carthage) users can simply add to their `Cartfile`:
@@ -140,19 +158,23 @@ if let font = UIFont(name: <Font name> , size: 18) {
]
}
```
# Get the Showroom App for iOS to give it a try
## 📄 License
Preview Transition is released under the MIT license.
See [LICENSE](./LICENSE) for details.
This library is a part of a <a href="https://github.com/Ramotion/swift-ui-animation-components-and-libraries"><b>selection of our best UI open-source projects.</b></a>
If you use the open-source library in your project, please make sure to credit and backlink to https://www.ramotion.com/
## 📱 Get the Showroom App for iOS to give it a try
Try this UI component and more like this in our iOS app. Contact us if interested.
<a href="https://itunes.apple.com/app/apple-store/id1182360240?pt=550053&ct=preview-transition&mt=8" >
<a href="https://itunes.apple.com/app/apple-store/id1182360240?pt=550053&ct=preview-transition&mt=8" >
<img src="https://github.com/ramotion/gliding-collection/raw/master/app_store@2x.png" width="117" height="34"></a>
<a href="https://ramotion.com/?utm_source=gthb&utm_medium=special&utm_campaign=preview-transition-contact-us/#Get_in_Touch">
<a href="https://www.ramotion.com/agency/app-development/?utm_source=gthb&utm_medium=repo&utm_campaign=preview-transition">
<img src="https://github.com/ramotion/gliding-collection/raw/master/contact_our_team@2x.png" width="187" height="34"></a>
<br>
<br>
Follow us for the latest updates<br>
[![Twitter URL](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/intent/tweet?text=https://github.com/ramotion/preview-transition)
[![Twitter Follow](https://img.shields.io/twitter/follow/ramotion.svg?style=social)](https://twitter.com/ramotion)
Binary file not shown.

After

Width:  |  Height:  |  Size: 13 MiB