Commit 5da64703 by Dmitriy Stepanets

Working on ShortsViewController UI

parent 05c77760
......@@ -12,7 +12,7 @@
<key>OneWeatherNotificationServiceExtension.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>61</integer>
<integer>67</integer>
</dict>
<key>PG (Playground) 1.xcscheme</key>
<dict>
......
......@@ -23,7 +23,7 @@
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>32</integer>
<integer>4</integer>
</dict>
<key>OneWeatherCorePlayground (Playground) 1.xcscheme</key>
<dict>
......
......@@ -35,6 +35,10 @@ class AppCoordinator: Coordinator {
forecastCoordinator.start()
childCoordinators.append(forecastCoordinator)
let shortsCoordinator = ShortsCoordinator(tabBarController: tabBarController)
shortsCoordinator.start()
childCoordinators.append(shortsCoordinator)
let radarCoordinator = RadarCoordinator(tabBarController: tabBarController)
radarCoordinator.start()
childCoordinators.append(radarCoordinator)
......
......@@ -10,7 +10,7 @@ import UIKit
class RadarCoordinator: Coordinator {
//Private
private let navigationController = UINavigationController(nibName: nil, bundle: nil)
private var tabBarController:UITabBarController?
private let tabBarController:UITabBarController
//Public
var childCoordinators = [Coordinator]()
......@@ -23,7 +23,7 @@ class RadarCoordinator: Coordinator {
func start() {
let radarViewController = RadarViewController(coordinator: self)
navigationController.viewControllers = [radarViewController]
tabBarController?.add(viewController: navigationController)
tabBarController.add(viewController: navigationController)
}
public func openNotificationsScreen() {
......
//
// ShortsCoordinator.swift
// 1Weather
//
// Created by Dmitry Stepanets on 10.06.2021.
//
import UIKit
class ShortsCoordinator: Coordinator {
//Private
private var tabBarController:UITabBarController
//Public
var childCoordinators = [Coordinator]()
var parentCoordinator: Coordinator?
init(tabBarController:UITabBarController) {
self.tabBarController = tabBarController
}
func start() {
let shortsViewController = ShortsViewController(coordinator: self)
tabBarController.add(viewController: shortsViewController)
}
func viewControllerDidEnd(controller: UIViewController) {
//
}
}
//
// UIColor+Highlight.swift
// 1Weather
//
// Created by Dmitry Stepanets on 28.11.2020.
//
import UIKit
public extension UIColor {
var isDarkColor: Bool {
var r, g, b, a: CGFloat
(r, g, b, a) = (0, 0, 0, 0)
self.getRed(&r, green: &g, blue: &b, alpha: &a)
let lum = 0.2126 * r + 0.7152 * g + 0.0722 * b
return lum < 0.60 ? true : false
}
var highlighted:UIColor {
return self.isDarkColor ? self.adjust(by: 30) : self.adjust(by: -30)
}
func lighter(by percentage: CGFloat = 30.0) -> UIColor? {
return self.adjust(by: abs(percentage) )
}
func darker(by percentage: CGFloat = 30.0) -> UIColor? {
return self.adjust(by: -1 * abs(percentage) )
}
func adjust(by percentage: CGFloat = 30.0) -> UIColor {
var red: CGFloat = 0, green: CGFloat = 0, blue: CGFloat = 0, alpha: CGFloat = 0
if self.getRed(&red, green: &green, blue: &blue, alpha: &alpha) {
return UIColor(red: min(red + percentage/100, 1.0),
green: min(green + percentage/100, 1.0),
blue: min(blue + percentage/100, 1.0),
alpha: alpha)
} else {
return self
}
}
}
......@@ -6,6 +6,7 @@
//
import UIKit
import OneWeatherCore
public enum AppInterfaceStyle {
case light
......
......@@ -155,6 +155,9 @@
"location.status.whenInUser" = "when in use";
"location.status.unknown" = "unknown";
//Shorts
"shorts.source" = "Source";
//Radar
"radar.layers.base" = "Base layer";
"radar.layers.severe" = "Severe weather layer";
......
......@@ -16,8 +16,9 @@ class AppTabBarController: UITabBarController {
public enum AppTab:Int, CaseIterable {
case today = 0
case forecast = 1
case radar = 2
case menu = 3
case shorts = 2
case radar = 3
case menu = 4
}
public func setupTabBar() {
......@@ -34,6 +35,10 @@ class AppTabBarController: UITabBarController {
tabBar.items?[$0.rawValue].title = "FORECAST"
tabBar.items?[$0.rawValue].image = UIImage(named: "tab_forecast")
tabBar.items?[$0.rawValue].selectedImage = UIImage(named: "tab_forecast_selected")
case .shorts:
tabBar.items?[$0.rawValue].title = "SHORTS"
tabBar.items?[$0.rawValue].image = UIImage(named: "tab_forecast")
tabBar.items?[$0.rawValue].selectedImage = UIImage(named: "tab_forecast_selected")
case .radar:
tabBar.items?[$0.rawValue].title = "RADAR"
tabBar.items?[$0.rawValue].image = UIImage(named: "tab_radar")
......
//
// ShortsItemCell.swift
// 1Weather
//
// Created by Dmitry Stepanets on 10.06.2021.
//
import UIKit
import OneWeatherCore
import Nuke
private class CellGradientView: UIView {
private var gradientLayer:CAGradientLayer? {
return self.layer as? CAGradientLayer
}
init() {
super.init(frame: .zero)
prepare()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override class var layerClass: AnyClass {
return CAGradientLayer.self
}
func update(color:UIColor) {
gradientLayer?.colors = [color.withAlphaComponent(0).cgColor,
color.cgColor]
}
private func prepare() {
self.backgroundColor = .clear
guard let gradientLayer = self.gradientLayer else { return }
gradientLayer.opacity = 1
gradientLayer.locations = [0.95, 1.0]
}
}
protocol ShortsItemCellDelegate: AnyObject {
func averageColor(forImage image:UIImage, identifier:String) -> UIColor?
}
class ShortsItemCell: UITableViewCell {
//Private
private static let dateFormatter: DateFormatter = {
let fmt = DateFormatter()
fmt.dateFormat = "d MMM, yyyy"
return fmt
}()
private static let kDefaultColor = UIColor(hex:0x39495c)
private let backgroundImageView = UIImageView()
private let gradientView = CellGradientView()
private let textContainer = UIView()
private let dateLabel = UILabel()
private let sourceLabel = UILabel()
private let titleLabel = UILabel()
private let summaryLabel = UILabel()
private let ctaButton = UIButton()
private let favoriteButton = UIButton()
private let shareButton = UIButton()
private let likeButton = UIButton()
private let swipeDownView = UIView()
//Public
weak var delegate:ShortsItemCellDelegate?
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
prepareBackground()
prepareTextContainer()
prepareGradient()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func prepareForReuse() {
super.prepareForReuse()
textContainer.backgroundColor = ShortsItemCell.kDefaultColor
gradientView.update(color: ShortsItemCell.kDefaultColor)
}
//Public
func configure(shortsItem:ShortsItem) {
if let backgroundImage = self.bestImageForCell(images: shortsItem.images) {
Nuke.loadImage(with: backgroundImage.url, into: backgroundImageView) {[weak self] result in
switch result {
case .success(let imageResponse):
onMain {
self?.backgroundImageView.image = imageResponse.image
if let cachedColor = self?.delegate?.averageColor(forImage: imageResponse.image,
identifier: backgroundImage.url.absoluteString) {
self?.textContainer.backgroundColor = cachedColor
self?.gradientView.update(color: cachedColor)
}
else {
self?.textContainer.backgroundColor = ShortsItemCell.kDefaultColor
self?.gradientView.update(color: ShortsItemCell.kDefaultColor)
}
}
default:
break
}
}
}
else {
backgroundImageView.image = nil
gradientView.update(color: ShortsItemCell.kDefaultColor)
textContainer.backgroundColor = ShortsItemCell.kDefaultColor
}
dateLabel.text = ShortsItemCell.dateFormatter.string(from: Date(timeIntervalSince1970: shortsItem.updatedAtInSecs))
sourceLabel.text = "shorts.source".localized() + " : " + "\(shortsItem.sourceName)"
titleLabel.text = shortsItem.title
summaryLabel.text = shortsItem.summaryText
UIView.performWithoutAnimation {
self.ctaButton.setTitle(shortsItem.ctaText, for: .normal)
}
}
//Private
private func bestImageForCell(images:[ShortsItemImage]) -> ShortsItemImage? {
guard !images.isEmpty && self.frame != .zero else {
return nil
}
var image = images.first
for itemImage in images {
if CGFloat(itemImage.width) >= self.frame.width && CGFloat(itemImage.height) >= self.frame.height {
image = itemImage
break
}
}
return image
}
@objc private func handleCtaButton() {
}
}
//MARK:- Prepare
private extension ShortsItemCell {
func prepareBackground() {
backgroundImageView.contentMode = .scaleAspectFill
contentView.addSubview(backgroundImageView)
backgroundImageView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
}
func prepareGradient() {
contentView.addSubview(gradientView)
gradientView.snp.makeConstraints { make in
make.left.top.right.equalToSuperview()
make.bottom.equalTo(textContainer.snp.top)
}
}
func prepareTextContainer() {
textContainer.backgroundColor = UIColor(hex: 0x39495c)
contentView.addSubview(textContainer)
dateLabel.textColor = UIColor.white
dateLabel.font = AppFont.SFPro.regular(size: 12)
textContainer.addSubview(dateLabel)
sourceLabel.textColor = UIColor.white.withAlphaComponent(0.6)
sourceLabel.font = AppFont.SFPro.regular(size: 12)
textContainer.addSubview(sourceLabel)
titleLabel.textColor = UIColor.white
titleLabel.font = AppFont.SFPro.bold(size: 18)
titleLabel.numberOfLines = 0
titleLabel.lineBreakMode = .byWordWrapping
titleLabel.setContentCompressionResistancePriority(.fittingSizeLevel, for: .vertical)
textContainer.addSubview(titleLabel)
summaryLabel.textColor = UIColor.white
summaryLabel.font = AppFont.SFPro.regular(size: 12)
summaryLabel.numberOfLines = 0
summaryLabel.lineBreakMode = .byWordWrapping
textContainer.addSubview(summaryLabel)
ctaButton.addTarget(self, action: #selector(handleCtaButton), for: .touchUpInside)
ctaButton.backgroundColor = .clear
ctaButton.layer.borderColor = UIColor(hex: 0xDDDDDD).cgColor
ctaButton.layer.borderWidth = 1
ctaButton.titleLabel?.textColor = UIColor.white
ctaButton.titleLabel?.font = AppFont.SFPro.bold(size: 12)
ctaButton.layer.cornerRadius = 14
textContainer.addSubview(ctaButton)
//Constraints
textContainer.snp.makeConstraints { make in
make.left.bottom.right.equalToSuperview()
}
dateLabel.snp.makeConstraints { make in
make.left.equalToSuperview().inset(18)
make.top.equalToSuperview()
}
sourceLabel.snp.makeConstraints { make in
make.left.equalTo(dateLabel.snp.right).offset(6)
make.top.equalToSuperview()
}
titleLabel.snp.makeConstraints { make in
make.left.equalToSuperview().inset(18)
make.right.equalToSuperview().inset(62)
make.top.equalTo(dateLabel.snp.bottom).offset(8)
}
summaryLabel.snp.makeConstraints { make in
make.left.equalToSuperview().inset(18)
make.right.equalToSuperview().inset(62)
make.top.equalTo(titleLabel.snp.bottom).offset(8)
}
ctaButton.snp.makeConstraints { make in
make.width.equalTo(92)
make.height.equalTo(28)
make.top.equalTo(summaryLabel.snp.bottom).offset(16)
make.left.equalToSuperview().inset(18)
make.bottom.greaterThanOrEqualToSuperview().inset(60)
make.bottom.equalToSuperview().inset(60)
}
}
}
//
// ShortsViewController.swift
// 1Weather
//
// Created by Dmitry Stepanets on 10.06.2021.
//
import UIKit
import OneWeatherCore
import pop
private enum ScrollDirection {
case toTop
case toBottom
}
class ShortsViewController: UIViewController {
//Private
private let kAnimationKey = "com.oneWeather.scrollView.snappingAnimation"
private let coordinator:ShortsCoordinator
private let viewModel = ShortsViewModel()
private let tableView = UITableView()
private var averageColorCache = [AnyHashable:UIColor]()
private var lastOffset: CGFloat = 0
init(coordinator:ShortsCoordinator) {
self.coordinator = coordinator
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
viewModel.delegate = self
prepareTableView()
viewModel.updateShorts()
}
private func scrollTo(newOffset:CGPoint, velocity:CGPoint) {
let animation = POPBasicAnimation(propertyNamed: kPOPScrollViewContentOffset)
animation?.timingFunction = CAMediaTimingFunction(name: .easeOut)
animation?.duration = 0.4
animation?.toValue = newOffset
animation?.fromValue = tableView.contentOffset
tableView.pop_add(animation, forKey: kAnimationKey)
}
}
//MARK:- Prepare
private extension ShortsViewController {
func prepareTableView() {
tableView.register(ShortsItemCell.self, forCellReuseIdentifier: ShortsItemCell.kIdentifier)
tableView.contentInsetAdjustmentBehavior = .never
tableView.dataSource = self
tableView.delegate = self
view.addSubview(tableView)
tableView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
}
}
//MARK:- UITableView Data Source
extension ShortsViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewModel.shorts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: ShortsItemCell.kIdentifier) as! ShortsItemCell
cell.configure(shortsItem: viewModel.shorts[indexPath.row])
cell.delegate = self
return cell
}
}
//MARK:- UITableView Delegate
extension ShortsViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return tableView.bounds.height
}
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
//Get direction
let direction:ScrollDirection
if velocity.y != 0 {
direction = velocity.y > 0 ? .toBottom : .toTop
}
else {
direction = targetContentOffset.pointee.y - lastOffset > 0 ? .toBottom : .toTop
}
//Save last offset
lastOffset = scrollView.contentOffset.y
//Disable velocity scrolling
targetContentOffset.pointee = scrollView.contentOffset
//Get visible rows IndexPaths
guard
let visiblePath = (tableView.indexPathsForVisibleRows?.sorted{$0.row < $1.row}),
visiblePath.count > 0,
let topRowIndexPath = visiblePath.first
else {
return
}
//Calculate next row
let nextRowIndexPath:IndexPath
switch direction {
case .toBottom:
let rowsCount = tableView.numberOfRows(inSection: topRowIndexPath.section)
let nextIndex = min(topRowIndexPath.row + 1, rowsCount - 1)
nextRowIndexPath = IndexPath(row: nextIndex, section: topRowIndexPath.section)
//Check for the last row
if nextRowIndexPath.row == rowsCount - 1 {
let offset = tableView.contentSize.height - tableView.frame.height
self.scrollTo(newOffset: .init(x: tableView.contentOffset.x, y: offset), velocity: velocity)
return
}
case .toTop:
if topRowIndexPath.row == 0 {
self.scrollTo(newOffset: .zero, velocity: velocity)
return
}
nextRowIndexPath = topRowIndexPath
}
let nextRowRect = tableView.rectForRow(at: nextRowIndexPath)
self.scrollTo(newOffset: nextRowRect.origin, velocity: velocity)
}
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
pop_removeAnimation(forKey: kAnimationKey)
}
}
//MARK:- ViewModel Delegate
extension ShortsViewController: ViewModelDelegate {
func viewModelDidChange<P>(model: P) where P : ViewModelProtocol {
onMain {
self.tableView.reloadData()
}
}
func viewModel<P>(model: P, errorHasOccured error: String?) where P : ViewModelProtocol {
self.showAlert(withTitle: "Updating error", message: "Failed to update shorts")
}
}
//MARK:- ShortsItemCell Delegate
extension ShortsViewController: ShortsItemCellDelegate {
func averageColor(forImage image: UIImage, identifier: String) -> UIColor? {
if let cachedColor = self.averageColorCache[identifier] {
return cachedColor
}
else {
if let color = image.averageColor {
self.averageColorCache[identifier] = color.isDarkColor ? color : color.darker(by: 30)
return color
}
else {
return nil
}
}
}
}
......@@ -73,7 +73,7 @@ extension ShortsView: ShortsCollectionCellDelegate {
}
else {
if let color = image.averageColor {
self.averageColorCache[identifier] = color
self.averageColorCache[identifier] = color.isDarkColor ? color : color.darker(by: 30)
return color
}
else {
......
//
// ShortsViewModel.swift
// 1Weather
//
// Created by Dmitry Stepanets on 10.06.2021.
//
import Foundation
import OneWeatherCore
class ShortsViewModel: ViewModelProtocol {
//Private
private let shortsManager = ShortsManager.shared
//Public
weak var delegate:ViewModelDelegate?
private(set) var shorts = [ShortsItem]()
func updateShorts() {
shortsManager.fetchShorts {[weak self] result in
guard let self = self else { return }
switch result {
case .success(let shortsItems):
self.shorts.removeAll()
self.shorts = shortsItems
self.delegate?.viewModelDidChange(model: self)
case .failure(let error):
self.delegate?.viewModel(model: self, errorHasOccured: error.localizedDescription)
}
}
}
}
//
// UIColor+Highlight.swift
// 1Weather
//
// Created by Dmitry Stepanets on 28.11.2020.
//
import UIKit
public extension UIColor {
private var isDarkColor: Bool {
var r, g, b, a: CGFloat
(r, g, b, a) = (0, 0, 0, 0)
self.getRed(&r, green: &g, blue: &b, alpha: &a)
let lum = 0.2126 * r + 0.7152 * g + 0.0722 * b
return lum < 0.60 ? true : false
}
var highlighted:UIColor {
return self.isDarkColor ? self.adjust(by: 30) : self.adjust(by: -30)
}
func lighten(by fraction:CGFloat) -> UIColor {
var red: CGFloat = 0
var green: CGFloat = 0
var blue: CGFloat = 0
var alpha: CGFloat = 0
getRed(&red, green: &green, blue: &blue, alpha: &alpha)
red = lightenColor(color: red, fraction: fraction)
green = lightenColor(color: green, fraction: fraction)
blue = lightenColor(color: blue, fraction: fraction)
return UIColor(red: red, green: green, blue: blue, alpha: alpha)
}
func darken(by fraction:CGFloat) -> UIColor {
var red: CGFloat = 0
var green: CGFloat = 0
var blue: CGFloat = 0
var alpha: CGFloat = 0
getRed(&red, green: &green, blue: &blue, alpha: &alpha)
red = darkenColor(color: red, fraction: fraction)
green = darkenColor(color: green, fraction: fraction)
blue = darkenColor(color: blue, fraction: fraction)
return UIColor(red: red, green: green, blue: blue, alpha: alpha)
}
private func lightenColor(color: CGFloat, fraction: CGFloat) -> CGFloat {
return min(color + (1 - color) * fraction, 1)
}
private func darkenColor(color: CGFloat, fraction: CGFloat) -> CGFloat {
return max(color - color * fraction, 0)
}
private func adjust(by percentage:CGFloat=30.0) -> UIColor {
var r:CGFloat=0, g:CGFloat=0, b:CGFloat=0, a:CGFloat=0;
if(self.getRed(&r, green: &g, blue: &b, alpha: &a)){
return UIColor(red: min(r + percentage/100, 1.0),
green: min(g + percentage/100, 1.0),
blue: min(b + percentage/100, 1.0),
alpha: a)
}
else{
return self
}
}
}
......@@ -46,6 +46,7 @@ def application_pods
pod 'PKHUD', '~> 5.0'
pod 'Nuke'
pod 'Nuke-WebP-Plugin'
pod 'pop', :git => 'https://github.com/facebook/pop.git'
end
#-------Targets-------
......
......@@ -189,6 +189,7 @@ PODS:
- libwebp (= 1.1.0)
- Nuke (~> 9.0)
- PKHUD (5.3.0)
- pop (1.0.11)
- PromisesObjC (1.2.12)
- SnapKit (5.0.1)
- Swarm (1.0.7)
......@@ -216,6 +217,7 @@ DEPENDENCIES:
- Nuke
- Nuke-WebP-Plugin
- PKHUD (~> 5.0)
- pop (from `https://github.com/facebook/pop.git`)
- SnapKit
- "Swarm (from `git@gitlab.pinsightmedia.com:oneweather/wdt-skywisetilekit-ios.git`, branch `develop`)"
- XMLCoder (~> 0.12.0)
......@@ -264,6 +266,8 @@ SPEC REPOS:
EXTERNAL SOURCES:
Cirque:
:git: https://github.com/StepanetsDmtry/Cirque.git
pop:
:git: https://github.com/facebook/pop.git
Swarm:
:branch: develop
:git: "git@gitlab.pinsightmedia.com:oneweather/wdt-skywisetilekit-ios.git"
......@@ -272,6 +276,9 @@ CHECKOUT OPTIONS:
Cirque:
:commit: ceb7ba910a35973cbcd41c73a62be6305aed4d13
:git: https://github.com/StepanetsDmtry/Cirque.git
pop:
:commit: 87d1f8b74cdaa4699d7a9f6be1ff5202014c581f
:git: https://github.com/facebook/pop.git
Swarm:
:commit: 85c4a3651dbc30b6320bcda27d1c0992b651f3a8
:git: "git@gitlab.pinsightmedia.com:oneweather/wdt-skywisetilekit-ios.git"
......@@ -313,11 +320,12 @@ SPEC CHECKSUMS:
Nuke: 6f400a4ea957e09149ec335a3c6acdcc814d89e4
Nuke-WebP-Plugin: a79a97be508453ce5c36b78989595cbbc19c2deb
PKHUD: 98f3e4bc904b9c916f1c5bb6d765365b5357291b
pop: ae3ae187018759968252242e175c21f7f9be5dd2
PromisesObjC: 3113f7f76903778cf4a0586bd1ab89329a0b7b97
SnapKit: 97b92857e3df3a0c71833cce143274bf6ef8e5eb
Swarm: 95393cd52715744c94e3a8475bc20b4de5d79f35
XMLCoder: f884dfa894a6f8b7dce465e4f6c02963bf17e028
PODFILE CHECKSUM: 2da69d89ab797bf224c9e0c50d943473a0f86c3b
PODFILE CHECKSUM: da03a05dc9d853e4534fd9e8fc8afb7fd54071e3
COCOAPODS: 1.10.1
{
"name": "pop",
"version": "1.0.11",
"license": {
"type": "BSD"
},
"homepage": "https://github.com/facebook/pop",
"authors": {
"Kimon Tsinteris": "kimon@mac.com"
},
"summary": "Extensible animation framework for iOS and OS X.",
"source": {
"git": "https://github.com/facebook/pop.git",
"tag": "1.0.10"
},
"source_files": "pop/**/*.{h,m,mm,cpp}",
"public_header_files": "pop/{POP,POPAnimatableProperty,POPAnimatablePropertyTypes,POPAnimation,POPAnimationEvent,POPAnimationExtras,POPAnimationTracer,POPAnimator,POPBasicAnimation,POPCustomAnimation,POPDecayAnimation,POPDefines,POPGeometry,POPLayerExtras,POPPropertyAnimation,POPSpringAnimation,POPVector}.h",
"requires_arc": true,
"social_media_url": "https://twitter.com/fbOpenSource",
"libraries": "c++",
"pod_target_xcconfig": {
"CLANG_CXX_LANGUAGE_STANDARD": "c++11",
"CLANG_CXX_LIBRARY": "libc++"
},
"platforms": {
"ios": "8.0",
"osx": "10.8",
"tvos": "9.0"
}
}
......@@ -189,6 +189,7 @@ PODS:
- libwebp (= 1.1.0)
- Nuke (~> 9.0)
- PKHUD (5.3.0)
- pop (1.0.11)
- PromisesObjC (1.2.12)
- SnapKit (5.0.1)
- Swarm (1.0.7)
......@@ -216,6 +217,7 @@ DEPENDENCIES:
- Nuke
- Nuke-WebP-Plugin
- PKHUD (~> 5.0)
- pop (from `https://github.com/facebook/pop.git`)
- SnapKit
- "Swarm (from `git@gitlab.pinsightmedia.com:oneweather/wdt-skywisetilekit-ios.git`, branch `develop`)"
- XMLCoder (~> 0.12.0)
......@@ -264,6 +266,8 @@ SPEC REPOS:
EXTERNAL SOURCES:
Cirque:
:git: https://github.com/StepanetsDmtry/Cirque.git
pop:
:git: https://github.com/facebook/pop.git
Swarm:
:branch: develop
:git: "git@gitlab.pinsightmedia.com:oneweather/wdt-skywisetilekit-ios.git"
......@@ -272,6 +276,9 @@ CHECKOUT OPTIONS:
Cirque:
:commit: ceb7ba910a35973cbcd41c73a62be6305aed4d13
:git: https://github.com/StepanetsDmtry/Cirque.git
pop:
:commit: 87d1f8b74cdaa4699d7a9f6be1ff5202014c581f
:git: https://github.com/facebook/pop.git
Swarm:
:commit: 85c4a3651dbc30b6320bcda27d1c0992b651f3a8
:git: "git@gitlab.pinsightmedia.com:oneweather/wdt-skywisetilekit-ios.git"
......@@ -313,11 +320,12 @@ SPEC CHECKSUMS:
Nuke: 6f400a4ea957e09149ec335a3c6acdcc814d89e4
Nuke-WebP-Plugin: a79a97be508453ce5c36b78989595cbbc19c2deb
PKHUD: 98f3e4bc904b9c916f1c5bb6d765365b5357291b
pop: ae3ae187018759968252242e175c21f7f9be5dd2
PromisesObjC: 3113f7f76903778cf4a0586bd1ab89329a0b7b97
SnapKit: 97b92857e3df3a0c71833cce143274bf6ef8e5eb
Swarm: 95393cd52715744c94e3a8475bc20b4de5d79f35
XMLCoder: f884dfa894a6f8b7dce465e4f6c02963bf17e028
PODFILE CHECKSUM: 2da69d89ab797bf224c9e0c50d943473a0f86c3b
PODFILE CHECKSUM: da03a05dc9d853e4534fd9e8fc8afb7fd54071e3
COCOAPODS: 1.10.1
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -3021,4 +3021,38 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
## mopub-ios-sdk
The MoPub SDK License can be found at http://www.mopub.com/legal/sdk-license-agreement/
## pop
BSD License
For Pop software
Copyright (c) 2014, Facebook, Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name Facebook nor the names of its contributors may be used to
endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Generated by CocoaPods - https://cocoapods.org
......@@ -3269,6 +3269,46 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
</dict>
<dict>
<key>FooterText</key>
<string>BSD License
For Pop software
Copyright (c) 2014, Facebook, Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name Facebook nor the names of its contributors may be used to
endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
</string>
<key>License</key>
<string>BSD</string>
<key>Title</key>
<string>pop</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>Generated by CocoaPods - https://cocoapods.org</string>
<key>Title</key>
<string></string>
......
......@@ -30,5 +30,6 @@ ${BUILT_PRODUCTS_DIR}/Swarm/Swarm.framework
${BUILT_PRODUCTS_DIR}/libwebp/libwebp.framework
${BUILT_PRODUCTS_DIR}/lottie-ios/Lottie.framework
${BUILT_PRODUCTS_DIR}/mopub-ios-sdk/MoPubSDK.framework
${BUILT_PRODUCTS_DIR}/pop/pop.framework
${PODS_XCFRAMEWORKS_BUILD_DIR}/DTBiOSSDK/DTBiOSSDK.framework/DTBiOSSDK
${PODS_XCFRAMEWORKS_BUILD_DIR}/OMSDK_Mopub/OMSDK_Mopub.framework/OMSDK_Mopub
\ No newline at end of file
......@@ -29,5 +29,6 @@ ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Swarm.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libwebp.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Lottie.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MoPubSDK.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/pop.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DTBiOSSDK.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OMSDK_Mopub.framework
\ No newline at end of file
......@@ -30,5 +30,6 @@ ${BUILT_PRODUCTS_DIR}/Swarm/Swarm.framework
${BUILT_PRODUCTS_DIR}/libwebp/libwebp.framework
${BUILT_PRODUCTS_DIR}/lottie-ios/Lottie.framework
${BUILT_PRODUCTS_DIR}/mopub-ios-sdk/MoPubSDK.framework
${BUILT_PRODUCTS_DIR}/pop/pop.framework
${PODS_XCFRAMEWORKS_BUILD_DIR}/DTBiOSSDK/DTBiOSSDK.framework/DTBiOSSDK
${PODS_XCFRAMEWORKS_BUILD_DIR}/OMSDK_Mopub/OMSDK_Mopub.framework/OMSDK_Mopub
\ No newline at end of file
......@@ -29,5 +29,6 @@ ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Swarm.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libwebp.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Lottie.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MoPubSDK.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/pop.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DTBiOSSDK.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OMSDK_Mopub.framework
\ No newline at end of file
......@@ -206,6 +206,7 @@ if [[ "$CONFIGURATION" == "Debug" ]]; then
install_framework "${BUILT_PRODUCTS_DIR}/libwebp/libwebp.framework"
install_framework "${BUILT_PRODUCTS_DIR}/lottie-ios/Lottie.framework"
install_framework "${BUILT_PRODUCTS_DIR}/mopub-ios-sdk/MoPubSDK.framework"
install_framework "${BUILT_PRODUCTS_DIR}/pop/pop.framework"
install_framework "${PODS_XCFRAMEWORKS_BUILD_DIR}/DTBiOSSDK/DTBiOSSDK.framework"
install_framework "${PODS_XCFRAMEWORKS_BUILD_DIR}/OMSDK_Mopub/OMSDK_Mopub.framework"
fi
......@@ -241,6 +242,7 @@ if [[ "$CONFIGURATION" == "Release" ]]; then
install_framework "${BUILT_PRODUCTS_DIR}/libwebp/libwebp.framework"
install_framework "${BUILT_PRODUCTS_DIR}/lottie-ios/Lottie.framework"
install_framework "${BUILT_PRODUCTS_DIR}/mopub-ios-sdk/MoPubSDK.framework"
install_framework "${BUILT_PRODUCTS_DIR}/pop/pop.framework"
install_framework "${PODS_XCFRAMEWORKS_BUILD_DIR}/DTBiOSSDK/DTBiOSSDK.framework"
install_framework "${PODS_XCFRAMEWORKS_BUILD_DIR}/OMSDK_Mopub/OMSDK_Mopub.framework"
fi
......
<?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>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0.11</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${CURRENT_PROJECT_VERSION}</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
#import <Foundation/Foundation.h>
@interface PodsDummy_pop : NSObject
@end
@implementation PodsDummy_pop
@end
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#else
#ifndef FOUNDATION_EXPORT
#if defined(__cplusplus)
#define FOUNDATION_EXPORT extern "C"
#else
#define FOUNDATION_EXPORT extern
#endif
#endif
#endif
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#else
#ifndef FOUNDATION_EXPORT
#if defined(__cplusplus)
#define FOUNDATION_EXPORT extern "C"
#else
#define FOUNDATION_EXPORT extern
#endif
#endif
#endif
#import "POP.h"
#import "POPAnimatableProperty.h"
#import "POPAnimatablePropertyTypes.h"
#import "POPAnimation.h"
#import "POPAnimationEvent.h"
#import "POPAnimationExtras.h"
#import "POPAnimationTracer.h"
#import "POPAnimator.h"
#import "POPBasicAnimation.h"
#import "POPCustomAnimation.h"
#import "POPDecayAnimation.h"
#import "POPDefines.h"
#import "POPGeometry.h"
#import "POPLayerExtras.h"
#import "POPPropertyAnimation.h"
#import "POPSpringAnimation.h"
#import "POPVector.h"
FOUNDATION_EXPORT double popVersionNumber;
FOUNDATION_EXPORT const unsigned char popVersionString[];
CLANG_CXX_LANGUAGE_STANDARD = c++11
CLANG_CXX_LIBRARY = libc++
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/pop
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
OTHER_LDFLAGS = $(inherited) -l"c++"
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_ROOT = ${SRCROOT}
PODS_TARGET_SRCROOT = ${PODS_ROOT}/pop
PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
SKIP_INSTALL = YES
USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
framework module pop {
umbrella header "pop-umbrella.h"
export *
module * { export * }
}
CLANG_CXX_LANGUAGE_STANDARD = c++11
CLANG_CXX_LIBRARY = libc++
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/pop
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
OTHER_LDFLAGS = $(inherited) -l"c++"
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_ROOT = ${SRCROOT}
PODS_TARGET_SRCROOT = ${PODS_ROOT}/pop
PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
SKIP_INSTALL = YES
USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
BSD License
For Pop software
Copyright (c) 2014, Facebook, Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name Facebook nor the names of its contributors may be used to
endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/**
Copyright (c) 2014-present, Facebook, Inc.
All rights reserved.
This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree. An additional grant
of patent rights can be found in the PATENTS file in the same directory.
*/
#ifndef POP_POP_H
#define POP_POP_H
#import <pop/POPDefines.h>
#import <pop/POPAnimatableProperty.h>
#import <pop/POPAnimatablePropertyTypes.h>
#import <pop/POPAnimation.h>
#import <pop/POPAnimationEvent.h>
#import <pop/POPAnimationExtras.h>
#import <pop/POPAnimationTracer.h>
#import <pop/POPAnimator.h>
#import <pop/POPBasicAnimation.h>
#import <pop/POPCustomAnimation.h>
#import <pop/POPDecayAnimation.h>
#import <pop/POPGeometry.h>
#import <pop/POPLayerExtras.h>
#import <pop/POPPropertyAnimation.h>
#import <pop/POPSpringAnimation.h>
#endif /* POP_POP_H */
/**
Copyright (c) 2014-present, Facebook, Inc.
All rights reserved.
This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree. An additional grant
of patent rights can be found in the PATENTS file in the same directory.
*/
#ifndef POPACTION_H
#define POPACTION_H
#import <QuartzCore/CATransaction.h>
#import <pop/POPDefines.h>
#ifdef __cplusplus
namespace POP {
/**
@abstract Disables Core Animation actions using RAII.
@discussion The disablement of actions is scoped to the current transaction.
*/
class ActionDisabler
{
BOOL state;
public:
ActionDisabler() POP_NOTHROW
{
state = [CATransaction disableActions];
[CATransaction setDisableActions:YES];
}
~ActionDisabler()
{
[CATransaction setDisableActions:state];
}
};
/**
@abstract Enables Core Animation actions using RAII.
@discussion The enablement of actions is scoped to the current transaction.
*/
class ActionEnabler
{
BOOL state;
public:
ActionEnabler() POP_NOTHROW
{
state = [CATransaction disableActions];
[CATransaction setDisableActions:NO];
}
~ActionEnabler()
{
[CATransaction setDisableActions:state];
}
};
}
#endif /* __cplusplus */
#endif /* POPACTION_H */
/**
Copyright (c) 2014-present, Facebook, Inc.
All rights reserved.
This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree. An additional grant
of patent rights can be found in the PATENTS file in the same directory.
*/
#import <CoreGraphics/CoreGraphics.h>
#import <Foundation/NSObject.h>
#import <pop/POPDefines.h>
#import <pop/POPAnimatablePropertyTypes.h>
@class POPMutableAnimatableProperty;
/**
@abstract Describes an animatable property.
*/
@interface POPAnimatableProperty : NSObject <NSCopying, NSMutableCopying>
/**
@abstract Property accessor.
@param name The name of the property.
@return The animatable property with that name or nil if it does not exist.
@discussion Common animatable properties are included by default. Use the provided constants to reference.
*/
+ (id)propertyWithName:(NSString *)name;
/**
@abstract The designated initializer.
@param name The name of the property.
@param block The block used to configure the property on creation.
@return The animatable property with name if it exists, otherwise a newly created instance configured by block.
@discussion Custom properties should use reverse-DNS naming. A newly created instance is only mutable in the scope of block. Once constructed, a property becomes immutable.
*/
+ (id)propertyWithName:(NSString *)name initializer:(void (^)(POPMutableAnimatableProperty *prop))block;
/**
@abstract The name of the property.
@discussion Used to uniquely identify an animatable property.
*/
@property (readonly, nonatomic, copy) NSString *name;
/**
@abstract Block used to read values from a property into an array of floats.
*/
@property (readonly, nonatomic, copy) POPAnimatablePropertyReadBlock readBlock;
/**
@abstract Block used to write values from an array of floats into a property.
*/
@property (readonly, nonatomic, copy) POPAnimatablePropertyWriteBlock writeBlock;
/**
@abstract The threshold value used when determining completion of dynamics simulations.
*/
@property (readonly, nonatomic, assign) CGFloat threshold;
@end
/**
@abstract A mutable animatable property intended for configuration.
*/
@interface POPMutableAnimatableProperty : POPAnimatableProperty
/**
@abstract A read-write version of POPAnimatableProperty name property.
*/
@property (readwrite, nonatomic, copy) NSString *name;
/**
@abstract A read-write version of POPAnimatableProperty readBlock property.
*/
@property (readwrite, nonatomic, copy) POPAnimatablePropertyReadBlock readBlock;
/**
@abstract A read-write version of POPAnimatableProperty writeBlock property.
*/
@property (readwrite, nonatomic, copy) POPAnimatablePropertyWriteBlock writeBlock;
/**
@abstract A read-write version of POPAnimatableProperty threshold property.
*/
@property (readwrite, nonatomic, assign) CGFloat threshold;
@end
POP_EXTERN_C_BEGIN
/**
Common CALayer property names.
*/
extern NSString * const kPOPLayerBackgroundColor;
extern NSString * const kPOPLayerBounds;
extern NSString * const kPOPLayerCornerRadius;
extern NSString * const kPOPLayerBorderWidth;
extern NSString * const kPOPLayerBorderColor;
extern NSString * const kPOPLayerOpacity;
extern NSString * const kPOPLayerPosition;
extern NSString * const kPOPLayerPositionX;
extern NSString * const kPOPLayerPositionY;
extern NSString * const kPOPLayerRotation;
extern NSString * const kPOPLayerRotationX;
extern NSString * const kPOPLayerRotationY;
extern NSString * const kPOPLayerScaleX;
extern NSString * const kPOPLayerScaleXY;
extern NSString * const kPOPLayerScaleY;
extern NSString * const kPOPLayerSize;
extern NSString * const kPOPLayerSubscaleXY;
extern NSString * const kPOPLayerSubtranslationX;
extern NSString * const kPOPLayerSubtranslationXY;
extern NSString * const kPOPLayerSubtranslationY;
extern NSString * const kPOPLayerSubtranslationZ;
extern NSString * const kPOPLayerTranslationX;
extern NSString * const kPOPLayerTranslationXY;
extern NSString * const kPOPLayerTranslationY;
extern NSString * const kPOPLayerTranslationZ;
extern NSString * const kPOPLayerZPosition;
extern NSString * const kPOPLayerShadowColor;
extern NSString * const kPOPLayerShadowOffset;
extern NSString * const kPOPLayerShadowOpacity;
extern NSString * const kPOPLayerShadowRadius;
/**
Common CAShapeLayer property names.
*/
extern NSString * const kPOPShapeLayerStrokeStart;
extern NSString * const kPOPShapeLayerStrokeEnd;
extern NSString * const kPOPShapeLayerStrokeColor;
extern NSString * const kPOPShapeLayerFillColor;
extern NSString * const kPOPShapeLayerLineWidth;
extern NSString * const kPOPShapeLayerLineDashPhase;
/**
Common NSLayoutConstraint property names.
*/
extern NSString * const kPOPLayoutConstraintConstant;
#if TARGET_OS_IPHONE
/**
Common UIView property names.
*/
extern NSString * const kPOPViewAlpha;
extern NSString * const kPOPViewBackgroundColor;
extern NSString * const kPOPViewBounds;
extern NSString * const kPOPViewCenter;
extern NSString * const kPOPViewFrame;
extern NSString * const kPOPViewScaleX;
extern NSString * const kPOPViewScaleXY;
extern NSString * const kPOPViewScaleY;
extern NSString * const kPOPViewSize;
extern NSString * const kPOPViewTintColor;
/**
Common UIScrollView property names.
*/
extern NSString * const kPOPScrollViewContentOffset;
extern NSString * const kPOPScrollViewContentSize;
extern NSString * const kPOPScrollViewZoomScale;
extern NSString * const kPOPScrollViewContentInset;
extern NSString * const kPOPScrollViewScrollIndicatorInsets;
/**
Common UITableView property names.
*/
extern NSString * const kPOPTableViewContentOffset;
extern NSString * const kPOPTableViewContentSize;
/**
Common UICollectionView property names.
*/
extern NSString * const kPOPCollectionViewContentOffset;
extern NSString * const kPOPCollectionViewContentSize;
/**
Common UINavigationBar property names.
*/
extern NSString * const kPOPNavigationBarBarTintColor;
/**
Common UIToolbar property names.
*/
extern NSString * const kPOPToolbarBarTintColor;
/**
Common UITabBar property names.
*/
extern NSString * const kPOPTabBarBarTintColor;
/**
Common UILabel property names.
*/
extern NSString * const kPOPLabelTextColor;
#else
/**
Common NSView property names.
*/
extern NSString * const kPOPViewFrame;
extern NSString * const kPOPViewBounds;
extern NSString * const kPOPViewAlphaValue;
extern NSString * const kPOPViewFrameRotation;
extern NSString * const kPOPViewFrameCenterRotation;
extern NSString * const kPOPViewBoundsRotation;
/**
Common NSWindow property names.
*/
extern NSString * const kPOPWindowFrame;
extern NSString * const kPOPWindowAlphaValue;
extern NSString * const kPOPWindowBackgroundColor;
#endif
#if SCENEKIT_SDK_AVAILABLE
/**
Common SceneKit property names.
*/
extern NSString * const kPOPSCNNodePosition;
extern NSString * const kPOPSCNNodePositionX;
extern NSString * const kPOPSCNNodePositionY;
extern NSString * const kPOPSCNNodePositionZ;
extern NSString * const kPOPSCNNodeTranslation;
extern NSString * const kPOPSCNNodeTranslationX;
extern NSString * const kPOPSCNNodeTranslationY;
extern NSString * const kPOPSCNNodeTranslationZ;
extern NSString * const kPOPSCNNodeRotation;
extern NSString * const kPOPSCNNodeRotationX;
extern NSString * const kPOPSCNNodeRotationY;
extern NSString * const kPOPSCNNodeRotationZ;
extern NSString * const kPOPSCNNodeRotationW;
extern NSString * const kPOPSCNNodeEulerAngles;
extern NSString * const kPOPSCNNodeEulerAnglesX;
extern NSString * const kPOPSCNNodeEulerAnglesY;
extern NSString * const kPOPSCNNodeEulerAnglesZ;
extern NSString * const kPOPSCNNodeOrientation;
extern NSString * const kPOPSCNNodeOrientationX;
extern NSString * const kPOPSCNNodeOrientationY;
extern NSString * const kPOPSCNNodeOrientationZ;
extern NSString * const kPOPSCNNodeOrientationW;
extern NSString * const kPOPSCNNodeScale;
extern NSString * const kPOPSCNNodeScaleX;
extern NSString * const kPOPSCNNodeScaleY;
extern NSString * const kPOPSCNNodeScaleZ;
extern NSString * const kPOPSCNNodeScaleXY;
#endif
POP_EXTERN_C_END
/**
Copyright (c) 2014-present, Facebook, Inc.
All rights reserved.
This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree. An additional grant
of patent rights can be found in the PATENTS file in the same directory.
*/
typedef void (^POPAnimatablePropertyReadBlock)(id obj, CGFloat values[]);
typedef void (^POPAnimatablePropertyWriteBlock)(id obj, const CGFloat values[]);
/**
Copyright (c) 2014-present, Facebook, Inc.
All rights reserved.
This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree. An additional grant
of patent rights can be found in the PATENTS file in the same directory.
*/
#import <Foundation/NSObject.h>
#import <pop/POPAnimationTracer.h>
#import <pop/POPGeometry.h>
@class CAMediaTimingFunction;
/**
@abstract The abstract animation base class.
@discussion Instantiate and use one of the concrete animation subclasses.
*/
@interface POPAnimation : NSObject
/**
@abstract The name of the animation.
@discussion Optional property to help identify the animation.
*/
@property (copy, nonatomic) NSString *name;
/**
@abstract The beginTime of the animation in media time.
@discussion Defaults to 0 and starts immediately.
*/
@property (assign, nonatomic) CFTimeInterval beginTime;
/**
@abstract The animation delegate.
@discussion See {@ref POPAnimationDelegate} for details.
*/
@property (weak, nonatomic) id delegate;
/**
@abstract The animation tracer.
@discussion Returns the existing tracer, creating one if needed. Call start/stop on the tracer to toggle event collection.
*/
@property (readonly, nonatomic) POPAnimationTracer *tracer;
/**
@abstract Optional block called on animation start.
*/
@property (copy, nonatomic) void (^animationDidStartBlock)(POPAnimation *anim);
/**
@abstract Optional block called when value meets or exceeds to value.
*/
@property (copy, nonatomic) void (^animationDidReachToValueBlock)(POPAnimation *anim);
/**
@abstract Optional block called on animation completion.
*/
@property (copy, nonatomic) void (^completionBlock)(POPAnimation *anim, BOOL finished);
/**
@abstract Optional block called each frame animation is applied.
*/
@property (copy, nonatomic) void (^animationDidApplyBlock)(POPAnimation *anim);
/**
@abstract Flag indicating whether animation should be removed on completion.
@discussion Setting to NO can facilitate animation reuse. Defaults to YES.
*/
@property (assign, nonatomic) BOOL removedOnCompletion;
/**
@abstract Flag indicating whether animation is paused.
@discussion A paused animation is excluded from the list of active animations. On initial creation, defaults to YES. On animation addition, the animation is implicity unpaused. On animation completion, the animation is implicity paused including for animations with removedOnCompletion set to NO.
*/
@property (assign, nonatomic, getter = isPaused) BOOL paused;
/**
@abstract Flag indicating whether animation autoreverses.
@discussion An animation that autoreverses will have twice the duration before it is considered finished. It will animate to the toValue, stop, then animate back to the original fromValue. The delegate methods are called as follows:
1) animationDidStart: is called at the beginning, as usual, and then after each toValue is reached and the autoreverse is going to start.
2) animationDidReachToValue: is called every time the toValue is reached. The toValue is swapped with the fromValue at the end of each animation segment. This means that with autoreverses set to YES, the animationDidReachToValue: delegate method will be called a minimum of twice.
3) animationDidStop:finished: is called every time the toValue is reached, the finished argument will be NO if the autoreverse is not yet complete.
*/
@property (assign, nonatomic) BOOL autoreverses;
/**
@abstract The number of times to repeat the animation.
@discussion A repeatCount of 0 or 1 means that the animation will not repeat, just like Core Animation. A repeatCount of 2 or greater means that the animation will run that many times before stopping. The delegate methods are called as follows:
1) animationDidStart: is called at the beginning of each animation repeat.
2) animationDidReachToValue: is called every time the toValue is reached.
3) animationDidStop:finished: is called every time the toValue is reached, the finished argument will be NO if the autoreverse is not yet complete.
When combined with the autoreverses property, a singular animation is effectively twice as long.
*/
@property (assign, nonatomic) NSInteger repeatCount;
/**
@abstract Repeat the animation forever.
@discussion This property will make the animation repeat forever. The value of the repeatCount property is undefined when this property is set. The finished parameter of the delegate callback animationDidStop:finished: will always be NO.
*/
@property (assign, nonatomic) BOOL repeatForever;
@end
/**
@abstract The animation delegate.
*/
@protocol POPAnimationDelegate <NSObject>
@optional
/**
@abstract Called on animation start.
@param anim The relevant animation.
*/
- (void)pop_animationDidStart:(POPAnimation *)anim;
/**
@abstract Called when value meets or exceeds to value.
@param anim The relevant animation.
*/
- (void)pop_animationDidReachToValue:(POPAnimation *)anim;
/**
@abstract Called on animation stop.
@param anim The relevant animation.
@param finished Flag indicating finished state. Flag is true if the animation reached completion before being removed.
*/
- (void)pop_animationDidStop:(POPAnimation *)anim finished:(BOOL)finished;
/**
@abstract Called each frame animation is applied.
@param anim The relevant animation.
*/
- (void)pop_animationDidApply:(POPAnimation *)anim;
@end
@interface NSObject (POP)
/**
@abstract Add an animation to the reciver.
@param anim The animation to add.
@param key The key used to identify the animation.
@discussion The 'key' may be any string such that only one animation per unique key is added per object.
*/
- (void)pop_addAnimation:(POPAnimation *)anim forKey:(NSString *)key;
/**
@abstract Remove all animations attached to the receiver.
*/
- (void)pop_removeAllAnimations;
/**
@abstract Remove any animation attached to the receiver for 'key'.
@param key The key used to identify the animation.
*/
- (void)pop_removeAnimationForKey:(NSString *)key;
/**
@abstract Returns an array containing the keys of all animations currently attached to the receiver.
The order of keys reflects the order in which animations will be applied.
*/
- (NSArray *)pop_animationKeys;
/**
@abstract Returns any animation attached to the receiver.
@param key The key used to identify the animation.
@returns The animation currently attached, or nil if no such animation exists.
*/
- (id)pop_animationForKey:(NSString *)key;
@end
/**
* This implementation of NSCopying does not do any copying of animation's state, but only configuration.
* i.e. you cannot copy an animation and expect to apply it to a view and have the copied animation pick up where the original left off.
* Two common uses of copying animations:
* * you need to apply the same animation to multiple different views.
* * you need to absolutely ensure that the the caller of your function cannot mutate the animation once it's been passed in.
*/
@interface POPAnimation (NSCopying) <NSCopying>
@end
/**
Copyright (c) 2014-present, Facebook, Inc.
All rights reserved.
This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree. An additional grant
of patent rights can be found in the PATENTS file in the same directory.
*/
#import "POPAnimationExtras.h"
#import "POPAnimationInternal.h"
#import <objc/runtime.h>
#import "POPAction.h"
#import "POPAnimationRuntime.h"
#import "POPAnimationTracerInternal.h"
#import "POPAnimatorPrivate.h"
using namespace POP;
#pragma mark - POPAnimation
@implementation POPAnimation
@synthesize solver = _solver;
@synthesize currentValue = _currentValue;
@synthesize progressMarkers = _progressMarkers;
#pragma mark - Lifecycle
- (id)init
{
[NSException raise:NSStringFromClass([self class]) format:@"Attempting to instantiate an abstract class. Use a concrete subclass instead."];
return nil;
}
- (id)_init
{
self = [super init];
if (nil != self) {
[self _initState];
}
return self;
}
- (void)_initState
{
_state = new POPAnimationState(self);
}
- (void)dealloc
{
if (_state) {
delete _state;
_state = NULL;
};
}
#pragma mark - Properties
- (id)delegate
{
return _state->delegate;
}
- (void)setDelegate:(id)delegate
{
_state->setDelegate(delegate);
}
- (BOOL)isPaused
{
return _state->paused;
}
- (void)setPaused:(BOOL)paused
{
_state->setPaused(paused ? true : false);
}
- (NSInteger)repeatCount
{
if (_state->autoreverses) {
return _state->repeatCount / 2;
} else {
return _state->repeatCount;
}
}
- (void)setRepeatCount:(NSInteger)repeatCount
{
if (repeatCount > 0) {
if (repeatCount > NSIntegerMax / 2) {
repeatCount = NSIntegerMax / 2;
}
if (_state->autoreverses) {
_state->repeatCount = (repeatCount * 2);
} else {
_state->repeatCount = repeatCount;
}
}
}
- (BOOL)autoreverses
{
return _state->autoreverses;
}
- (void)setAutoreverses:(BOOL)autoreverses
{
_state->autoreverses = autoreverses;
if (autoreverses) {
if (_state->repeatCount == 0) {
[self setRepeatCount:1];
}
}
}
FB_PROPERTY_GET(POPAnimationState, type, POPAnimationType);
DEFINE_RW_PROPERTY_OBJ_COPY(POPAnimationState, animationDidStartBlock, setAnimationDidStartBlock:, POPAnimationDidStartBlock);
DEFINE_RW_PROPERTY_OBJ_COPY(POPAnimationState, animationDidReachToValueBlock, setAnimationDidReachToValueBlock:, POPAnimationDidReachToValueBlock);
DEFINE_RW_PROPERTY_OBJ_COPY(POPAnimationState, completionBlock, setCompletionBlock:, POPAnimationCompletionBlock);
DEFINE_RW_PROPERTY_OBJ_COPY(POPAnimationState, animationDidApplyBlock, setAnimationDidApplyBlock:, POPAnimationDidApplyBlock);
DEFINE_RW_PROPERTY_OBJ_COPY(POPAnimationState, name, setName:, NSString*);
DEFINE_RW_PROPERTY(POPAnimationState, beginTime, setBeginTime:, CFTimeInterval);
DEFINE_RW_FLAG(POPAnimationState, removedOnCompletion, removedOnCompletion, setRemovedOnCompletion:);
DEFINE_RW_FLAG(POPAnimationState, repeatForever, repeatForever, setRepeatForever:);
- (id)valueForUndefinedKey:(NSString *)key
{
return _state->dict[key];
}
- (void)setValue:(id)value forUndefinedKey:(NSString *)key
{
if (!value) {
[_state->dict removeObjectForKey:key];
} else {
if (!_state->dict)
_state->dict = [[NSMutableDictionary alloc] init];
_state->dict[key] = value;
}
}
- (POPAnimationTracer *)tracer
{
if (!_state->tracer) {
_state->tracer = [[POPAnimationTracer alloc] initWithAnimation:self];
}
return _state->tracer;
}
- (NSString *)description
{
NSMutableString *s = [NSMutableString stringWithFormat:@"<%@:%p", NSStringFromClass([self class]), self];
[self _appendDescription:s debug:NO];
[s appendString:@">"];
return s;
}
- (NSString *)debugDescription
{
NSMutableString *s = [NSMutableString stringWithFormat:@"<%@:%p", NSStringFromClass([self class]), self];
[self _appendDescription:s debug:YES];
[s appendString:@">"];
return s;
}
#pragma mark - Utility
POPAnimationState *POPAnimationGetState(POPAnimation *a)
{
return a->_state;
}
- (BOOL)_advance:(id)object currentTime:(CFTimeInterval)currentTime elapsedTime:(CFTimeInterval)elapsedTime
{
return YES;
}
- (void)_appendDescription:(NSMutableString *)s debug:(BOOL)debug
{
if (_state->name)
[s appendFormat:@"; name = %@", _state->name];
if (!self.removedOnCompletion)
[s appendFormat:@"; removedOnCompletion = %@", POPStringFromBOOL(self.removedOnCompletion)];
if (debug) {
if (_state->active)
[s appendFormat:@"; active = %@", POPStringFromBOOL(_state->active)];
if (_state->paused)
[s appendFormat:@"; paused = %@", POPStringFromBOOL(_state->paused)];
}
if (_state->beginTime) {
[s appendFormat:@"; beginTime = %f", _state->beginTime];
}
for (NSString *key in _state->dict) {
[s appendFormat:@"; %@ = %@", key, _state->dict[key]];
}
}
@end
#pragma mark - POPPropertyAnimation
#pragma mark - POPBasicAnimation
#pragma mark - POPDecayAnimation
@implementation NSObject (POP)
- (void)pop_addAnimation:(POPAnimation *)anim forKey:(NSString *)key
{
[[POPAnimator sharedAnimator] addAnimation:anim forObject:self key:key];
}
- (void)pop_removeAllAnimations
{
[[POPAnimator sharedAnimator] removeAllAnimationsForObject:self];
}
- (void)pop_removeAnimationForKey:(NSString *)key
{
[[POPAnimator sharedAnimator] removeAnimationForObject:self key:key];
}
- (NSArray *)pop_animationKeys
{
return [[POPAnimator sharedAnimator] animationKeysForObject:self];
}
- (id)pop_animationForKey:(NSString *)key
{
return [[POPAnimator sharedAnimator] animationForObject:self key:key];
}
@end
@implementation NSProxy (POP)
- (void)pop_addAnimation:(POPAnimation *)anim forKey:(NSString *)key
{
[[POPAnimator sharedAnimator] addAnimation:anim forObject:self key:key];
}
- (void)pop_removeAllAnimations
{
[[POPAnimator sharedAnimator] removeAllAnimationsForObject:self];
}
- (void)pop_removeAnimationForKey:(NSString *)key
{
[[POPAnimator sharedAnimator] removeAnimationForObject:self key:key];
}
- (NSArray *)pop_animationKeys
{
return [[POPAnimator sharedAnimator] animationKeysForObject:self];
}
- (id)pop_animationForKey:(NSString *)key
{
return [[POPAnimator sharedAnimator] animationForObject:self key:key];
}
@end
@implementation POPAnimation (NSCopying)
- (instancetype)copyWithZone:(NSZone *)zone
{
/*
* Must use [self class] instead of POPAnimation so that subclasses can call this via super.
* Even though POPAnimation and POPPropertyAnimation throw exceptions on init,
* it's safe to call it since you can only copy objects that have been successfully created.
*/
POPAnimation *copy = [[[self class] allocWithZone:zone] init];
if (copy) {
copy.name = self.name;
copy.beginTime = self.beginTime;
copy.delegate = self.delegate;
copy.animationDidStartBlock = self.animationDidStartBlock;
copy.animationDidReachToValueBlock = self.animationDidReachToValueBlock;
copy.completionBlock = self.completionBlock;
copy.animationDidApplyBlock = self.animationDidApplyBlock;
copy.removedOnCompletion = self.removedOnCompletion;
copy.autoreverses = self.autoreverses;
copy.repeatCount = self.repeatCount;
copy.repeatForever = self.repeatForever;
}
return copy;
}
@end
\ No newline at end of file
/**
Copyright (c) 2014-present, Facebook, Inc.
All rights reserved.
This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree. An additional grant
of patent rights can be found in the PATENTS file in the same directory.
*/
#import <Foundation/Foundation.h>
/**
@abstract Enumeraton of animation event types.
*/
typedef NS_ENUM(NSUInteger, POPAnimationEventType) {
kPOPAnimationEventPropertyRead = 0,
kPOPAnimationEventPropertyWrite,
kPOPAnimationEventToValueUpdate,
kPOPAnimationEventFromValueUpdate,
kPOPAnimationEventVelocityUpdate,
kPOPAnimationEventBouncinessUpdate,
kPOPAnimationEventSpeedUpdate,
kPOPAnimationEventFrictionUpdate,
kPOPAnimationEventMassUpdate,
kPOPAnimationEventTensionUpdate,
kPOPAnimationEventDidStart,
kPOPAnimationEventDidStop,
kPOPAnimationEventDidReachToValue,
kPOPAnimationEventAutoreversed
};
/**
@abstract The base animation event class.
*/
@interface POPAnimationEvent : NSObject
/**
@abstract The event type. See {@ref POPAnimationEventType} for possible values.
*/
@property (readonly, nonatomic, assign) POPAnimationEventType type;
/**
@abstract The time of event.
*/
@property (readonly, nonatomic, assign) CFTimeInterval time;
/**
@abstract Optional string describing the animation at time of event.
*/
@property (readonly, nonatomic, copy) NSString *animationDescription;
@end
/**
@abstract An animation event subclass for recording value and velocity.
*/
@interface POPAnimationValueEvent : POPAnimationEvent
/**
@abstract The value recorded.
*/
@property (readonly, nonatomic, strong) id value;
/**
@abstract The velocity recorded, if any.
*/
@property (readonly, nonatomic, strong) id velocity;
@end
/**
Copyright (c) 2014-present, Facebook, Inc.
All rights reserved.
This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree. An additional grant
of patent rights can be found in the PATENTS file in the same directory.
*/
#import "POPAnimationEvent.h"
#import "POPAnimationEventInternal.h"
static NSString *stringFromType(POPAnimationEventType aType)
{
switch (aType) {
case kPOPAnimationEventPropertyRead:
return @"read";
case kPOPAnimationEventPropertyWrite:
return @"write";
case kPOPAnimationEventToValueUpdate:
return @"toValue";
case kPOPAnimationEventFromValueUpdate:
return @"fromValue";
case kPOPAnimationEventVelocityUpdate:
return @"velocity";
case kPOPAnimationEventSpeedUpdate:
return @"speed";
case kPOPAnimationEventBouncinessUpdate:
return @"bounciness";
case kPOPAnimationEventFrictionUpdate:
return @"friction";
case kPOPAnimationEventMassUpdate:
return @"mass";
case kPOPAnimationEventTensionUpdate:
return @"tension";
case kPOPAnimationEventDidStart:
return @"didStart";
case kPOPAnimationEventDidStop:
return @"didStop";
case kPOPAnimationEventDidReachToValue:
return @"didReachToValue";
case kPOPAnimationEventAutoreversed:
return @"autoreversed";
default:
return nil;
}
}
@implementation POPAnimationEvent
@synthesize type = _type;
@synthesize time = _time;
@synthesize animationDescription = _animationDescription;
- (instancetype)initWithType:(POPAnimationEventType)aType time:(CFTimeInterval)aTime
{
self = [super init];
if (nil != self) {
_type = aType;
_time = aTime;
}
return self;
}
- (NSString *)description
{
NSMutableString *s = [NSMutableString stringWithFormat:@"<POPAnimationEvent:%f; type = %@", _time, stringFromType(_type)];
[self _appendDescription:s];
[s appendString:@">"];
return s;
}
// subclass override
- (void)_appendDescription:(NSMutableString *)s
{
if (0 != _animationDescription.length) {
[s appendFormat:@"; animation = %@", _animationDescription];
}
}
@end
@implementation POPAnimationValueEvent
@synthesize value = _value;
@synthesize velocity = _velocity;
- (instancetype)initWithType:(POPAnimationEventType)aType time:(CFTimeInterval)aTime value:(id)aValue
{
self = [self initWithType:aType time:aTime];
if (nil != self) {
_value = aValue;
}
return self;
}
- (void)_appendDescription:(NSMutableString *)s
{
[super _appendDescription:s];
if (nil != _value) {
[s appendFormat:@"; value = %@", _value];
}
if (nil != _velocity) {
[s appendFormat:@"; velocity = %@", _velocity];
}
}
@end
/**
Copyright (c) 2014-present, Facebook, Inc.
All rights reserved.
This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree. An additional grant
of patent rights can be found in the PATENTS file in the same directory.
*/
#import <Foundation/Foundation.h>
#import "POPAnimationEvent.h"
@interface POPAnimationEvent ()
/**
@abstract Default initializer.
*/
- (instancetype)initWithType:(POPAnimationEventType)type time:(CFTimeInterval)time;
/**
@abstract Readwrite redefinition of public property.
*/
@property (readwrite, nonatomic, copy) NSString *animationDescription;
@end
@interface POPAnimationValueEvent ()
/**
@abstract Default initializer.
*/
- (instancetype)initWithType:(POPAnimationEventType)type time:(CFTimeInterval)time value:(id)value;
/**
@abstract Readwrite redefinition of public property.
*/
@property (readwrite, nonatomic, strong) id velocity;
@end
/**
Copyright (c) 2014-present, Facebook, Inc.
All rights reserved.
This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree. An additional grant
of patent rights can be found in the PATENTS file in the same directory.
*/
#import <QuartzCore/CAAnimation.h>
#import <pop/POPDefines.h>
#import <pop/POPSpringAnimation.h>
/**
@abstract The current drag coefficient.
@discussion A value greater than 1.0 indicates Simulator slow-motion animations are enabled. Defaults to 1.0.
*/
extern CGFloat POPAnimationDragCoefficient(void);
@interface CAAnimation (POPAnimationExtras)
/**
@abstract Apply the current drag coefficient to animation speed.
@discussion Convenience utility to respect Simulator slow-motion animation settings.
*/
- (void)pop_applyDragCoefficient;
@end
@interface POPSpringAnimation (POPAnimationExtras)
/**
@abstract Converts from spring bounciness and speed to tension, friction and mass dynamics values.
*/
+ (void)convertBounciness:(CGFloat)bounciness speed:(CGFloat)speed toTension:(CGFloat *)outTension friction:(CGFloat *)outFriction mass:(CGFloat *)outMass;
/**
@abstract Converts from dynamics tension, friction and mass to spring bounciness and speed values.
*/
+ (void)convertTension:(CGFloat)tension friction:(CGFloat)friction toBounciness:(CGFloat *)outBounciness speed:(CGFloat *)outSpeed;
@end
/**
Copyright (c) 2014-present, Facebook, Inc.
All rights reserved.
This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree. An additional grant
of patent rights can be found in the PATENTS file in the same directory.
*/
#import "POPAnimationExtras.h"
#import "POPAnimationPrivate.h"
#if TARGET_OS_IPHONE
#import <UIKit/UIKit.h>
#endif
#if TARGET_IPHONE_SIMULATOR
UIKIT_EXTERN float UIAnimationDragCoefficient(); // UIKit private drag coefficient, use judiciously
#endif
#import "POPMath.h"
CGFloat POPAnimationDragCoefficient()
{
#if TARGET_IPHONE_SIMULATOR
return UIAnimationDragCoefficient();
#else
return 1.0;
#endif
}
@implementation CAAnimation (POPAnimationExtras)
- (void)pop_applyDragCoefficient
{
CGFloat k = POPAnimationDragCoefficient();
if (k != 0 && k != 1)
self.speed = 1 / k;
}
@end
@implementation POPSpringAnimation (POPAnimationExtras)
static const CGFloat POPBouncy3NormalizationRange = 20.0;
static const CGFloat POPBouncy3NormalizationScale = 1.7;
static const CGFloat POPBouncy3BouncinessNormalizedMin = 0.0;
static const CGFloat POPBouncy3BouncinessNormalizedMax = 0.8;
static const CGFloat POPBouncy3SpeedNormalizedMin = 0.5;
static const CGFloat POPBouncy3SpeedNormalizedMax = 200;
static const CGFloat POPBouncy3FrictionInterpolationMax = 0.01;
+ (void)convertBounciness:(CGFloat)bounciness speed:(CGFloat)speed toTension:(CGFloat *)outTension friction:(CGFloat *)outFriction mass:(CGFloat *)outMass
{
double b = POPNormalize(bounciness / POPBouncy3NormalizationScale, 0, POPBouncy3NormalizationRange);
b = POPProjectNormal(b, POPBouncy3BouncinessNormalizedMin, POPBouncy3BouncinessNormalizedMax);
double s = POPNormalize(speed / POPBouncy3NormalizationScale, 0, POPBouncy3NormalizationRange);
CGFloat tension = POPProjectNormal(s, POPBouncy3SpeedNormalizedMin, POPBouncy3SpeedNormalizedMax);
CGFloat friction = POPQuadraticOutInterpolation(b, POPBouncy3NoBounce(tension), POPBouncy3FrictionInterpolationMax);
tension = POP_ANIMATION_TENSION_FOR_QC_TENSION(tension);
friction = POP_ANIMATION_FRICTION_FOR_QC_FRICTION(friction);
if (outTension) {
*outTension = tension;
}
if (outFriction) {
*outFriction = friction;
}
if (outMass) {
*outMass = 1.0;
}
}
+ (void)convertTension:(CGFloat)tension friction:(CGFloat)friction toBounciness:(CGFloat *)outBounciness speed:(CGFloat *)outSpeed
{
// Convert to QC values, in which our calculations are done.
CGFloat qcFriction = QC_FRICTION_FOR_POP_ANIMATION_FRICTION(friction);
CGFloat qcTension = QC_TENSION_FOR_POP_ANIMATION_TENSION(tension);
// Friction is a function of bounciness and tension, according to the following:
// friction = POPQuadraticOutInterpolation(b, POPBouncy3NoBounce(tension), POPBouncy3FrictionInterpolationMax);
// Solve for bounciness, given a tension and friction.
CGFloat nobounceTension = POPBouncy3NoBounce(qcTension);
CGFloat bounciness1, bounciness2;
POPQuadraticSolve((nobounceTension - POPBouncy3FrictionInterpolationMax), // a
2 * (POPBouncy3FrictionInterpolationMax - nobounceTension), // b
(nobounceTension - qcFriction), // c
bounciness1, // x1
bounciness2); // x2
// Choose the quadratic solution within the normalized bounciness range
CGFloat projectedNormalizedBounciness = (bounciness2 < POPBouncy3BouncinessNormalizedMax) ? bounciness2 : bounciness1;
CGFloat projectedNormalizedSpeed = qcTension;
// Reverse projection + normalization
CGFloat bounciness = ((POPBouncy3NormalizationRange * POPBouncy3NormalizationScale) / (POPBouncy3BouncinessNormalizedMax - POPBouncy3BouncinessNormalizedMin)) * (projectedNormalizedBounciness - POPBouncy3BouncinessNormalizedMin);
CGFloat speed = ((POPBouncy3NormalizationRange * POPBouncy3NormalizationScale) / (POPBouncy3SpeedNormalizedMax - POPBouncy3SpeedNormalizedMin)) * (projectedNormalizedSpeed - POPBouncy3SpeedNormalizedMin);
// Write back results
if (outBounciness) {
*outBounciness = bounciness;
}
if (outSpeed) {
*outSpeed = speed;
}
}
@end
/**
Copyright (c) 2014-present, Facebook, Inc.
All rights reserved.
This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree. An additional grant
of patent rights can be found in the PATENTS file in the same directory.
*/
#import <pop/POPAnimation.h>
#define POP_ANIMATION_FRICTION_FOR_QC_FRICTION(qcFriction) (25.0 + (((qcFriction - 8.0) / 2.0) * (25.0 - 19.0)))
#define POP_ANIMATION_TENSION_FOR_QC_TENSION(qcTension) (194.0 + (((qcTension - 30.0) / 50.0) * (375.0 - 194.0)))
#define QC_FRICTION_FOR_POP_ANIMATION_FRICTION(fbFriction) (8.0 + 2.0 * ((fbFriction - 25.0)/(25.0 - 19.0)))
#define QC_TENSION_FOR_POP_ANIMATION_TENSION(fbTension) (30.0 + 50.0 * ((fbTension - 194.0)/(375.0 - 194.0)))
/**
Copyright (c) 2014-present, Facebook, Inc.
All rights reserved.
This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree. An additional grant
of patent rights can be found in the PATENTS file in the same directory.
*/
#import <objc/runtime.h>
#import <CoreGraphics/CoreGraphics.h>
#import <Foundation/Foundation.h>
#import "POPAnimatablePropertyTypes.h"
#import "POPVector.h"
enum POPValueType
{
kPOPValueUnknown = 0,
kPOPValueInteger,
kPOPValueFloat,
kPOPValuePoint,
kPOPValueSize,
kPOPValueRect,
kPOPValueEdgeInsets,
kPOPValueAffineTransform,
kPOPValueTransform,
kPOPValueRange,
kPOPValueColor,
kPOPValueSCNVector3,
kPOPValueSCNVector4,
};
using namespace POP;
/**
Returns value type based on objc type description, given list of supported value types and length.
*/
extern POPValueType POPSelectValueType(const char *objctype, const POPValueType *types, size_t length);
/**
Returns value type based on objc object, given a list of supported value types and length.
*/
extern POPValueType POPSelectValueType(id obj, const POPValueType *types, size_t length);
/**
Array of all value types.
*/
extern const POPValueType kPOPAnimatableAllTypes[12];
/**
Array of all value types supported for animation.
*/
extern const POPValueType kPOPAnimatableSupportTypes[10];
/**
Returns a string description of a value type.
*/
extern NSString *POPValueTypeToString(POPValueType t);
/**
Returns a mutable dictionary of weak pointer keys to weak pointer values.
*/
extern CFMutableDictionaryRef POPDictionaryCreateMutableWeakPointerToWeakPointer(NSUInteger capacity) CF_RETURNS_RETAINED;
/**
Returns a mutable dictionary of weak pointer keys to weak pointer values.
*/
extern CFMutableDictionaryRef POPDictionaryCreateMutableWeakPointerToStrongObject(NSUInteger capacity) CF_RETURNS_RETAINED;
/**
Box a vector.
*/
extern id POPBox(VectorConstRef vec, POPValueType type, bool force = false);
/**
Unbox a vector.
*/
extern VectorRef POPUnbox(id value, POPValueType &type, NSUInteger &count, bool validate);
/**
Read object value and return a Vector4r.
*/
NS_INLINE Vector4r read_values(POPAnimatablePropertyReadBlock read, id obj, size_t count)
{
Vector4r vec = Vector4r::Zero();
if (0 == count)
return vec;
read(obj, vec.data());
return vec;
}
NS_INLINE NSString *POPStringFromBOOL(BOOL value)
{
return value ? @"YES" : @"NO";
}
/**
Copyright (c) 2014-present, Facebook, Inc.
All rights reserved.
This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree. An additional grant
of patent rights can be found in the PATENTS file in the same directory.
*/
#import "POPAnimationRuntime.h"
#import <objc/objc.h>
#import <QuartzCore/QuartzCore.h>
#if TARGET_OS_IPHONE
#import <UIKit/UIKit.h>
#endif
#import "POPCGUtils.h"
#import "POPDefines.h"
#import "POPGeometry.h"
#import "POPVector.h"
static Boolean pointerEqual(const void *ptr1, const void *ptr2) {
return ptr1 == ptr2;
}
static CFHashCode pointerHash(const void *ptr) {
return (CFHashCode)(ptr);
}
CFMutableDictionaryRef POPDictionaryCreateMutableWeakPointerToWeakPointer(NSUInteger capacity)
{
CFDictionaryKeyCallBacks kcb = kCFTypeDictionaryKeyCallBacks;
// weak, pointer keys
kcb.retain = NULL;
kcb.release = NULL;
kcb.equal = pointerEqual;
kcb.hash = pointerHash;
CFDictionaryValueCallBacks vcb = kCFTypeDictionaryValueCallBacks;
// weak, pointer values
vcb.retain = NULL;
vcb.release = NULL;
vcb.equal = pointerEqual;
return CFDictionaryCreateMutable(NULL, capacity, &kcb, &vcb);
}
CFMutableDictionaryRef POPDictionaryCreateMutableWeakPointerToStrongObject(NSUInteger capacity)
{
CFDictionaryKeyCallBacks kcb = kCFTypeDictionaryKeyCallBacks;
// weak, pointer keys
kcb.retain = NULL;
kcb.release = NULL;
kcb.equal = pointerEqual;
kcb.hash = pointerHash;
// strong, object values
CFDictionaryValueCallBacks vcb = kCFTypeDictionaryValueCallBacks;
return CFDictionaryCreateMutable(NULL, capacity, &kcb, &vcb);
}
static bool FBCompareTypeEncoding(const char *objctype, POPValueType type)
{
switch (type)
{
case kPOPValueFloat:
return (strcmp(objctype, @encode(float)) == 0
|| strcmp(objctype, @encode(double)) == 0
);
case kPOPValuePoint:
return (strcmp(objctype, @encode(CGPoint)) == 0
#if !TARGET_OS_IPHONE
|| strcmp(objctype, @encode(NSPoint)) == 0
#endif
);
case kPOPValueSize:
return (strcmp(objctype, @encode(CGSize)) == 0
#if !TARGET_OS_IPHONE
|| strcmp(objctype, @encode(NSSize)) == 0
#endif
);
case kPOPValueRect:
return (strcmp(objctype, @encode(CGRect)) == 0
#if !TARGET_OS_IPHONE
|| strcmp(objctype, @encode(NSRect)) == 0
#endif
);
case kPOPValueEdgeInsets:
#if TARGET_OS_IPHONE
return strcmp(objctype, @encode(UIEdgeInsets)) == 0;
#else
return false;
#endif
case kPOPValueAffineTransform:
return strcmp(objctype, @encode(CGAffineTransform)) == 0;
case kPOPValueTransform:
return strcmp(objctype, @encode(CATransform3D)) == 0;
case kPOPValueRange:
return strcmp(objctype, @encode(CFRange)) == 0
|| strcmp(objctype, @encode (NSRange)) == 0;
case kPOPValueInteger:
return (strcmp(objctype, @encode(int)) == 0
|| strcmp(objctype, @encode(unsigned int)) == 0
|| strcmp(objctype, @encode(short)) == 0
|| strcmp(objctype, @encode(unsigned short)) == 0
|| strcmp(objctype, @encode(long)) == 0
|| strcmp(objctype, @encode(unsigned long)) == 0
|| strcmp(objctype, @encode(long long)) == 0
|| strcmp(objctype, @encode(unsigned long long)) == 0
);
case kPOPValueSCNVector3:
#if SCENEKIT_SDK_AVAILABLE
return strcmp(objctype, @encode(SCNVector3)) == 0;
#else
return false;
#endif
case kPOPValueSCNVector4:
#if SCENEKIT_SDK_AVAILABLE
return strcmp(objctype, @encode(SCNVector4)) == 0;
#else
return false;
#endif
default:
return false;
}
}
POPValueType POPSelectValueType(const char *objctype, const POPValueType *types, size_t length)
{
if (NULL != objctype) {
for (size_t idx = 0; idx < length; idx++) {
if (FBCompareTypeEncoding(objctype, types[idx]))
return types[idx];
}
}
return kPOPValueUnknown;
}
POPValueType POPSelectValueType(id obj, const POPValueType *types, size_t length)
{
if ([obj isKindOfClass:[NSValue class]]) {
return POPSelectValueType([obj objCType], types, length);
} else if (NULL != POPCGColorWithColor(obj)) {
return kPOPValueColor;
}
return kPOPValueUnknown;
}
const POPValueType kPOPAnimatableAllTypes[12] = {kPOPValueInteger, kPOPValueFloat, kPOPValuePoint, kPOPValueSize, kPOPValueRect, kPOPValueEdgeInsets, kPOPValueAffineTransform, kPOPValueTransform, kPOPValueRange, kPOPValueColor, kPOPValueSCNVector3, kPOPValueSCNVector4};
const POPValueType kPOPAnimatableSupportTypes[10] = {kPOPValueInteger, kPOPValueFloat, kPOPValuePoint, kPOPValueSize, kPOPValueRect, kPOPValueEdgeInsets, kPOPValueColor, kPOPValueSCNVector3, kPOPValueSCNVector4};
NSString *POPValueTypeToString(POPValueType t)
{
switch (t) {
case kPOPValueUnknown:
return @"unknown";
case kPOPValueInteger:
return @"int";
case kPOPValueFloat:
return @"CGFloat";
case kPOPValuePoint:
return @"CGPoint";
case kPOPValueSize:
return @"CGSize";
case kPOPValueRect:
return @"CGRect";
case kPOPValueEdgeInsets:
return @"UIEdgeInsets";
case kPOPValueAffineTransform:
return @"CGAffineTransform";
case kPOPValueTransform:
return @"CATransform3D";
case kPOPValueRange:
return @"CFRange";
case kPOPValueColor:
return @"CGColorRef";
case kPOPValueSCNVector3:
return @"SCNVector3";
case kPOPValueSCNVector4:
return @"SCNVector4";
default:
return nil;
}
}
id POPBox(VectorConstRef vec, POPValueType type, bool force)
{
if (NULL == vec)
return nil;
switch (type) {
case kPOPValueInteger:
case kPOPValueFloat:
return @(vec->data()[0]);
break;
case kPOPValuePoint:
return [NSValue valueWithCGPoint:vec->cg_point()];
break;
case kPOPValueSize:
return [NSValue valueWithCGSize:vec->cg_size()];
break;
case kPOPValueRect:
return [NSValue valueWithCGRect:vec->cg_rect()];
break;
#if TARGET_OS_IPHONE
case kPOPValueEdgeInsets:
return [NSValue valueWithUIEdgeInsets:vec->ui_edge_insets()];
break;
#endif
case kPOPValueColor: {
return (__bridge_transfer id)vec->cg_color();
break;
}
#if SCENEKIT_SDK_AVAILABLE
case kPOPValueSCNVector3: {
return [NSValue valueWithSCNVector3:vec->scn_vector3()];
break;
}
case kPOPValueSCNVector4: {
return [NSValue valueWithSCNVector4:vec->scn_vector4()];
break;
}
#endif
default:
return force ? [NSValue valueWithCGPoint:vec->cg_point()] : nil;
break;
}
}
static VectorRef vectorize(id value, POPValueType type)
{
Vector *vec = NULL;
switch (type) {
case kPOPValueInteger:
case kPOPValueFloat:
#if CGFLOAT_IS_DOUBLE
vec = Vector::new_cg_float([value doubleValue]);
#else
vec = Vector::new_cg_float([value floatValue]);
#endif
break;
case kPOPValuePoint:
vec = Vector::new_cg_point([value CGPointValue]);
break;
case kPOPValueSize:
vec = Vector::new_cg_size([value CGSizeValue]);
break;
case kPOPValueRect:
vec = Vector::new_cg_rect([value CGRectValue]);
break;
#if TARGET_OS_IPHONE
case kPOPValueEdgeInsets:
vec = Vector::new_ui_edge_insets([value UIEdgeInsetsValue]);
break;
#endif
case kPOPValueAffineTransform:
vec = Vector::new_cg_affine_transform([value CGAffineTransformValue]);
break;
case kPOPValueColor:
vec = Vector::new_cg_color(POPCGColorWithColor(value));
break;
#if SCENEKIT_SDK_AVAILABLE
case kPOPValueSCNVector3:
vec = Vector::new_scn_vector3([value SCNVector3Value]);
break;
case kPOPValueSCNVector4:
vec = Vector::new_scn_vector4([value SCNVector4Value]);
break;
#endif
default:
break;
}
return VectorRef(vec);
}
VectorRef POPUnbox(id value, POPValueType &animationType, NSUInteger &count, bool validate)
{
if (nil == value) {
count = 0;
return VectorRef(NULL);
}
// determine type of value
POPValueType valueType = POPSelectValueType(value, kPOPAnimatableSupportTypes, POP_ARRAY_COUNT(kPOPAnimatableSupportTypes));
// handle unknown types
if (kPOPValueUnknown == valueType) {
NSString *valueDesc = [[value class] description];
[NSException raise:@"Unsuported value" format:@"Animating %@ values is not supported", valueDesc];
}
// vectorize
VectorRef vec = vectorize(value, valueType);
if (kPOPValueUnknown == animationType || 0 == count) {
// update animation type based on value type
animationType = valueType;
if (NULL != vec) {
count = vec->size();
}
} else if (validate) {
// allow for mismatched types, so long as vector size matches
if (count != vec->size()) {
[NSException raise:@"Invalid value" format:@"%@ should be of type %@", value, POPValueTypeToString(animationType)];
}
}
return vec;
}
/**
Copyright (c) 2014-present, Facebook, Inc.
All rights reserved.
This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree. An additional grant
of patent rights can be found in the PATENTS file in the same directory.
*/
#import <Foundation/Foundation.h>
#import <pop/POPAnimationEvent.h>
@class POPAnimation;
/**
@abstract Tracer of animation events to facilitate unit testing & debugging.
*/
@interface POPAnimationTracer : NSObject
/**
@abstract Start recording events.
*/
- (void)start;
/**
@abstract Stop recording events.
*/
- (void)stop;
/**
@abstract Resets any recoded events. Continues recording events if already started.
*/
- (void)reset;
/**
@abstract Property representing all recorded events.
@discussion Events are returned in order of occurrence.
*/
@property (nonatomic, assign, readonly) NSArray *allEvents;
/**
@abstract Property representing all recorded write events for convenience.
@discussion Events are returned in order of occurrence.
*/
@property (nonatomic, assign, readonly) NSArray *writeEvents;
/**
@abstract Queries for events of specified type.
@param type The type of event to return.
@returns An array of events of specified type in order of occurrence.
*/
- (NSArray *)eventsWithType:(POPAnimationEventType)type;
/**
@abstract Property indicating whether tracer should automatically log events and reset collection on animation completion.
*/
@property (nonatomic, assign) BOOL shouldLogAndResetOnCompletion;
@end
/**
Copyright (c) 2014-present, Facebook, Inc.
All rights reserved.
This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree. An additional grant
of patent rights can be found in the PATENTS file in the same directory.
*/
#import "POPAnimationTracer.h"
#import <QuartzCore/QuartzCore.h>
#import "POPAnimationEventInternal.h"
#import "POPAnimationInternal.h"
#import "POPSpringAnimation.h"
@implementation POPAnimationTracer
{
__weak POPAnimation *_animation;
POPAnimationState *_animationState;
NSMutableArray *_events;
BOOL _animationHasVelocity;
}
@synthesize shouldLogAndResetOnCompletion = _shouldLogAndResetOnCompletion;
static POPAnimationEvent *create_event(POPAnimationTracer *self, POPAnimationEventType type, id value = nil, bool recordAnimation = false)
{
bool useLocalTime = 0 != self->_animationState->startTime;
CFTimeInterval time = useLocalTime
? self->_animationState->lastTime - self->_animationState->startTime
: self->_animationState->lastTime;
POPAnimationEvent *event;
__strong POPAnimation* animation = self->_animation;
if (!value) {
event = [[POPAnimationEvent alloc] initWithType:type time:time];
} else {
event = [[POPAnimationValueEvent alloc] initWithType:type time:time value:value];
if (self->_animationHasVelocity) {
[(POPAnimationValueEvent *)event setVelocity:[(POPSpringAnimation *)animation velocity]];
}
}
if (recordAnimation) {
event.animationDescription = [animation description];
}
return event;
}
- (id)initWithAnimation:(POPAnimation *)anAnim
{
self = [super init];
if (nil != self) {
_animation = anAnim;
_animationState = POPAnimationGetState(anAnim);
_events = [[NSMutableArray alloc] initWithCapacity:50];
_animationHasVelocity = [anAnim respondsToSelector:@selector(velocity)];
}
return self;
}
- (void)readPropertyValue:(id)aValue
{
POPAnimationEvent *event = create_event(self, kPOPAnimationEventPropertyRead, aValue);
[_events addObject:event];
}
- (void)writePropertyValue:(id)aValue
{
POPAnimationEvent *event = create_event(self, kPOPAnimationEventPropertyWrite, aValue);
[_events addObject:event];
}
- (void)updateToValue:(id)aValue
{
POPAnimationEvent *event = create_event(self, kPOPAnimationEventToValueUpdate, aValue);
[_events addObject:event];
}
- (void)updateFromValue:(id)aValue
{
POPAnimationEvent *event = create_event(self, kPOPAnimationEventFromValueUpdate, aValue);
[_events addObject:event];
}
- (void)updateVelocity:(id)aValue
{
POPAnimationEvent *event = create_event(self, kPOPAnimationEventVelocityUpdate, aValue);
[_events addObject:event];
}
- (void)updateSpeed:(float)aFloat
{
POPAnimationEvent *event = create_event(self, kPOPAnimationEventSpeedUpdate, @(aFloat));
[_events addObject:event];
}
- (void)updateBounciness:(float)aFloat
{
POPAnimationEvent *event = create_event(self, kPOPAnimationEventBouncinessUpdate, @(aFloat));
[_events addObject:event];
}
- (void)updateFriction:(float)aFloat
{
POPAnimationEvent *event = create_event(self, kPOPAnimationEventFrictionUpdate, @(aFloat));
[_events addObject:event];
}
- (void)updateMass:(float)aFloat
{
POPAnimationEvent *event = create_event(self, kPOPAnimationEventMassUpdate, @(aFloat));
[_events addObject:event];
}
- (void)updateTension:(float)aFloat
{
POPAnimationEvent *event = create_event(self, kPOPAnimationEventTensionUpdate, @(aFloat));
[_events addObject:event];
}
- (void)didStart
{
POPAnimationEvent *event = create_event(self, kPOPAnimationEventDidStart, nil, true);
[_events addObject:event];
}
- (void)didStop:(BOOL)finished
{
POPAnimationEvent *event = create_event(self, kPOPAnimationEventDidStop, @(finished), true);
[_events addObject:event];
if (_shouldLogAndResetOnCompletion) {
NSLog(@"events:%@", self.allEvents);
[self reset];
}
}
- (void)didReachToValue:(id)aValue
{
POPAnimationEvent *event = create_event(self, kPOPAnimationEventDidReachToValue, aValue);
[_events addObject:event];
}
- (void)autoreversed
{
POPAnimationEvent *event = create_event(self, kPOPAnimationEventAutoreversed);
[_events addObject:event];
}
- (void)start
{
POPAnimationState *s = POPAnimationGetState(_animation);
s->tracing = true;
}
- (void)stop
{
POPAnimationState *s = POPAnimationGetState(_animation);
s->tracing = false;
}
- (void)reset
{
[_events removeAllObjects];
}
- (NSArray *)allEvents
{
return [_events copy];
}
- (NSArray *)writeEvents
{
return [self eventsWithType:kPOPAnimationEventPropertyWrite];
}
- (NSArray *)eventsWithType:(POPAnimationEventType)aType
{
NSMutableArray *array = [NSMutableArray array];
for (POPAnimationEvent *event in _events) {
if (aType == event.type) {
[array addObject:event];
}
}
return array;
}
@end
/**
Copyright (c) 2014-present, Facebook, Inc.
All rights reserved.
This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree. An additional grant
of patent rights can be found in the PATENTS file in the same directory.
*/
#import <Foundation/Foundation.h>
#import <pop/POPAnimationTracer.h>
@interface POPAnimationTracer (Internal)
/**
@abstract Designated initializer. Pass the animation being traced.
*/
- (instancetype)initWithAnimation:(POPAnimation *)anAnim;
/**
@abstract Records read value.
*/
- (void)readPropertyValue:(id)aValue;
/**
@abstract Records write value.
*/
- (void)writePropertyValue:(id)aValue;
/**
Records to value update.
*/
- (void)updateToValue:(id)aValue;
/**
@abstract Records from value update.
*/
- (void)updateFromValue:(id)aValue;
/**
@abstract Records from value update.
*/
- (void)updateVelocity:(id)aValue;
/**
@abstract Records bounciness update.
*/
- (void)updateBounciness:(float)aFloat;
/**
@abstract Records speed update.
*/
- (void)updateSpeed:(float)aFloat;
/**
@abstract Records friction update.
*/
- (void)updateFriction:(float)aFloat;
/**
@abstract Records mass update.
*/
- (void)updateMass:(float)aFloat;
/**
@abstract Records tension update.
*/
- (void)updateTension:(float)aFloat;
/**
@abstract Records did add.
*/
- (void)didAdd;
/**
@abstract Records did start.
*/
- (void)didStart;
/**
@abstract Records did stop.
*/
- (void)didStop:(BOOL)finished;
/**
@abstract Records did reach to value.
*/
- (void)didReachToValue:(id)aValue;
/**
@abstract Records when an autoreverse animation takes place.
*/
- (void)autoreversed;
@end
/**
Copyright (c) 2014-present, Facebook, Inc.
All rights reserved.
This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree. An additional grant
of patent rights can be found in the PATENTS file in the same directory.
*/
#import <Foundation/Foundation.h>
@protocol POPAnimatorDelegate;
/**
@abstract The animator class renders animations.
*/
@interface POPAnimator : NSObject
/**
@abstract The shared animator instance.
@discussion Consumers should generally use the shared instance in lieu of creating new instances.
*/
+ (instancetype)sharedAnimator;
#if !TARGET_OS_IPHONE
/**
@abstract Allows to select display to bind. Returns nil if failed to create the display link.
*/
- (instancetype)initWithDisplayID:(CGDirectDisplayID)displayID;
#endif
/**
@abstract The optional animator delegate.
*/
@property (weak, nonatomic) id<POPAnimatorDelegate> delegate;
/**
@abstract Retrieves the nominal refresh period of a display link. Returns zero if unavailable.
*/
@property (readonly, nonatomic) CFTimeInterval refreshPeriod;
@end
/**
@abstract The animator delegate.
*/
@protocol POPAnimatorDelegate <NSObject>
/**
@abstract Called on each frame before animation application.
*/
- (void)animatorWillAnimate:(POPAnimator *)animator;
/**
@abstract Called on each frame after animation application.
*/
- (void)animatorDidAnimate:(POPAnimator *)animator;
@end
/**
Copyright (c) 2014-present, Facebook, Inc.
All rights reserved.
This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree. An additional grant
of patent rights can be found in the PATENTS file in the same directory.
*/
#import <pop/POPAnimator.h>
@class POPAnimation;
@protocol POPAnimatorObserving <NSObject>
@required
/**
@abstract Called on each observer after animator has advanced. Core Animation actions are disabled by default.
*/
- (void)animatorDidAnimate:(POPAnimator *)animator;
@end
@interface POPAnimator ()
#if !TARGET_OS_IPHONE
/**
Determines whether or not to use a high priority background thread for animation updates. Using a background thread can result in faster, more responsive updates, but may be less compatible. Defaults to YES.
*/
+ (BOOL)disableBackgroundThread;
+ (void)setDisableBackgroundThread:(BOOL)flag;
/**
Determines the frequency (Hz) of the timer used when no display is available. Defaults to 60Hz.
*/
+ (uint64_t)displayTimerFrequency;
+ (void)setDisplayTimerFrequency:(uint64_t)frequency;
#endif
/**
Used for externally driven animator instances.
*/
@property (assign, nonatomic) BOOL disableDisplayLink;
/**
Time used when starting animations. Defaults to 0 meaning current media time is used. Exposed for unit testing.
*/
@property (assign, nonatomic) CFTimeInterval beginTime;
/**
Exposed for unit testing.
*/
- (void)renderTime:(CFTimeInterval)time;
/**
Funnel methods for category additions.
*/
- (void)addAnimation:(POPAnimation *)anim forObject:(id)obj key:(NSString *)key;
- (void)removeAllAnimationsForObject:(id)obj;
- (void)removeAnimationForObject:(id)obj key:(NSString *)key;
- (NSArray *)animationKeysForObject:(id)obj;
- (POPAnimation *)animationForObject:(id)obj key:(NSString *)key;
/**
@abstract Add an animator observer. Observer will be notified of each subsequent animator advance until removal.
*/
- (void)addObserver:(id<POPAnimatorObserving>)observer;
/**
@abstract Remove an animator observer.
*/
- (void)removeObserver:(id<POPAnimatorObserving>)observer;
@end
/**
Copyright (c) 2014-present, Facebook, Inc.
All rights reserved.
This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree. An additional grant
of patent rights can be found in the PATENTS file in the same directory.
*/
#import <pop/POPPropertyAnimation.h>
/**
@abstract A concrete basic animation class.
@discussion Animation is achieved through interpolation.
*/
@interface POPBasicAnimation : POPPropertyAnimation
/**
@abstract The designated initializer.
@returns An instance of a basic animation.
*/
+ (instancetype)animation;
/**
@abstract Convenience initializer that returns an animation with animatable property of name.
@param name The name of the animatable property.
@returns An instance of a basic animation configured with specified animatable property.
*/
+ (instancetype)animationWithPropertyNamed:(NSString *)name;
/**
@abstract Convenience constructor.
@returns Returns a basic animation with kCAMediaTimingFunctionDefault timing function.
*/
+ (instancetype)defaultAnimation;
/**
@abstract Convenience constructor.
@returns Returns a basic animation with kCAMediaTimingFunctionLinear timing function.
*/
+ (instancetype)linearAnimation;
/**
@abstract Convenience constructor.
@returns Returns a basic animation with kCAMediaTimingFunctionEaseIn timing function.
*/
+ (instancetype)easeInAnimation;
/**
@abstract Convenience constructor.
@returns Returns a basic animation with kCAMediaTimingFunctionEaseOut timing function.
*/
+ (instancetype)easeOutAnimation;
/**
@abstract Convenience constructor.
@returns Returns a basic animation with kCAMediaTimingFunctionEaseInEaseOut timing function.
*/
+ (instancetype)easeInEaseOutAnimation;
/**
@abstract The duration in seconds. Defaults to 0.4.
*/
@property (assign, nonatomic) CFTimeInterval duration;
/**
@abstract A timing function defining the pacing of the animation. Defaults to nil indicating pacing according to kCAMediaTimingFunctionDefault.
*/
@property (strong, nonatomic) CAMediaTimingFunction *timingFunction;
@end
/**
Copyright (c) 2014-present, Facebook, Inc.
All rights reserved.
This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree. An additional grant
of patent rights can be found in the PATENTS file in the same directory.
*/
#import "POPBasicAnimationInternal.h"
@implementation POPBasicAnimation
#undef __state
#define __state ((POPBasicAnimationState *)_state)
#pragma mark - Lifecycle
+ (instancetype)animation
{
return [[self alloc] init];
}
+ (instancetype)animationWithPropertyNamed:(NSString *)aName
{
POPBasicAnimation *anim = [self animation];
anim.property = [POPAnimatableProperty propertyWithName:aName];
return anim;
}
- (void)_initState
{
_state = new POPBasicAnimationState(self);
}
+ (instancetype)linearAnimation
{
POPBasicAnimation *anim = [self animation];
anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
return anim;
}
+ (instancetype)easeInAnimation
{
POPBasicAnimation *anim = [self animation];
anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
return anim;
}
+ (instancetype)easeOutAnimation
{
POPBasicAnimation *anim = [self animation];
anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
return anim;
}
+ (instancetype)easeInEaseOutAnimation
{
POPBasicAnimation *anim = [self animation];
anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
return anim;
}
+ (instancetype)defaultAnimation
{
POPBasicAnimation *anim = [self animation];
anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault];
return anim;
}
- (id)init
{
return [self _init];
}
#pragma mark - Properties
DEFINE_RW_PROPERTY(POPBasicAnimationState, duration, setDuration:, CFTimeInterval);
DEFINE_RW_PROPERTY_OBJ(POPBasicAnimationState, timingFunction, setTimingFunction:, CAMediaTimingFunction*, __state->updatedTimingFunction(););
#pragma mark - Utility
- (void)_appendDescription:(NSMutableString *)s debug:(BOOL)debug
{
[super _appendDescription:s debug:debug];
if (__state->duration)
[s appendFormat:@"; duration = %f", __state->duration];
}
@end
@implementation POPBasicAnimation (NSCopying)
- (instancetype)copyWithZone:(NSZone *)zone {
POPBasicAnimation *copy = [super copyWithZone:zone];
if (copy) {
copy.duration = self.duration;
copy.timingFunction = self.timingFunction; // not a 'copy', but timing functions are publicly immutable.
}
return copy;
}
@end
\ No newline at end of file
/**
Copyright (c) 2014-present, Facebook, Inc.
All rights reserved.
This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree. An additional grant
of patent rights can be found in the PATENTS file in the same directory.
*/
#import "POPBasicAnimation.h"
#import "POPPropertyAnimationInternal.h"
// default animation duration
static CGFloat const kPOPAnimationDurationDefault = 0.4;
// progress threshold for computing done
static CGFloat const kPOPProgressThreshold = 1e-6;
static void interpolate(POPValueType valueType, NSUInteger count, const CGFloat *fromVec, const CGFloat *toVec, CGFloat *outVec, CGFloat p)
{
switch (valueType) {
case kPOPValueInteger:
case kPOPValueFloat:
case kPOPValuePoint:
case kPOPValueSize:
case kPOPValueRect:
case kPOPValueEdgeInsets:
case kPOPValueColor:
POPInterpolateVector(count, outVec, fromVec, toVec, p);
break;
default:
NSCAssert(false, @"unhandled type %d", valueType);
break;
}
}
struct _POPBasicAnimationState : _POPPropertyAnimationState
{
CAMediaTimingFunction *timingFunction;
double timingControlPoints[4];
CFTimeInterval duration;
CFTimeInterval timeProgress;
_POPBasicAnimationState(id __unsafe_unretained anim) : _POPPropertyAnimationState(anim),
timingFunction(nil),
timingControlPoints{0.},
duration(kPOPAnimationDurationDefault),
timeProgress(0.)
{
type = kPOPAnimationBasic;
}
bool isDone() {
if (_POPPropertyAnimationState::isDone()) {
return true;
}
return timeProgress + kPOPProgressThreshold >= 1.;
}
void updatedTimingFunction()
{
float vec[4] = {0.};
[timingFunction getControlPointAtIndex:1 values:&vec[0]];
[timingFunction getControlPointAtIndex:2 values:&vec[2]];
for (NSUInteger idx = 0; idx < POP_ARRAY_COUNT(vec); idx++) {
timingControlPoints[idx] = vec[idx];
}
}
bool advance(CFTimeInterval time, CFTimeInterval dt, id obj) {
// default timing function
if (!timingFunction) {
((POPBasicAnimation *)self).timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault];
}
// solve for normalized time, aka progress [0, 1]
CGFloat p = 1.0f;
if (duration > 0.0f) {
// cap local time to duration
CFTimeInterval t = MIN(time - startTime, duration) / duration;
p = POPTimingFunctionSolve(timingControlPoints, t, SOLVE_EPS(duration));
timeProgress = t;
} else {
timeProgress = 1.;
}
// interpolate and advance
interpolate(valueType, valueCount, fromVec->data(), toVec->data(), currentVec->data(), p);
progress = p;
clampCurrentValue();
return true;
}
};
typedef struct _POPBasicAnimationState POPBasicAnimationState;
/**
Copyright (c) 2014-present, Facebook, Inc.
All rights reserved.
This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree. An additional grant
of patent rights can be found in the PATENTS file in the same directory.
*/
#import <CoreGraphics/CoreGraphics.h>
#if TARGET_OS_IPHONE
#import <UIKit/UIKit.h>
#else
#import <AppKit/AppKit.h>
#endif
#import "POPDefines.h"
#if SCENEKIT_SDK_AVAILABLE
#import <SceneKit/SceneKit.h>
#endif
POP_EXTERN_C_BEGIN
NS_INLINE CGPoint values_to_point(const CGFloat values[])
{
return CGPointMake(values[0], values[1]);
}
NS_INLINE CGSize values_to_size(const CGFloat values[])
{
return CGSizeMake(values[0], values[1]);
}
NS_INLINE CGRect values_to_rect(const CGFloat values[])
{
return CGRectMake(values[0], values[1], values[2], values[3]);
}
#if SCENEKIT_SDK_AVAILABLE
NS_INLINE SCNVector3 values_to_vec3(const CGFloat values[])
{
return SCNVector3Make(values[0], values[1], values[2]);
}
NS_INLINE SCNVector4 values_to_vec4(const CGFloat values[])
{
return SCNVector4Make(values[0], values[1], values[2], values[3]);
}
#endif
#if TARGET_OS_IPHONE
NS_INLINE UIEdgeInsets values_to_edge_insets(const CGFloat values[])
{
return UIEdgeInsetsMake(values[0], values[1], values[2], values[3]);
}
#endif
NS_INLINE void values_from_point(CGFloat values[], CGPoint p)
{
values[0] = p.x;
values[1] = p.y;
}
NS_INLINE void values_from_size(CGFloat values[], CGSize s)
{
values[0] = s.width;
values[1] = s.height;
}
NS_INLINE void values_from_rect(CGFloat values[], CGRect r)
{
values[0] = r.origin.x;
values[1] = r.origin.y;
values[2] = r.size.width;
values[3] = r.size.height;
}
#if SCENEKIT_SDK_AVAILABLE
NS_INLINE void values_from_vec3(CGFloat values[], SCNVector3 v)
{
values[0] = v.x;
values[1] = v.y;
values[2] = v.z;
}
NS_INLINE void values_from_vec4(CGFloat values[], SCNVector4 v)
{
values[0] = v.x;
values[1] = v.y;
values[2] = v.z;
values[3] = v.w;
}
#endif
#if TARGET_OS_IPHONE
NS_INLINE void values_from_edge_insets(CGFloat values[], UIEdgeInsets i)
{
values[0] = i.top;
values[1] = i.left;
values[2] = i.bottom;
values[3] = i.right;
}
#endif
/**
Takes a CGColorRef and converts it into RGBA components, if necessary.
*/
extern void POPCGColorGetRGBAComponents(CGColorRef color, CGFloat components[]);
/**
Takes RGBA components and returns a CGColorRef.
*/
extern CGColorRef POPCGColorRGBACreate(const CGFloat components[]) CF_RETURNS_RETAINED;
/**
Takes a color reference and returns a CGColor.
*/
extern CGColorRef POPCGColorWithColor(id color) CF_RETURNS_NOT_RETAINED;
#if TARGET_OS_IPHONE
/**
Takes a UIColor and converts it into RGBA components, if necessary.
*/
extern void POPUIColorGetRGBAComponents(UIColor *color, CGFloat components[]);
/**
Takes RGBA components and returns a UIColor.
*/
extern UIColor *POPUIColorRGBACreate(const CGFloat components[]) NS_RETURNS_RETAINED;
#else
/**
Takes a NSColor and converts it into RGBA components, if necessary.
*/
extern void POPNSColorGetRGBAComponents(NSColor *color, CGFloat components[]);
/**
Takes RGBA components and returns a NSColor.
*/
extern NSColor *POPNSColorRGBACreate(const CGFloat components[]) NS_RETURNS_RETAINED;
#endif
POP_EXTERN_C_END
/**
Copyright (c) 2014-present, Facebook, Inc.
All rights reserved.
This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree. An additional grant
of patent rights can be found in the PATENTS file in the same directory.
*/
#import "POPCGUtils.h"
#import <objc/runtime.h>
void POPCGColorGetRGBAComponents(CGColorRef color, CGFloat components[])
{
if (color) {
const CGFloat *colors = CGColorGetComponents(color);
size_t count = CGColorGetNumberOfComponents(color);
if (4 == count) {
// RGB colorspace
components[0] = colors[0];
components[1] = colors[1];
components[2] = colors[2];
components[3] = colors[3];
} else if (2 == count) {
// Grey colorspace
components[0] = components[1] = components[2] = colors[0];
components[3] = colors[1];
} else {
// Use CI to convert
CIColor *ciColor = [CIColor colorWithCGColor:color];
components[0] = ciColor.red;
components[1] = ciColor.green;
components[2] = ciColor.blue;
components[3] = ciColor.alpha;
}
} else {
memset(components, 0, 4 * sizeof(components[0]));
}
}
CGColorRef POPCGColorRGBACreate(const CGFloat components[])
{
#if TARGET_OS_IPHONE
CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
CGColorRef color = CGColorCreate(space, components);
CGColorSpaceRelease(space);
return color;
#else
return CGColorCreateGenericRGB(components[0], components[1], components[2], components[3]);
#endif
}
CGColorRef POPCGColorWithColor(id color)
{
if (CFGetTypeID((__bridge CFTypeRef)color) == CGColorGetTypeID()) {
return ((__bridge CGColorRef)color);
}
#if TARGET_OS_IPHONE
else if ([color isKindOfClass:[UIColor class]]) {
return [color CGColor];
}
#else
else if ([color isKindOfClass:[NSColor class]]) {
// -[NSColor CGColor] is only supported since OSX 10.8+
if ([color respondsToSelector:@selector(CGColor)]) {
return [color CGColor];
}
/*
* Otherwise create a CGColorRef manually.
*
* The original accessor is (or would be) declared as:
* @property(readonly) CGColorRef CGColor;
* - (CGColorRef)CGColor NS_RETURNS_INNER_POINTER CF_RETURNS_NOT_RETAINED;
*
* (Please note that OSX' accessor is atomic, while iOS' isn't.)
*
* The access to the NSColor object must thus be synchronized
* and the CGColorRef be stored as an associated object,
* to return a reference which doesn't need to be released manually.
*/
@synchronized(color) {
static const void* key = &key;
CGColorRef colorRef = (__bridge CGColorRef)objc_getAssociatedObject(color, key);
if (!colorRef) {
size_t numberOfComponents = [(NSColor *)color numberOfComponents];
CGFloat components[numberOfComponents];
CGColorSpaceRef colorSpace = [[(NSColor *)color colorSpace] CGColorSpace];
[color getComponents:components];
colorRef = CGColorCreate(colorSpace, components);
objc_setAssociatedObject(color, key, (__bridge id)colorRef, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
CGColorRelease(colorRef);
}
return colorRef;
}
}
#endif
return nil;
}
#if TARGET_OS_IPHONE
void POPUIColorGetRGBAComponents(UIColor *color, CGFloat components[])
{
return POPCGColorGetRGBAComponents(POPCGColorWithColor(color), components);
}
UIColor *POPUIColorRGBACreate(const CGFloat components[])
{
CGColorRef colorRef = POPCGColorRGBACreate(components);
UIColor *color = [[UIColor alloc] initWithCGColor:colorRef];
CGColorRelease(colorRef);
return color;
}
#else
void POPNSColorGetRGBAComponents(NSColor *color, CGFloat components[])
{
return POPCGColorGetRGBAComponents(POPCGColorWithColor(color), components);
}
NSColor *POPNSColorRGBACreate(const CGFloat components[])
{
CGColorRef colorRef = POPCGColorRGBACreate(components);
NSColor *color = nil;
if (colorRef) {
if ([NSColor respondsToSelector:@selector(colorWithCGColor:)]) {
color = [NSColor colorWithCGColor:colorRef];
} else {
color = [NSColor colorWithCIColor:[CIColor colorWithCGColor:colorRef]];
}
CGColorRelease(colorRef);
}
return color;
}
#endif
/**
Copyright (c) 2014-present, Facebook, Inc.
All rights reserved.
This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree. An additional grant
of patent rights can be found in the PATENTS file in the same directory.
*/
#import <pop/POPAnimation.h>
@class POPCustomAnimation;
/**
@abstract POPCustomAnimationBlock is the callback block of a custom animation.
@discussion This block will be executed for each animation frame and should update the property or properties being animated based on current timing.
@param target The object being animated. Reference the passed in target to help avoid retain loops.
@param animation The custom animation instance. Use to determine the current and elapsed time since last callback. Reference the passed in animation to help avoid retain loops.
@return Flag indicating whether the animation should continue animating. Return NO to indicate animation is done.
*/
typedef BOOL (^POPCustomAnimationBlock)(id target, POPCustomAnimation *animation);
/**
@abstract POPCustomAnimation is a concrete animation subclass for custom animations.
*/
@interface POPCustomAnimation : POPAnimation
/**
@abstract Creates and returns an initialized custom animation instance.
@discussion This is the designated initializer.
@param block The custom animation callback block. See {@ref POPCustomAnimationBlock}.
@return The initialized custom animation instance.
*/
+ (instancetype)animationWithBlock:(POPCustomAnimationBlock)block;
/**
@abstract The current animation time at time of callback.
*/
@property (readonly, nonatomic) CFTimeInterval currentTime;
/**
@abstract The elapsed animation time since last callback.
*/
@property (readonly, nonatomic) CFTimeInterval elapsedTime;
@end
/**
Copyright (c) 2014-present, Facebook, Inc.
All rights reserved.
This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree. An additional grant
of patent rights can be found in the PATENTS file in the same directory.
*/
#import "POPAnimationInternal.h"
#import "POPCustomAnimation.h"
@interface POPCustomAnimation ()
@property (nonatomic, copy) POPCustomAnimationBlock animate;
@end
@implementation POPCustomAnimation
@synthesize currentTime = _currentTime;
@synthesize elapsedTime = _elapsedTime;
@synthesize animate = _animate;
+ (instancetype)animationWithBlock:(BOOL(^)(id target, POPCustomAnimation *))block
{
POPCustomAnimation *b = [[self alloc] _init];
b.animate = block;
return b;
}
- (id)_init
{
self = [super _init];
if (nil != self) {
_state->type = kPOPAnimationCustom;
}
return self;
}
- (CFTimeInterval)beginTime
{
POPAnimationState *s = POPAnimationGetState(self);
return s->startTime > 0 ? s->startTime : s->beginTime;
}
- (BOOL)_advance:(id)object currentTime:(CFTimeInterval)currentTime elapsedTime:(CFTimeInterval)elapsedTime
{
_currentTime = currentTime;
_elapsedTime = elapsedTime;
return _animate(object, self);
}
- (void)_appendDescription:(NSMutableString *)s debug:(BOOL)debug
{
[s appendFormat:@"; elapsedTime = %f; currentTime = %f;", _elapsedTime, _currentTime];
}
@end
/**
* Note that only the animate block is copied, but not the current/elapsed times
*/
@implementation POPCustomAnimation (NSCopying)
- (instancetype)copyWithZone:(NSZone *)zone {
POPCustomAnimation *copy = [super copyWithZone:zone];
if (copy) {
copy.animate = self.animate;
}
return copy;
}
@end
\ No newline at end of file
/**
Copyright (c) 2014-present, Facebook, Inc.
All rights reserved.
This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree. An additional grant
of patent rights can be found in the PATENTS file in the same directory.
*/
#import <pop/POPPropertyAnimation.h>
/**
@abstract A concrete decay animation class.
@discussion Animation is achieved through gradual decay of animation value.
*/
@interface POPDecayAnimation : POPPropertyAnimation
/**
@abstract The designated initializer.
@returns An instance of a decay animation.
*/
+ (instancetype)animation;
/**
@abstract Convenience initializer that returns an animation with animatable property of name.
@param name The name of the animatable property.
@returns An instance of a decay animation configured with specified animatable property.
*/
+ (instancetype)animationWithPropertyNamed:(NSString *)name;
/**
@abstract The current velocity value.
@discussion Set before animation start to account for initial velocity. Expressed in change of value units per second. The only POPValueTypes supported for velocity are: kPOPValuePoint, kPOPValueInteger, kPOPValueFloat, kPOPValueRect, and kPOPValueSize.
*/
@property (copy, nonatomic) id velocity;
/**
@abstract The original velocity value.
@discussion Since the velocity property is modified as the animation progresses, this property stores the original, passed in velocity to support autoreverse and repeatCount.
*/
@property (copy, nonatomic, readonly) id originalVelocity;
/**
@abstract The deceleration factor.
@discussion Values specifies should be in the range [0, 1]. Lower values results in faster deceleration. Defaults to 0.998.
*/
@property (assign, nonatomic) CGFloat deceleration;
/**
@abstract The expected duration.
@discussion Derived based on input velocity and deceleration values.
*/
@property (readonly, assign, nonatomic) CFTimeInterval duration;
/**
The to value is derived based on input velocity and deceleration.
*/
- (void)setToValue:(id)toValue NS_UNAVAILABLE;
/**
@abstract The reversed velocity.
@discussion The reversed velocity based on the originalVelocity when the animation was set up.
*/
- (id)reversedVelocity;
@end
/**
Copyright (c) 2014-present, Facebook, Inc.
All rights reserved.
This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree. An additional grant
of patent rights can be found in the PATENTS file in the same directory.
*/
#import "POPDecayAnimationInternal.h"
#if TARGET_OS_IPHONE
#import <UIKit/UIKit.h>
#endif
const POPValueType supportedVelocityTypes[6] = { kPOPValuePoint, kPOPValueInteger, kPOPValueFloat, kPOPValueRect, kPOPValueSize, kPOPValueEdgeInsets };
@implementation POPDecayAnimation
#pragma mark - Lifecycle
#undef __state
#define __state ((POPDecayAnimationState *)_state)
+ (instancetype)animation
{
return [[self alloc] init];
}
+ (instancetype)animationWithPropertyNamed:(NSString *)aName
{
POPDecayAnimation *anim = [self animation];
anim.property = [POPAnimatableProperty propertyWithName:aName];
return anim;
}
- (id)init
{
return [self _init];
}
- (void)_initState
{
_state = new POPDecayAnimationState(self);
}
#pragma mark - Properties
DEFINE_RW_PROPERTY(POPDecayAnimationState, deceleration, setDeceleration:, CGFloat, __state->toVec = NULL;);
@dynamic velocity;
- (id)toValue
{
[self _ensureComputedProperties];
return POPBox(__state->toVec, __state->valueType);
}
- (CFTimeInterval)duration
{
[self _ensureComputedProperties];
return __state->duration;
}
- (void)setFromValue:(id)fromValue
{
super.fromValue = fromValue;
[self _invalidateComputedProperties];
}
- (void)setToValue:(id)aValue
{
// no-op
NSLog(@"ignoring to value on decay animation %@", self);
}
- (id)reversedVelocity
{
id reversedVelocity = nil;
POPValueType velocityType = POPSelectValueType(self.originalVelocity, supportedVelocityTypes, POP_ARRAY_COUNT(supportedVelocityTypes));
if (velocityType == kPOPValueFloat) {
#if CGFLOAT_IS_DOUBLE
CGFloat originalVelocityFloat = [(NSNumber *)self.originalVelocity doubleValue];
#else
CGFloat originalVelocityFloat = [(NSNumber *)self.originalVelocity floatValue];
#endif
NSNumber *negativeOriginalVelocityNumber = @(-originalVelocityFloat);
reversedVelocity = negativeOriginalVelocityNumber;
} else if (velocityType == kPOPValueInteger) {
NSInteger originalVelocityInteger = [(NSNumber *)self.originalVelocity integerValue];
NSNumber *negativeOriginalVelocityNumber = @(-originalVelocityInteger);
reversedVelocity = negativeOriginalVelocityNumber;
} else if (velocityType == kPOPValuePoint) {
CGPoint originalVelocityPoint = [self.originalVelocity CGPointValue];
CGPoint negativeOriginalVelocityPoint = CGPointMake(-originalVelocityPoint.x, -originalVelocityPoint.y);
reversedVelocity = [NSValue valueWithCGPoint:negativeOriginalVelocityPoint];
} else if (velocityType == kPOPValueRect) {
CGRect originalVelocityRect = [self.originalVelocity CGRectValue];
CGRect negativeOriginalVelocityRect = CGRectMake(-originalVelocityRect.origin.x, -originalVelocityRect.origin.y, -originalVelocityRect.size.width, -originalVelocityRect.size.height);
reversedVelocity = [NSValue valueWithCGRect:negativeOriginalVelocityRect];
} else if (velocityType == kPOPValueSize) {
CGSize originalVelocitySize = [self.originalVelocity CGSizeValue];
CGSize negativeOriginalVelocitySize = CGSizeMake(-originalVelocitySize.width, -originalVelocitySize.height);
reversedVelocity = [NSValue valueWithCGSize:negativeOriginalVelocitySize];
} else if (velocityType == kPOPValueEdgeInsets) {
#if TARGET_OS_IPHONE
UIEdgeInsets originalVelocityInsets = [self.originalVelocity UIEdgeInsetsValue];
UIEdgeInsets negativeOriginalVelocityInsets = UIEdgeInsetsMake(-originalVelocityInsets.top, -originalVelocityInsets.left, -originalVelocityInsets.bottom, -originalVelocityInsets.right);
reversedVelocity = [NSValue valueWithUIEdgeInsets:negativeOriginalVelocityInsets];
#endif
}
return reversedVelocity;
}
- (id)originalVelocity
{
return POPBox(__state->originalVelocityVec, __state->valueType);
}
- (id)velocity
{
return POPBox(__state->velocityVec, __state->valueType);
}
- (void)setVelocity:(id)aValue
{
POPValueType valueType = POPSelectValueType(aValue, supportedVelocityTypes, POP_ARRAY_COUNT(supportedVelocityTypes));
if (valueType != kPOPValueUnknown) {
VectorRef vec = POPUnbox(aValue, __state->valueType, __state->valueCount, YES);
VectorRef origVec = POPUnbox(aValue, __state->valueType, __state->valueCount, YES);
if (!vec_equal(vec, __state->velocityVec)) {
__state->velocityVec = vec;
__state->originalVelocityVec = origVec;
if (__state->tracing) {
[__state->tracer updateVelocity:aValue];
}
[self _invalidateComputedProperties];
// automatically unpause active animations
if (__state->active && __state->paused) {
__state->fromVec = NULL;
__state->setPaused(false);
}
}
} else {
__state->velocityVec = NULL;
NSLog(@"Invalid velocity value for the decayAnimation: %@", aValue);
}
}
#pragma mark - Utility
- (void)_ensureComputedProperties
{
if (NULL == __state->toVec) {
__state->computeDuration();
__state->computeToValue();
}
}
- (void)_invalidateComputedProperties
{
__state->toVec = NULL;
__state->duration = 0;
}
- (void)_appendDescription:(NSMutableString *)s debug:(BOOL)debug
{
[super _appendDescription:s debug:debug];
if (0 != self.duration) {
[s appendFormat:@"; duration = %f", self.duration];
}
if (__state->deceleration) {
[s appendFormat:@"; deceleration = %f", __state->deceleration];
}
}
@end
@implementation POPDecayAnimation (NSCopying)
- (instancetype)copyWithZone:(NSZone *)zone {
POPDecayAnimation *copy = [super copyWithZone:zone];
if (copy) {
// Set the velocity to the animation's original velocity, not its current.
copy.velocity = self.originalVelocity;
copy.deceleration = self.deceleration;
}
return copy;
}
@end
\ No newline at end of file
/**
Copyright (c) 2014-present, Facebook, Inc.
All rights reserved.
This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree. An additional grant
of patent rights can be found in the PATENTS file in the same directory.
*/
#import "POPDecayAnimation.h"
#import <cmath>
#import "POPPropertyAnimationInternal.h"
// minimal velocity factor before decay animation is considered complete, in units / s
static CGFloat kPOPAnimationDecayMinimalVelocityFactor = 5.;
// default decay animation deceleration
static CGFloat kPOPAnimationDecayDecelerationDefault = 0.998;
static void decay_position(CGFloat *x, CGFloat *v, NSUInteger count, CFTimeInterval dt, CGFloat deceleration)
{
dt *= 1000;
// v0 = v / 1000
// v = v0 * powf(deceleration, dt);
// v = v * 1000;
// x0 = x;
// x = x0 + v0 * deceleration * (1 - powf(deceleration, dt)) / (1 - deceleration)
float v0[count];
float kv = powf(deceleration, dt);
float kx = deceleration * (1 - kv) / (1 - deceleration);
for (NSUInteger idx = 0; idx < count; idx++) {
v0[idx] = v[idx] / 1000.;
v[idx] = v0[idx] * kv * 1000.;
x[idx] = x[idx] + v0[idx] * kx;
}
}
struct _POPDecayAnimationState : _POPPropertyAnimationState
{
double deceleration;
CFTimeInterval duration;
_POPDecayAnimationState(id __unsafe_unretained anim) :
_POPPropertyAnimationState(anim),
deceleration(kPOPAnimationDecayDecelerationDefault),
duration(0)
{
type = kPOPAnimationDecay;
}
bool isDone() {
if (_POPPropertyAnimationState::isDone()) {
return true;
}
CGFloat f = dynamicsThreshold * kPOPAnimationDecayMinimalVelocityFactor;
const CGFloat *velocityValues = vec_data(velocityVec);
for (NSUInteger idx = 0; idx < valueCount; idx++) {
if (std::abs((velocityValues[idx])) >= f)
return false;
}
return true;
}
void computeDuration() {
// compute duration till threshold velocity
Vector4r scaledVelocity = vector4(velocityVec) / 1000.;
double k = dynamicsThreshold * kPOPAnimationDecayMinimalVelocityFactor / 1000.;
double vx = k / scaledVelocity.x;
double vy = k / scaledVelocity.y;
double vz = k / scaledVelocity.z;
double vw = k / scaledVelocity.w;
double d = log(deceleration) * 1000.;
duration = MAX(MAX(MAX(log(fabs(vx)) / d, log(fabs(vy)) / d), log(fabs(vz)) / d), log(fabs(vw)) / d);
// ensure velocity threshold is exceeded
if (std::isnan(duration) || duration < 0) {
duration = 0;
}
}
void computeToValue() {
// to value assuming final velocity as a factor of dynamics threshold
// derived from v' = v * d^dt used in decay_position
// to compute the to value with maximal dt, p' = p + (v * d) / (1 - d)
VectorRef fromValue = NULL != currentVec ? currentVec : fromVec;
if (!fromValue) {
return;
}
// ensure duration is computed
if (0 == duration) {
computeDuration();
}
// compute to value
VectorRef toValue(Vector::new_vector(fromValue.get()));
Vector4r velocity = velocityVec->vector4r();
decay_position(toValue->data(), velocity.data(), valueCount, duration, deceleration);
toVec = toValue;
}
bool advance(CFTimeInterval time, CFTimeInterval dt, id obj) {
// advance past not yet initialized animations
if (NULL == currentVec) {
return false;
}
decay_position(currentVec->data(), velocityVec->data(), valueCount, dt, deceleration);
// clamp to compute end value; avoid possibility of decaying past
clampCurrentValue(kPOPAnimationClampEnd | clampMode);
return true;
}
};
typedef struct _POPDecayAnimationState POPDecayAnimationState;
/**
Copyright (c) 2014-present, Facebook, Inc.
All rights reserved.
This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree. An additional grant
of patent rights can be found in the PATENTS file in the same directory.
*/
#ifndef POP_POPDefines_h
#define POP_POPDefines_h
#import <Availability.h>
#ifdef __cplusplus
# define POP_EXTERN_C_BEGIN extern "C" {
# define POP_EXTERN_C_END }
#else
# define POP_EXTERN_C_BEGIN
# define POP_EXTERN_C_END
#endif
#define POP_ARRAY_COUNT(x) sizeof(x) / sizeof(x[0])
#if defined (__cplusplus) && defined (__GNUC__)
# define POP_NOTHROW __attribute__ ((nothrow))
#else
# define POP_NOTHROW
#endif
#if defined(POP_USE_SCENEKIT)
# if TARGET_OS_MAC || TARGET_OS_IPHONE
# define SCENEKIT_SDK_AVAILABLE 1
# endif
#endif
#endif
/**
Copyright (c) 2014-present, Facebook, Inc.
All rights reserved.
This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree. An additional grant
of patent rights can be found in the PATENTS file in the same directory.
*/
#import <Foundation/Foundation.h>
#if TARGET_OS_IPHONE
#import <UIKit/UIGeometry.h>
#endif
#if !TARGET_OS_IPHONE
/** NSValue extensions to support animatable types. */
@interface NSValue (POP)
/**
@abstract Creates an NSValue given a CGPoint.
*/
+ (NSValue *)valueWithCGPoint:(CGPoint)point;
/**
@abstract Creates an NSValue given a CGSize.
*/
+ (NSValue *)valueWithCGSize:(CGSize)size;
/**
@abstract Creates an NSValue given a CGRect.
*/
+ (NSValue *)valueWithCGRect:(CGRect)rect;
/**
@abstract Creates an NSValue given a CFRange.
*/
+ (NSValue *)valueWithCFRange:(CFRange)range;
/**
@abstract Creates an NSValue given a CGAffineTransform.
*/
+ (NSValue *)valueWithCGAffineTransform:(CGAffineTransform)transform;
/**
@abstract Returns the underlying CGPoint value.
*/
- (CGPoint)CGPointValue;
/**
@abstract Returns the underlying CGSize value.
*/
- (CGSize)CGSizeValue;
/**
@abstract Returns the underlying CGRect value.
*/
- (CGRect)CGRectValue;
/**
@abstract Returns the underlying CFRange value.
*/
- (CFRange)CFRangeValue;
/**
@abstract Returns the underlying CGAffineTransform value.
*/
- (CGAffineTransform)CGAffineTransformValue;
@end
#endif
/**
Copyright (c) 2014-present, Facebook, Inc.
All rights reserved.
This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree. An additional grant
of patent rights can be found in the PATENTS file in the same directory.
*/
#import "POPGeometry.h"
#if !TARGET_OS_IPHONE
@implementation NSValue (POP)
+ (NSValue *)valueWithCGPoint:(CGPoint)point {
return [NSValue valueWithBytes:&point objCType:@encode(CGPoint)];
}
+ (NSValue *)valueWithCGSize:(CGSize)size {
return [NSValue valueWithBytes:&size objCType:@encode(CGSize)];
}
+ (NSValue *)valueWithCGRect:(CGRect)rect {
return [NSValue valueWithBytes:&rect objCType:@encode(CGRect)];
}
+ (NSValue *)valueWithCFRange:(CFRange)range {
return [NSValue valueWithBytes:&range objCType:@encode(CFRange)];
}
+ (NSValue *)valueWithCGAffineTransform:(CGAffineTransform)transform
{
return [NSValue valueWithBytes:&transform objCType:@encode(CGAffineTransform)];
}
- (CGPoint)CGPointValue {
CGPoint result;
[self getValue:&result];
return result;
}
- (CGSize)CGSizeValue {
CGSize result;
[self getValue:&result];
return result;
}
- (CGRect)CGRectValue {
CGRect result;
[self getValue:&result];
return result;
}
- (CFRange)CFRangeValue {
CFRange result;
[self getValue:&result];
return result;
}
- (CGAffineTransform)CGAffineTransformValue {
CGAffineTransform result;
[self getValue:&result];
return result;
}
@end
#endif
#if TARGET_OS_IPHONE
#import "POPDefines.h"
#if SCENEKIT_SDK_AVAILABLE
#import <SceneKit/SceneKit.h>
/**
Dirty hacks because iOS is weird and decided to define both SCNVector3's and SCNVector4's objCType as "t". However @encode(SCNVector3) and @encode(SCNVector4) both return the proper definition ("{SCNVector3=fff}" and "{SCNVector4=ffff}" respectively)
[[NSValue valueWithSCNVector3:SCNVector3Make(0.0, 0.0, 0.0)] objcType] returns "t", whereas it should return "{SCNVector3=fff}".
*flips table*
*/
@implementation NSValue (SceneKitFixes)
+ (NSValue *)valueWithSCNVector3:(SCNVector3)vec3 {
return [NSValue valueWithBytes:&vec3 objCType:@encode(SCNVector3)];
}
+ (NSValue *)valueWithSCNVector4:(SCNVector4)vec4 {
return [NSValue valueWithBytes:&vec4 objCType:@encode(SCNVector4)];
}
@end
#endif
#endif
/**
Copyright (c) 2014-present, Facebook, Inc.
All rights reserved.
This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree. An additional grant
of patent rights can be found in the PATENTS file in the same directory.
*/
#import <QuartzCore/QuartzCore.h>
#import <pop/POPDefines.h>
POP_EXTERN_C_BEGIN
#pragma mark - Scale
/**
@abstract Returns layer scale factor for the x axis.
*/
extern CGFloat POPLayerGetScaleX(CALayer *l);
/**
@abstract Set layer scale factor for the x axis.
*/
extern void POPLayerSetScaleX(CALayer *l, CGFloat f);
/**
@abstract Returns layer scale factor for the y axis.
*/
extern CGFloat POPLayerGetScaleY(CALayer *l);
/**
@abstract Set layer scale factor for the y axis.
*/
extern void POPLayerSetScaleY(CALayer *l, CGFloat f);
/**
@abstract Returns layer scale factor for the z axis.
*/
extern CGFloat POPLayerGetScaleZ(CALayer *l);
/**
@abstract Set layer scale factor for the z axis.
*/
extern void POPLayerSetScaleZ(CALayer *l, CGFloat f);
/**
@abstract Returns layer scale factors for x and y access as point.
*/
extern CGPoint POPLayerGetScaleXY(CALayer *l);
/**
@abstract Sets layer x and y scale factors given point.
*/
extern void POPLayerSetScaleXY(CALayer *l, CGPoint p);
#pragma mark - Translation
/**
@abstract Returns layer translation factor for the x axis.
*/
extern CGFloat POPLayerGetTranslationX(CALayer *l);
/**
@abstract Set layer translation factor for the x axis.
*/
extern void POPLayerSetTranslationX(CALayer *l, CGFloat f);
/**
@abstract Returns layer translation factor for the y axis.
*/
extern CGFloat POPLayerGetTranslationY(CALayer *l);
/**
@abstract Set layer translation factor for the y axis.
*/
extern void POPLayerSetTranslationY(CALayer *l, CGFloat f);
/**
@abstract Returns layer translation factor for the z axis.
*/
extern CGFloat POPLayerGetTranslationZ(CALayer *l);
/**
@abstract Set layer translation factor for the z axis.
*/
extern void POPLayerSetTranslationZ(CALayer *l, CGFloat f);
/**
@abstract Returns layer translation factors for x and y access as point.
*/
extern CGPoint POPLayerGetTranslationXY(CALayer *l);
/**
@abstract Sets layer x and y translation factors given point.
*/
extern void POPLayerSetTranslationXY(CALayer *l, CGPoint p);
#pragma mark - Rotation
/**
@abstract Returns layer rotation, in radians, in the X axis.
*/
extern CGFloat POPLayerGetRotationX(CALayer *l);
/**
@abstract Sets layer rotation, in radians, in the X axis.
*/
extern void POPLayerSetRotationX(CALayer *l, CGFloat f);
/**
@abstract Returns layer rotation, in radians, in the Y axis.
*/
extern CGFloat POPLayerGetRotationY(CALayer *l);
/**
@abstract Sets layer rotation, in radians, in the Y axis.
*/
extern void POPLayerSetRotationY(CALayer *l, CGFloat f);
/**
@abstract Returns layer rotation, in radians, in the Z axis.
*/
extern CGFloat POPLayerGetRotationZ(CALayer *l);
/**
@abstract Sets layer rotation, in radians, in the Z axis.
*/
extern void POPLayerSetRotationZ(CALayer *l, CGFloat f);
/**
@abstract Returns layer rotation, in radians, in the Z axis.
*/
extern CGFloat POPLayerGetRotation(CALayer *l);
/**
@abstract Sets layer rotation, in radians, in the Z axis.
*/
extern void POPLayerSetRotation(CALayer *l, CGFloat f);
#pragma mark - Sublayer Scale
/**
@abstract Returns sublayer scale factors for x and y access as point.
*/
extern CGPoint POPLayerGetSubScaleXY(CALayer *l);
/**
@abstract Sets sublayer x and y scale factors given point.
*/
extern void POPLayerSetSubScaleXY(CALayer *l, CGPoint p);
#pragma mark - Sublayer Translation
/**
@abstract Returns sublayer translation factor for the x axis.
*/
extern CGFloat POPLayerGetSubTranslationX(CALayer *l);
/**
@abstract Set sublayer translation factor for the x axis.
*/
extern void POPLayerSetSubTranslationX(CALayer *l, CGFloat f);
/**
@abstract Returns sublayer translation factor for the y axis.
*/
extern CGFloat POPLayerGetSubTranslationY(CALayer *l);
/**
@abstract Set sublayer translation factor for the y axis.
*/
extern void POPLayerSetSubTranslationY(CALayer *l, CGFloat f);
/**
@abstract Returns sublayer translation factor for the z axis.
*/
extern CGFloat POPLayerGetSubTranslationZ(CALayer *l);
/**
@abstract Set sublayer translation factor for the z axis.
*/
extern void POPLayerSetSubTranslationZ(CALayer *l, CGFloat f);
/**
@abstract Returns sublayer translation factors for x and y access as point.
*/
extern CGPoint POPLayerGetSubTranslationXY(CALayer *l);
/**
@abstract Sets sublayer x and y translation factors given point.
*/
extern void POPLayerSetSubTranslationXY(CALayer *l, CGPoint p);
POP_EXTERN_C_END
/**
Copyright (c) 2014-present, Facebook, Inc.
All rights reserved.
This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree. An additional grant
of patent rights can be found in the PATENTS file in the same directory.
*/
#import "POPLayerExtras.h"
#include "TransformationMatrix.h"
using namespace WebCore;
#define DECOMPOSE_TRANSFORM(L) \
TransformationMatrix _m(L.transform); \
TransformationMatrix::DecomposedType _d; \
_m.decompose(_d);
#define RECOMPOSE_TRANSFORM(L) \
_m.recompose(_d); \
L.transform = _m.transform3d();
#define RECOMPOSE_ROT_TRANSFORM(L) \
_m.recompose(_d, true); \
L.transform = _m.transform3d();
#define DECOMPOSE_SUBLAYER_TRANSFORM(L) \
TransformationMatrix _m(L.sublayerTransform); \
TransformationMatrix::DecomposedType _d; \
_m.decompose(_d);
#define RECOMPOSE_SUBLAYER_TRANSFORM(L) \
_m.recompose(_d); \
L.sublayerTransform = _m.transform3d();
#pragma mark - Scale
NS_INLINE void ensureNonZeroValue(CGFloat &f)
{
if (f == 0) {
f = 1e-6;
}
}
NS_INLINE void ensureNonZeroValue(CGPoint &p)
{
if (p.x == 0 && p.y == 0) {
p.x = 1e-6;
p.y = 1e-6;
}
}
CGFloat POPLayerGetScaleX(CALayer *l)
{
DECOMPOSE_TRANSFORM(l);
return _d.scaleX;
}
void POPLayerSetScaleX(CALayer *l, CGFloat f)
{
ensureNonZeroValue(f);
DECOMPOSE_TRANSFORM(l);
_d.scaleX = f;
RECOMPOSE_TRANSFORM(l);
}
CGFloat POPLayerGetScaleY(CALayer *l)
{
DECOMPOSE_TRANSFORM(l);
return _d.scaleY;
}
void POPLayerSetScaleY(CALayer *l, CGFloat f)
{
ensureNonZeroValue(f);
DECOMPOSE_TRANSFORM(l);
_d.scaleY = f;
RECOMPOSE_TRANSFORM(l);
}
CGFloat POPLayerGetScaleZ(CALayer *l)
{
DECOMPOSE_TRANSFORM(l);
return _d.scaleZ;
}
void POPLayerSetScaleZ(CALayer *l, CGFloat f)
{
ensureNonZeroValue(f);
DECOMPOSE_TRANSFORM(l);
_d.scaleZ = f;
RECOMPOSE_TRANSFORM(l);
}
CGPoint POPLayerGetScaleXY(CALayer *l)
{
DECOMPOSE_TRANSFORM(l);
return CGPointMake(_d.scaleX, _d.scaleY);
}
void POPLayerSetScaleXY(CALayer *l, CGPoint p)
{
ensureNonZeroValue(p);
DECOMPOSE_TRANSFORM(l);
_d.scaleX = p.x;
_d.scaleY = p.y;
RECOMPOSE_TRANSFORM(l);
}
#pragma mark - Translation
CGFloat POPLayerGetTranslationX(CALayer *l)
{
DECOMPOSE_TRANSFORM(l);
return _d.translateX;
}
void POPLayerSetTranslationX(CALayer *l, CGFloat f)
{
DECOMPOSE_TRANSFORM(l);
_d.translateX = f;
RECOMPOSE_TRANSFORM(l);
}
CGFloat POPLayerGetTranslationY(CALayer *l)
{
DECOMPOSE_TRANSFORM(l);
return _d.translateY;
}
void POPLayerSetTranslationY(CALayer *l, CGFloat f)
{
DECOMPOSE_TRANSFORM(l);
_d.translateY = f;
RECOMPOSE_TRANSFORM(l);
}
CGFloat POPLayerGetTranslationZ(CALayer *l)
{
DECOMPOSE_TRANSFORM(l);
return _d.translateZ;
}
void POPLayerSetTranslationZ(CALayer *l, CGFloat f)
{
DECOMPOSE_TRANSFORM(l);
_d.translateZ = f;
RECOMPOSE_TRANSFORM(l);
}
CGPoint POPLayerGetTranslationXY(CALayer *l)
{
DECOMPOSE_TRANSFORM(l);
return CGPointMake(_d.translateX, _d.translateY);
}
void POPLayerSetTranslationXY(CALayer *l, CGPoint p)
{
DECOMPOSE_TRANSFORM(l);
_d.translateX = p.x;
_d.translateY = p.y;
RECOMPOSE_TRANSFORM(l);
}
#pragma mark - Rotation
CGFloat POPLayerGetRotationX(CALayer *l)
{
DECOMPOSE_TRANSFORM(l);
return _d.rotateX;
}
void POPLayerSetRotationX(CALayer *l, CGFloat f)
{
DECOMPOSE_TRANSFORM(l);
_d.rotateX = f;
RECOMPOSE_ROT_TRANSFORM(l);
}
CGFloat POPLayerGetRotationY(CALayer *l)
{
DECOMPOSE_TRANSFORM(l);
return _d.rotateY;
}
void POPLayerSetRotationY(CALayer *l, CGFloat f)
{
DECOMPOSE_TRANSFORM(l);
_d.rotateY = f;
RECOMPOSE_ROT_TRANSFORM(l);
}
CGFloat POPLayerGetRotationZ(CALayer *l)
{
DECOMPOSE_TRANSFORM(l);
return _d.rotateZ;
}
void POPLayerSetRotationZ(CALayer *l, CGFloat f)
{
DECOMPOSE_TRANSFORM(l);
_d.rotateZ = f;
RECOMPOSE_ROT_TRANSFORM(l);
}
CGFloat POPLayerGetRotation(CALayer *l)
{
return POPLayerGetRotationZ(l);
}
void POPLayerSetRotation(CALayer *l, CGFloat f)
{
POPLayerSetRotationZ(l, f);
}
#pragma mark - Sublayer Scale
CGPoint POPLayerGetSubScaleXY(CALayer *l)
{
DECOMPOSE_SUBLAYER_TRANSFORM(l);
return CGPointMake(_d.scaleX, _d.scaleY);
}
void POPLayerSetSubScaleXY(CALayer *l, CGPoint p)
{
ensureNonZeroValue(p);
DECOMPOSE_SUBLAYER_TRANSFORM(l);
_d.scaleX = p.x;
_d.scaleY = p.y;
RECOMPOSE_SUBLAYER_TRANSFORM(l);
}
#pragma mark - Sublayer Translation
extern CGFloat POPLayerGetSubTranslationX(CALayer *l)
{
DECOMPOSE_SUBLAYER_TRANSFORM(l);
return _d.translateX;
}
extern void POPLayerSetSubTranslationX(CALayer *l, CGFloat f)
{
DECOMPOSE_SUBLAYER_TRANSFORM(l);
_d.translateX = f;
RECOMPOSE_SUBLAYER_TRANSFORM(l);
}
extern CGFloat POPLayerGetSubTranslationY(CALayer *l)
{
DECOMPOSE_SUBLAYER_TRANSFORM(l);
return _d.translateY;
}
extern void POPLayerSetSubTranslationY(CALayer *l, CGFloat f)
{
DECOMPOSE_SUBLAYER_TRANSFORM(l);
_d.translateY = f;
RECOMPOSE_SUBLAYER_TRANSFORM(l);
}
extern CGFloat POPLayerGetSubTranslationZ(CALayer *l)
{
DECOMPOSE_SUBLAYER_TRANSFORM(l);
return _d.translateZ;
}
extern void POPLayerSetSubTranslationZ(CALayer *l, CGFloat f)
{
DECOMPOSE_SUBLAYER_TRANSFORM(l);
_d.translateZ = f;
RECOMPOSE_SUBLAYER_TRANSFORM(l);
}
extern CGPoint POPLayerGetSubTranslationXY(CALayer *l)
{
DECOMPOSE_SUBLAYER_TRANSFORM(l);
return CGPointMake(_d.translateX, _d.translateY);
}
extern void POPLayerSetSubTranslationXY(CALayer *l, CGPoint p)
{
DECOMPOSE_SUBLAYER_TRANSFORM(l);
_d.translateX = p.x;
_d.translateY = p.y;
RECOMPOSE_SUBLAYER_TRANSFORM(l);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment