├── .gitignore
├── LTStackView.xcodeproj
├── project.pbxproj
└── project.xcworkspace
│ └── contents.xcworkspacedata
├── LTStackView
├── AppDelegate.h
├── AppDelegate.m
├── Base.lproj
│ └── Main.storyboard
├── Images.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ └── LaunchImage.launchimage
│ │ └── Contents.json
├── LTStackView-Info.plist
├── LTStackView-Prefix.pch
├── LTStackView.h
├── LTStackView.m
├── ViewController.h
├── ViewController.m
├── en.lproj
│ └── InfoPlist.strings
├── main.m
└── pop
│ ├── POP.h
│ ├── POPAction.h
│ ├── POPAnimatableProperty.h
│ ├── POPAnimatableProperty.mm
│ ├── POPAnimation.h
│ ├── POPAnimation.mm
│ ├── POPAnimationEvent.h
│ ├── POPAnimationEvent.mm
│ ├── POPAnimationEventInternal.h
│ ├── POPAnimationExtras.h
│ ├── POPAnimationExtras.mm
│ ├── POPAnimationInternal.h
│ ├── POPAnimationPrivate.h
│ ├── POPAnimationRuntime.h
│ ├── POPAnimationRuntime.mm
│ ├── POPAnimationTracer.h
│ ├── POPAnimationTracer.mm
│ ├── POPAnimationTracerInternal.h
│ ├── POPAnimator.h
│ ├── POPAnimator.mm
│ ├── POPAnimatorPrivate.h
│ ├── POPBasicAnimation.h
│ ├── POPBasicAnimation.mm
│ ├── POPBasicAnimationInternal.h
│ ├── POPCGUtils.h
│ ├── POPCGUtils.mm
│ ├── POPCustomAnimation.h
│ ├── POPCustomAnimation.mm
│ ├── POPDecayAnimation.h
│ ├── POPDecayAnimation.mm
│ ├── POPDecayAnimationInternal.h
│ ├── POPDefines.h
│ ├── POPGeometry.h
│ ├── POPGeometry.mm
│ ├── POPLayerExtras.h
│ ├── POPLayerExtras.mm
│ ├── POPMath.h
│ ├── POPMath.mm
│ ├── POPPropertyAnimation.h
│ ├── POPPropertyAnimation.mm
│ ├── POPPropertyAnimationInternal.h
│ ├── POPSpringAnimation.h
│ ├── POPSpringAnimation.mm
│ ├── POPSpringAnimationInternal.h
│ ├── POPSpringSolver.h
│ ├── POPVector.h
│ ├── POPVector.mm
│ ├── WebCore
│ ├── FloatConversion.h
│ ├── TransformationMatrix.cpp
│ ├── TransformationMatrix.h
│ └── UnitBezier.h
│ ├── en.lproj
│ └── InfoPlist.strings
│ ├── pop-Info.plist
│ └── pop-Prefix.pch
├── LTStackViewTests
├── LTStackViewTests-Info.plist
├── LTStackViewTests.m
└── en.lproj
│ └── InfoPlist.strings
├── README.md
└── image
└── demostration.gif
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | *.swp
3 | *~.nib
4 |
5 | build/
6 | xcuserdata/
7 | *.pbxuser
8 | *.perspective
9 | *.perspectivev3
10 |
--------------------------------------------------------------------------------
/LTStackView.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/LTStackView/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // LTStackView
4 | //
5 | // Created by ltebean on 14-8-26.
6 | // Copyright (c) 2014年 ltebean. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AppDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow *window;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/LTStackView/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // LTStackView
4 | //
5 | // Created by ltebean on 14-8-26.
6 | // Copyright (c) 2014年 ltebean. All rights reserved.
7 | //
8 |
9 | #import "AppDelegate.h"
10 |
11 | @implementation AppDelegate
12 |
13 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
14 | {
15 | // Override point for customization after application launch.
16 | return YES;
17 | }
18 |
19 | - (void)applicationWillResignActive:(UIApplication *)application
20 | {
21 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
22 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
23 | }
24 |
25 | - (void)applicationDidEnterBackground:(UIApplication *)application
26 | {
27 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
28 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
29 | }
30 |
31 | - (void)applicationWillEnterForeground:(UIApplication *)application
32 | {
33 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
34 | }
35 |
36 | - (void)applicationDidBecomeActive:(UIApplication *)application
37 | {
38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
39 | }
40 |
41 | - (void)applicationWillTerminate:(UIApplication *)application
42 | {
43 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
44 | }
45 |
46 | @end
47 |
--------------------------------------------------------------------------------
/LTStackView/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/LTStackView/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "40x40",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "60x60",
16 | "scale" : "2x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/LTStackView/Images.xcassets/LaunchImage.launchimage/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "orientation" : "portrait",
5 | "idiom" : "iphone",
6 | "extent" : "full-screen",
7 | "minimum-system-version" : "7.0",
8 | "scale" : "2x"
9 | },
10 | {
11 | "orientation" : "portrait",
12 | "idiom" : "iphone",
13 | "subtype" : "retina4",
14 | "extent" : "full-screen",
15 | "minimum-system-version" : "7.0",
16 | "scale" : "2x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/LTStackView/LTStackView-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | ${PRODUCT_NAME}
9 | CFBundleExecutable
10 | ${EXECUTABLE_NAME}
11 | CFBundleIdentifier
12 | org.ltebean.${PRODUCT_NAME:rfc1034identifier}
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | ${PRODUCT_NAME}
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1.0
25 | LSRequiresIPhoneOS
26 |
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/LTStackView/LTStackView-Prefix.pch:
--------------------------------------------------------------------------------
1 | //
2 | // Prefix header
3 | //
4 | // The contents of this file are implicitly included at the beginning of every source file.
5 | //
6 |
7 | #import
8 |
9 | #ifndef __IPHONE_5_0
10 | #warning "This project uses features only available in iOS SDK 5.0 and later."
11 | #endif
12 |
13 | #ifdef __OBJC__
14 | #import
15 | #import
16 | #endif
17 |
--------------------------------------------------------------------------------
/LTStackView/LTStackView.h:
--------------------------------------------------------------------------------
1 | //
2 | // LTStackView.h
3 | // LTStackView
4 | //
5 | // Created by ltebean on 14-8-26.
6 | // Copyright (c) 2014年 ltebean. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @protocol LTStackViewDataSource
12 | -(UIView*) nextView;
13 | @end
14 |
15 | @interface LTStackView : UIView
16 | @property(nonatomic,weak) id dataSource;
17 | -(void) next;
18 | @end
19 |
--------------------------------------------------------------------------------
/LTStackView/LTStackView.m:
--------------------------------------------------------------------------------
1 | //
2 | // LTStackView.m
3 | // LTStackView
4 | //
5 | // Created by ltebean on 14-8-26.
6 | // Copyright (c) 2014年 ltebean. All rights reserved.
7 | //
8 |
9 | #import "LTStackView.h"
10 | #import "POP/POP.h"
11 |
12 | @interface LTStackView()
13 | @property (nonatomic) CGRect pullBackArea;
14 | @property (nonatomic,strong) UIView* nextView;
15 | @end
16 |
17 | @implementation LTStackView
18 |
19 | - (id)initWithFrame:(CGRect)frame
20 | {
21 | self = [super initWithFrame:frame];
22 | if (self) {
23 | }
24 | return self;
25 | }
26 |
27 | -(void) next
28 | {
29 | self.pullBackArea= CGRectMake(self.frame.size.width/4, self.frame.size.height/4, self.frame.size.width/2, self.frame.size.height/2);
30 |
31 | if(!self.nextView){
32 | self.nextView=[self.dataSource nextView];
33 | }
34 | [self showView:self.nextView];
35 | self.nextView=[self.dataSource nextView];
36 | }
37 |
38 | - (void)handlePan:(UIPanGestureRecognizer *)recognizer
39 | {
40 | CGPoint translation = [recognizer translationInView:self];
41 |
42 | UIView *view = recognizer.view;
43 | view.center = CGPointMake(view.center.x + translation.x,
44 | view.center.y + translation.y);
45 |
46 | [recognizer setTranslation:CGPointMake(0, 0) inView:self];
47 |
48 | if(recognizer.state == UIGestureRecognizerStateEnded) {
49 | if(CGRectContainsPoint(self.pullBackArea, recognizer.view.center) || !self.nextView){
50 | CGPoint center=CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2);
51 |
52 | POPSpringAnimation *positionAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewCenter];
53 | positionAnimation.springBounciness=10;
54 | positionAnimation.toValue = [NSValue valueWithCGPoint:center];
55 | [recognizer.view pop_addAnimation:positionAnimation forKey:@"layerPositionAnimation"];
56 | }else{
57 | CGPoint velocity = [recognizer velocityInView:recognizer.view];
58 |
59 | POPDecayAnimation *positionAnimation = [POPDecayAnimation animationWithPropertyNamed:kPOPLayerPosition];
60 | positionAnimation.delegate = self;
61 | positionAnimation.velocity =[NSValue valueWithCGPoint:velocity];
62 |
63 | POPBasicAnimation *fadeOutAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPViewAlpha];
64 | fadeOutAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
65 | fadeOutAnimation.toValue=@(0.0);
66 |
67 | [fadeOutAnimation setCompletionBlock:^(POPAnimation * anim , BOOL finished) {
68 | [view removeFromSuperview];
69 | }];
70 |
71 |
72 | [recognizer.view.layer pop_addAnimation:positionAnimation forKey:@"layerPositionAnimation"];
73 |
74 | [recognizer.view pop_addAnimation:fadeOutAnimation forKey:@"fadeOutAnimation"];
75 |
76 | [self next];
77 | }
78 | }
79 | }
80 |
81 | -(void) showView:(UIView*) view
82 | {
83 | CGRect frame=view.frame;
84 |
85 | view.frame=CGRectZero;
86 | view.center=CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2);
87 |
88 |
89 | UIPanGestureRecognizer *recognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
90 | [view addGestureRecognizer:recognizer];
91 |
92 | [self addSubview:view];
93 |
94 | POPSpringAnimation *animation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewSize];
95 | animation.toValue=[NSValue valueWithCGSize:frame.size];
96 | animation.springBounciness=10;
97 | [view pop_addAnimation:animation forKey:@"zoomInAnimation"];
98 | }
99 |
100 | @end
101 |
--------------------------------------------------------------------------------
/LTStackView/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // LTStackView
4 | //
5 | // Created by ltebean on 14-8-26.
6 | // Copyright (c) 2014年 ltebean. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/LTStackView/ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.m
3 | // LTStackView
4 | //
5 | // Created by ltebean on 14-8-26.
6 | // Copyright (c) 2014年 ltebean. All rights reserved.
7 | //
8 |
9 | #import "ViewController.h"
10 | #import "LTStackView.h"
11 | @interface ViewController ()
12 | @property (weak, nonatomic) IBOutlet LTStackView *stackView;
13 | @property int counter;
14 | @end
15 |
16 | @implementation ViewController
17 |
18 | - (void)viewDidLoad
19 | {
20 | [super viewDidLoad];
21 | self.stackView.dataSource=self;
22 | self.counter=0;
23 |
24 | // Do any additional setup after loading the view, typically from a nib.
25 | }
26 |
27 | -(UIView*) nextView
28 | {
29 | if(self.counter++==20){
30 | return nil;
31 | }
32 |
33 | UIView *view=[[UIView alloc]initWithFrame:CGRectMake(0, 0, 200, 200)];
34 | view.backgroundColor= [UIColor colorWithRed:((10 * self.counter) / 255.0) green:((20 * self.counter)/255.0) blue:((30 * self.counter)/255.0) alpha:1.0f];
35 | return view;
36 | }
37 |
38 |
39 | -(void) viewDidAppear:(BOOL)animated
40 | {
41 | [super viewDidAppear:animated];
42 | [self.stackView next];
43 | }
44 |
45 | @end
46 |
--------------------------------------------------------------------------------
/LTStackView/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/LTStackView/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // LTStackView
4 | //
5 | // Created by ltebean on 14-8-26.
6 | // Copyright (c) 2014年 ltebean. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #import "AppDelegate.h"
12 |
13 | int main(int argc, char * argv[])
14 | {
15 | @autoreleasepool {
16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/LTStackView/pop/POP.h:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #ifndef POP_POP_H
11 | #define POP_POP_H
12 |
13 | #import "POPAnimatableProperty.h"
14 | #import "POPAnimation.h"
15 | #import "POPAnimationEvent.h"
16 | #import "POPAnimationExtras.h"
17 | #import "POPAnimationTracer.h"
18 | #import "POPAnimator.h"
19 | #import "POPBasicAnimation.h"
20 | #import "POPCustomAnimation.h"
21 | #import "POPDecayAnimation.h"
22 | #import "POPDefines.h"
23 | #import "POPGeometry.h"
24 | #import "POPLayerExtras.h"
25 | #import "POPPropertyAnimation.h"
26 | #import "POPSpringAnimation.h"
27 |
28 |
29 | #endif /* POP_POP_H */
30 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPAction.h:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #ifndef POPACTION_H
11 | #define POPACTION_H
12 |
13 | #import
14 | #import "POPDefines.h"
15 |
16 | #ifdef __cplusplus
17 |
18 | namespace POP {
19 |
20 | /**
21 | @abstract Disables Core Animation actions using RAII.
22 | @discussion The disablement of actions is scoped to the current transaction.
23 | */
24 | class ActionDisabler
25 | {
26 | BOOL state;
27 |
28 | public:
29 | ActionDisabler() POP_NOTHROW
30 | {
31 | state = [CATransaction disableActions];
32 | [CATransaction setDisableActions:YES];
33 | }
34 |
35 | ~ActionDisabler()
36 | {
37 | [CATransaction setDisableActions:state];
38 | }
39 | };
40 |
41 | /**
42 | @abstract Enables Core Animation actions using RAII.
43 | @discussion The enablement of actions is scoped to the current transaction.
44 | */
45 | class ActionEnabler
46 | {
47 | BOOL state;
48 |
49 | public:
50 | ActionEnabler() POP_NOTHROW
51 | {
52 | state = [CATransaction disableActions];
53 | [CATransaction setDisableActions:NO];
54 | }
55 |
56 | ~ActionEnabler()
57 | {
58 | [CATransaction setDisableActions:state];
59 | }
60 | };
61 |
62 | }
63 |
64 | #endif /* __cplusplus */
65 |
66 | #endif /* POPACTION_H */
67 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPAnimatableProperty.h:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 | #import
12 |
13 | @class POPMutableAnimatableProperty;
14 |
15 | /**
16 | @abstract Describes an animatable property.
17 | */
18 | @interface POPAnimatableProperty : NSObject
19 |
20 | /**
21 | @abstract Property accessor.
22 | @param name The name of the property.
23 | @return The animatable property with that name or nil if it does not exist.
24 | @discussion Common animatable properties are included by default. Use the provided constants to reference.
25 | */
26 | + (id)propertyWithName:(NSString *)name;
27 |
28 | /**
29 | @abstract The designated initializer.
30 | @param name The name of the property.
31 | @param block The block used to configure the property on creation.
32 | @return The animatable property with name if it exists, otherwise a newly created instance configured by block.
33 | @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.
34 | */
35 | + (id)propertyWithName:(NSString *)name initializer:(void (^)(POPMutableAnimatableProperty *prop))block;
36 |
37 | /**
38 | @abstract The name of the property.
39 | @discussion Used to uniquely identify an animatable property.
40 | */
41 | @property (readonly, nonatomic, copy) NSString *name;
42 |
43 | /**
44 | @abstract Block used to read values from a property into an array of floats.
45 | */
46 | @property (readonly, nonatomic, copy) void (^readBlock)(id obj, CGFloat values[]);
47 |
48 | /**
49 | @abstract Block used to write values from an array of floats into a property.
50 | */
51 | @property (readonly, nonatomic, copy) void (^writeBlock)(id obj, const CGFloat values[]);
52 |
53 | /**
54 | @abstract The threshold value used when determining completion of dynamics simulations.
55 | */
56 | @property (readonly, nonatomic, assign) CGFloat threshold;
57 |
58 | @end
59 |
60 | /**
61 | @abstract A mutable animatable property intended for configuration.
62 | */
63 | @interface POPMutableAnimatableProperty : POPAnimatableProperty
64 |
65 | /**
66 | @abstract A read-write version of POPAnimatableProperty name property.
67 | */
68 | @property (readwrite, nonatomic, copy) NSString *name;
69 |
70 | /**
71 | @abstract A read-write version of POPAnimatableProperty readBlock property.
72 | */
73 | @property (readwrite, nonatomic, copy) void (^readBlock)(id obj, CGFloat values[]);
74 |
75 | /**
76 | @abstract A read-write version of POPAnimatableProperty writeBlock property.
77 | */
78 | @property (readwrite, nonatomic, copy) void (^writeBlock)(id obj, const CGFloat values[]);
79 |
80 | /**
81 | @abstract A read-write version of POPAnimatableProperty threshold property.
82 | */
83 | @property (readwrite, nonatomic, assign) CGFloat threshold;
84 |
85 | @end
86 |
87 | /**
88 | Common CALayer property names.
89 | */
90 | extern NSString * const kPOPLayerBackgroundColor;
91 | extern NSString * const kPOPLayerBounds;
92 | extern NSString * const kPOPLayerOpacity;
93 | extern NSString * const kPOPLayerPosition;
94 | extern NSString * const kPOPLayerPositionX;
95 | extern NSString * const kPOPLayerPositionY;
96 | extern NSString * const kPOPLayerRotation;
97 | extern NSString * const kPOPLayerRotationX;
98 | extern NSString * const kPOPLayerRotationY;
99 | extern NSString * const kPOPLayerScaleX;
100 | extern NSString * const kPOPLayerScaleXY;
101 | extern NSString * const kPOPLayerScaleY;
102 | extern NSString * const kPOPLayerSize;
103 | extern NSString * const kPOPLayerSubscaleXY;
104 | extern NSString * const kPOPLayerSubtranslationX;
105 | extern NSString * const kPOPLayerSubtranslationXY;
106 | extern NSString * const kPOPLayerSubtranslationY;
107 | extern NSString * const kPOPLayerSubtranslationZ;
108 | extern NSString * const kPOPLayerTranslationX;
109 | extern NSString * const kPOPLayerTranslationXY;
110 | extern NSString * const kPOPLayerTranslationY;
111 | extern NSString * const kPOPLayerTranslationZ;
112 | extern NSString * const kPOPLayerZPosition;
113 |
114 |
115 | #if TARGET_OS_IPHONE
116 |
117 | /**
118 | Common UIView property names.
119 | */
120 | extern NSString * const kPOPViewAlpha;
121 | extern NSString * const kPOPViewBackgroundColor;
122 | extern NSString * const kPOPViewBounds;
123 | extern NSString * const kPOPViewCenter;
124 | extern NSString * const kPOPViewFrame;
125 | extern NSString * const kPOPViewScaleX;
126 | extern NSString * const kPOPViewScaleXY;
127 | extern NSString * const kPOPViewScaleY;
128 | extern NSString * const kPOPViewSize;
129 |
130 |
131 | /**
132 | Common UITableView property names.
133 | */
134 | extern NSString * const kPOPTableViewContentOffset;
135 | extern NSString * const kPOPTableViewContentSize;
136 |
137 |
138 | #endif
139 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPAnimation.h:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 |
12 | #import "POPAnimationTracer.h"
13 | #import "POPGeometry.h"
14 |
15 | @class CAMediaTimingFunction;
16 |
17 | /**
18 | @abstract The abstract animation base class.
19 | @discussion Instantiate and use one of the concrete animation subclasses.
20 | */
21 | @interface POPAnimation : NSObject
22 |
23 | /**
24 | @abstract The name of the animation.
25 | @discussion Optional property to help identify the animation.
26 | */
27 | @property (copy, nonatomic) NSString *name;
28 |
29 | /**
30 | @abstract The beginTime of the animation in media time.
31 | @discussion Defaults to 0 and starts immediately.
32 | */
33 | @property (assign, nonatomic) CFTimeInterval beginTime;
34 |
35 | /**
36 | @abstract The animation delegate.
37 | @discussion See {@ref POPAnimationDelegate} for details.
38 | */
39 | @property (weak, nonatomic) id delegate;
40 |
41 | /**
42 | @abstract The animation tracer.
43 | @discussion Returns the existing tracer, creating one if needed. Call start/stop on the tracer to toggle event collection.
44 | */
45 | @property (readonly, nonatomic) POPAnimationTracer *tracer;
46 |
47 | /**
48 | @abstract Optional block called on animation completion.
49 | */
50 | @property (copy, nonatomic) void (^completionBlock)(POPAnimation *anim, BOOL finished);
51 |
52 | /**
53 | @abstract Flag indicating whether animation should be removed on completion.
54 | @discussion Setting to NO can facilitate animation reuse. Defaults to YES.
55 | */
56 | @property (assign, nonatomic) BOOL removedOnCompletion;
57 |
58 | /**
59 | @abstract Flag indicating whether animation is paused.
60 | @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.
61 | */
62 | @property (assign, nonatomic, getter = isPaused) BOOL paused;
63 |
64 | @end
65 |
66 | /**
67 | @abstract The animation delegate.
68 | */
69 | @protocol POPAnimationDelegate
70 | @optional
71 |
72 | /**
73 | @abstract Called on animation start.
74 | @param anim The relevant animation.
75 | */
76 | - (void)pop_animationDidStart:(POPAnimation *)anim;
77 |
78 | /**
79 | @abstract Called when value meets or exceeds to value.
80 | @param anim The relevant animation.
81 | */
82 | - (void)pop_animationDidReachToValue:(POPAnimation *)anim;
83 |
84 | /**
85 | @abstract Called on animation stop.
86 | @param anim The relevant animation.
87 | @param finished Flag indicating finished state. Flag is true if the animation reached completion before being removed.
88 | */
89 | - (void)pop_animationDidStop:(POPAnimation *)anim finished:(BOOL)finished;
90 |
91 | /**
92 | @abstract Called each frame animation is applied.
93 | @param anim The relevant animation.
94 | */
95 | - (void)pop_animationDidApply:(POPAnimation *)anim;
96 |
97 | @end
98 |
99 |
100 | @interface NSObject (POP)
101 |
102 | /**
103 | @abstract Add an animation to the reciver.
104 | @param anim The animation to add.
105 | @param key The key used to identify the animation.
106 | @discussion The 'key' may be any string such that only one animation per unique key is added per object.
107 | */
108 | - (void)pop_addAnimation:(POPAnimation *)anim forKey:(NSString *)key;
109 |
110 | /**
111 | @abstract Remove all animations attached to the receiver.
112 | */
113 | - (void)pop_removeAllAnimations;
114 |
115 | /**
116 | @abstract Remove any animation attached to the receiver for 'key'.
117 | @param key The key used to identify the animation.
118 | */
119 | - (void)pop_removeAnimationForKey:(NSString *)key;
120 |
121 | /**
122 | @abstract Returns an array containing the keys of all animations currently attached to the receiver.
123 | @param The order of keys reflects the order in which animations will be applied.
124 | */
125 | - (NSArray *)pop_animationKeys;
126 |
127 | /**
128 | @abstract Returns any animation attached to the receiver.
129 | @param key The key used to identify the animation.
130 | @returns The animation currently attached, or nil if no such animation exists.
131 | */
132 | - (id)pop_animationForKey:(NSString *)key;
133 |
134 | @end
135 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPAnimation.mm:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import "POPAnimationInternal.h"
11 | #import "POPAnimationTracerInternal.h"
12 |
13 | #import
14 | #include
15 |
16 | #import "POPAnimationExtras.h"
17 | #import "POPAnimationRuntime.h"
18 | #import "POPAnimatorPrivate.h"
19 | #import "POPAction.h"
20 |
21 | using namespace POP;
22 |
23 | #pragma mark - POPAnimation
24 |
25 | @implementation POPAnimation
26 |
27 | #pragma mark - Lifecycle
28 |
29 | - (id)init
30 | {
31 | [NSException raise:NSStringFromClass([self class]) format:@"Attempting to instantiate an abstract class. Use a concrete subclass instead."];
32 | return nil;
33 | }
34 |
35 | - (id)_init
36 | {
37 | self = [super init];
38 | if (nil != self) {
39 | [self _initState];
40 | }
41 | return self;
42 | }
43 |
44 | - (void)_initState
45 | {
46 | _state = new POPAnimationState(self);
47 | }
48 |
49 | - (void)dealloc
50 | {
51 | if (_state) {
52 | delete _state;
53 | _state = NULL;
54 | };
55 | }
56 |
57 | #pragma mark - Properties
58 |
59 | - (id)delegate
60 | {
61 | return _state->delegate;
62 | }
63 |
64 | - (void)setDelegate:(id)delegate
65 | {
66 | _state->setDelegate(delegate);
67 | }
68 |
69 | - (BOOL)isPaused
70 | {
71 | return _state->paused;
72 | }
73 |
74 | - (void)setPaused:(BOOL)paused
75 | {
76 | _state->setPaused(paused ? true : false);
77 | }
78 |
79 | FB_PROPERTY_GET(POPAnimationState, type, POPAnimationType);
80 | DEFINE_RW_PROPERTY_OBJ_COPY(POPAnimationState, completionBlock, setCompletionBlock:, POPAnimationCompletionBlock);
81 | DEFINE_RW_PROPERTY_OBJ_COPY(POPAnimationState, name, setName:, NSString*);
82 | DEFINE_RW_PROPERTY(POPAnimationState, beginTime, setBeginTime:, CFTimeInterval);
83 | DEFINE_RW_FLAG(POPAnimationState, removedOnCompletion, removedOnCompletion, setRemovedOnCompletion:);
84 |
85 | - (id)valueForUndefinedKey:(NSString *)key
86 | {
87 | return _state->dict[key];
88 | }
89 |
90 | - (void)setValue:(id)value forUndefinedKey:(NSString *)key
91 | {
92 | if (!value) {
93 | [_state->dict removeObjectForKey:key];
94 | } else {
95 | if (!_state->dict)
96 | _state->dict = [[NSMutableDictionary alloc] init];
97 | _state->dict[key] = value;
98 | }
99 | }
100 |
101 | - (POPAnimationTracer *)tracer
102 | {
103 | POPAnimationState *s = POPAnimationGetState(self);
104 | if (!s->tracer) {
105 | s->tracer = [[POPAnimationTracer alloc] initWithAnimation:self];
106 | }
107 | return s->tracer;
108 | }
109 |
110 | - (NSString *)description
111 | {
112 | NSMutableString *s = [NSMutableString stringWithFormat:@"<%@:%p", NSStringFromClass([self class]), self];
113 | [self _appendDescription:s debug:NO];
114 | [s appendString:@">"];
115 | return s;
116 | }
117 |
118 | - (NSString *)debugDescription
119 | {
120 | NSMutableString *s = [NSMutableString stringWithFormat:@"<%@:%p", NSStringFromClass([self class]), self];
121 | [self _appendDescription:s debug:YES];
122 | [s appendString:@">"];
123 | return s;
124 | }
125 |
126 | #pragma mark - Utility
127 |
128 | POPAnimationState *POPAnimationGetState(POPAnimation *a)
129 | {
130 | return a->_state;
131 | }
132 |
133 | - (BOOL)_advance:(id)object currentTime:(CFTimeInterval)currentTime elapsedTime:(CFTimeInterval)elapsedTime
134 | {
135 | return YES;
136 | }
137 |
138 | - (void)_appendDescription:(NSMutableString *)s debug:(BOOL)debug
139 | {
140 | if (_state->name)
141 | [s appendFormat:@"; name = %@", _state->name];
142 |
143 | if (!self.removedOnCompletion)
144 | [s appendFormat:@"; removedOnCompletion = %@", POPStringFromBOOL(self.removedOnCompletion)];
145 |
146 | if (debug) {
147 | if (_state->active)
148 | [s appendFormat:@"; active = %@", POPStringFromBOOL(_state->active)];
149 |
150 | if (_state->paused)
151 | [s appendFormat:@"; paused = %@", POPStringFromBOOL(_state->paused)];
152 | }
153 |
154 | if (_state->beginTime) {
155 | [s appendFormat:@"; beginTime = %f", _state->beginTime];
156 | }
157 |
158 | for (NSString *key in _state->dict) {
159 | [s appendFormat:@"; %@ = %@", key, _state->dict[key]];
160 | }
161 | }
162 |
163 | @end
164 |
165 |
166 | #pragma mark - POPPropertyAnimation
167 |
168 | #pragma mark - POPBasicAnimation
169 |
170 | #pragma mark - POPDecayAnimation
171 |
172 | @implementation NSObject (POP)
173 |
174 | - (void)pop_addAnimation:(POPAnimation *)anim forKey:(NSString *)key
175 | {
176 | [[POPAnimator sharedAnimator] addAnimation:anim forObject:self key:key];
177 | }
178 |
179 | - (void)pop_removeAllAnimations
180 | {
181 | [[POPAnimator sharedAnimator] removeAllAnimationsForObject:self];
182 | }
183 |
184 | - (void)pop_removeAnimationForKey:(NSString *)key
185 | {
186 | [[POPAnimator sharedAnimator] removeAnimationForObject:self key:key];
187 | }
188 |
189 | - (NSArray *)pop_animationKeys
190 | {
191 | return [[POPAnimator sharedAnimator] animationKeysForObject:self];
192 | }
193 |
194 | - (id)pop_animationForKey:(NSString *)key
195 | {
196 | return [[POPAnimator sharedAnimator] animationForObject:self key:key];
197 | }
198 |
199 | @end
200 |
201 | @implementation NSProxy (POP)
202 |
203 | - (void)pop_addAnimation:(POPAnimation *)anim forKey:(NSString *)key
204 | {
205 | [[POPAnimator sharedAnimator] addAnimation:anim forObject:self key:key];
206 | }
207 |
208 | - (void)pop_removeAllAnimations
209 | {
210 | [[POPAnimator sharedAnimator] removeAllAnimationsForObject:self];
211 | }
212 |
213 | - (void)pop_removeAnimationForKey:(NSString *)key
214 | {
215 | [[POPAnimator sharedAnimator] removeAnimationForObject:self key:key];
216 | }
217 |
218 | - (NSArray *)pop_animationKeys
219 | {
220 | return [[POPAnimator sharedAnimator] animationKeysForObject:self];
221 | }
222 |
223 | - (id)pop_animationForKey:(NSString *)key
224 | {
225 | return [[POPAnimator sharedAnimator] animationForObject:self key:key];
226 | }
227 |
228 | @end
229 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPAnimationEvent.h:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 |
12 | /**
13 | @abstract Enumeraton of animation event types.
14 | */
15 | typedef NS_ENUM(NSUInteger, POPAnimationEventType) {
16 | kPOPAnimationEventPropertyRead = 0,
17 | kPOPAnimationEventPropertyWrite,
18 | kPOPAnimationEventToValueUpdate,
19 | kPOPAnimationEventFromValueUpdate,
20 | kPOPAnimationEventVelocityUpdate,
21 | kPOPAnimationEventBouncinessUpdate,
22 | kPOPAnimationEventSpeedUpdate,
23 | kPOPAnimationEventFrictionUpdate,
24 | kPOPAnimationEventMassUpdate,
25 | kPOPAnimationEventTensionUpdate,
26 | kPOPAnimationEventDidStart,
27 | kPOPAnimationEventDidStop,
28 | kPOPAnimationEventDidReachToValue,
29 | };
30 |
31 | /**
32 | @abstract The base animation event class.
33 | */
34 | @interface POPAnimationEvent : NSObject
35 |
36 | /**
37 | @abstract The event type. See {@ref POPAnimationEventType} for possible values.
38 | */
39 | @property (readonly, nonatomic, assign) POPAnimationEventType type;
40 |
41 | /**
42 | @abstract The time of event.
43 | */
44 | @property (readonly, nonatomic, assign) CFTimeInterval time;
45 |
46 | /**
47 | @abstract Optional string describing the animation at time of event.
48 | */
49 | @property (readonly, nonatomic, copy) NSString *animationDescription;
50 |
51 | @end
52 |
53 | /**
54 | @abstract An animation event subclass for recording value and velocity.
55 | */
56 | @interface POPAnimationValueEvent : POPAnimationEvent
57 |
58 | /**
59 | @abstract The value recorded.
60 | */
61 | @property (readonly, nonatomic, strong) id value;
62 |
63 | /**
64 | @abstract The velocity recorded, if any.
65 | */
66 | @property (readonly, nonatomic, strong) id velocity;
67 |
68 | @end
69 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPAnimationEvent.mm:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import "POPAnimationEvent.h"
11 | #import "POPAnimationEventInternal.h"
12 |
13 | static NSString *stringFromType(POPAnimationEventType aType)
14 | {
15 | switch (aType) {
16 | case kPOPAnimationEventPropertyRead:
17 | return @"read";
18 | case kPOPAnimationEventPropertyWrite:
19 | return @"write";
20 | case kPOPAnimationEventToValueUpdate:
21 | return @"toValue";
22 | case kPOPAnimationEventFromValueUpdate:
23 | return @"fromValue";
24 | case kPOPAnimationEventVelocityUpdate:
25 | return @"velocity";
26 | case kPOPAnimationEventSpeedUpdate:
27 | return @"speed";
28 | case kPOPAnimationEventBouncinessUpdate:
29 | return @"bounciness";
30 | case kPOPAnimationEventFrictionUpdate:
31 | return @"friction";
32 | case kPOPAnimationEventMassUpdate:
33 | return @"mass";
34 | case kPOPAnimationEventTensionUpdate:
35 | return @"tension";
36 | case kPOPAnimationEventDidStart:
37 | return @"didStart";
38 | case kPOPAnimationEventDidStop:
39 | return @"didStop";
40 | case kPOPAnimationEventDidReachToValue:
41 | return @"didReachToValue";
42 | default:
43 | return nil;
44 | }
45 | }
46 |
47 | @implementation POPAnimationEvent
48 |
49 | - (instancetype)initWithType:(POPAnimationEventType)aType time:(CFTimeInterval)aTime
50 | {
51 | self = [super init];
52 | if (nil != self) {
53 | _type = aType;
54 | _time = aTime;
55 | }
56 | return self;
57 | }
58 |
59 | - (NSString *)description
60 | {
61 | NSMutableString *s = [NSMutableString stringWithFormat:@""];
64 | return s;
65 | }
66 |
67 | // subclass override
68 | - (void)_appendDescription:(NSMutableString *)s
69 | {
70 | if (0 != _animationDescription.length) {
71 | [s appendFormat:@"; animation = %@", _animationDescription];
72 | }
73 | }
74 |
75 | @end
76 |
77 | @implementation POPAnimationValueEvent
78 |
79 | - (instancetype)initWithType:(POPAnimationEventType)aType time:(CFTimeInterval)aTime value:(id)aValue
80 | {
81 | self = [self initWithType:aType time:aTime];
82 | if (nil != self) {
83 | _value = aValue;
84 | }
85 | return self;
86 | }
87 |
88 | - (void)_appendDescription:(NSMutableString *)s
89 | {
90 | [super _appendDescription:s];
91 |
92 | if (nil != _value) {
93 | [s appendFormat:@"; value = %@", _value];
94 | }
95 |
96 | if (nil != _velocity) {
97 | [s appendFormat:@"; velocity = %@", _velocity];
98 | }
99 | }
100 |
101 | @end
102 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPAnimationEventInternal.h:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 |
12 | #import "POPAnimationEvent.h"
13 |
14 | @interface POPAnimationEvent ()
15 |
16 | /**
17 | @abstract Default initializer.
18 | */
19 | - (instancetype)initWithType:(POPAnimationEventType)type time:(CFTimeInterval)time;
20 |
21 | /**
22 | @abstract Readwrite redefinition of public property.
23 | */
24 | @property (readwrite, nonatomic, copy) NSString *animationDescription;
25 |
26 | @end
27 |
28 | @interface POPAnimationValueEvent ()
29 |
30 | /**
31 | @abstract Default initializer.
32 | */
33 | - (instancetype)initWithType:(POPAnimationEventType)type time:(CFTimeInterval)time value:(id)value;
34 |
35 | /**
36 | @abstract Readwrite redefinition of public property.
37 | */
38 | @property (readwrite, nonatomic, strong) id velocity;
39 |
40 | @end
41 |
42 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPAnimationExtras.h:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 |
12 | #import "POPDefines.h"
13 | #import "POPSpringAnimation.h"
14 |
15 | /**
16 | @abstract The current drag coefficient.
17 | @discussion A value greater than 1.0 indicates Simulator slow-motion animations are enabled. Defaults to 1.0.
18 | */
19 | extern CGFloat POPAnimationDragCoefficient();
20 |
21 | @interface CAAnimation (POPAnimationExtras)
22 |
23 | /**
24 | @abstract Apply the current drag coefficient to animation speed.
25 | @discussion Convenience utility to respect Simulator slow-motion animation settings.
26 | */
27 | - (void)pop_applyDragCoefficient;
28 |
29 | @end
30 |
31 | @interface POPSpringAnimation (POPAnimationExtras)
32 |
33 | /**
34 | @abstract Converts from spring bounciness and speed to tension, friction and mass dynamics values.
35 | */
36 | + (void)convertBounciness:(CGFloat)bounciness speed:(CGFloat)speed toTension:(CGFloat *)outTension friction:(CGFloat *)outFriction mass:(CGFloat *)outMass;
37 |
38 | /**
39 | @abstract Converts from dynamics tension, friction and mass to spring bounciness and speed values.
40 | */
41 | + (void)convertTension:(CGFloat)tension friction:(CGFloat)friction toBounciness:(CGFloat *)outBounciness speed:(CGFloat *)outSpeed;
42 |
43 | @end
44 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPAnimationExtras.mm:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import "POPAnimationExtras.h"
11 |
12 | #import "POPAnimationPrivate.h"
13 | #import "POPMath.h"
14 |
15 | #if TARGET_OS_IPHONE
16 | #import
17 | #endif
18 |
19 | #if TARGET_IPHONE_SIMULATOR
20 | UIKIT_EXTERN CGFloat UIAnimationDragCoefficient(); // UIKit private drag coeffient, use judiciously
21 | #endif
22 |
23 | CGFloat POPAnimationDragCoefficient()
24 | {
25 | #if TARGET_IPHONE_SIMULATOR
26 | return UIAnimationDragCoefficient();
27 | #else
28 | return 1.0;
29 | #endif
30 | }
31 |
32 | @implementation CAAnimation (POPAnimationExtras)
33 |
34 | - (void)pop_applyDragCoefficient
35 | {
36 | CGFloat k = POPAnimationDragCoefficient();
37 | if (k != 0 && k != 1)
38 | self.speed = 1 / k;
39 | }
40 |
41 | @end
42 |
43 | @implementation POPSpringAnimation (POPAnimationExtras)
44 |
45 | static const CGFloat POPBouncy3NormalizationRange = 20.0;
46 | static const CGFloat POPBouncy3NormalizationScale = 1.7;
47 | static const CGFloat POPBouncy3BouncinessNormalizedMin = 0.0;
48 | static const CGFloat POPBouncy3BouncinessNormalizedMax = 0.8;
49 | static const CGFloat POPBouncy3SpeedNormalizedMin = 0.5;
50 | static const CGFloat POPBouncy3SpeedNormalizedMax = 200;
51 | static const CGFloat POPBouncy3FrictionInterpolationMax = 0.01;
52 |
53 | + (void)convertBounciness:(CGFloat)bounciness speed:(CGFloat)speed toTension:(CGFloat *)outTension friction:(CGFloat *)outFriction mass:(CGFloat *)outMass
54 | {
55 | double b = normalize(bounciness / POPBouncy3NormalizationScale, 0, POPBouncy3NormalizationRange);
56 | b = project_normal(b, POPBouncy3BouncinessNormalizedMin, POPBouncy3BouncinessNormalizedMax);
57 |
58 | double s = normalize(speed / POPBouncy3NormalizationScale, 0, POPBouncy3NormalizationRange);
59 |
60 | CGFloat tension = project_normal(s, POPBouncy3SpeedNormalizedMin, POPBouncy3SpeedNormalizedMax);
61 | CGFloat friction = quadratic_out_interpolation(b, b3_nobounce(tension), POPBouncy3FrictionInterpolationMax);
62 |
63 | tension = POP_ANIMATION_TENSION_FOR_QC_TENSION(tension);
64 | friction = POP_ANIMATION_FRICTION_FOR_QC_FRICTION(friction);
65 |
66 | if (outTension) {
67 | *outTension = tension;
68 | }
69 |
70 | if (outFriction) {
71 | *outFriction = friction;
72 | }
73 |
74 | if (outMass) {
75 | *outMass = 1.0;
76 | }
77 | }
78 |
79 | + (void)convertTension:(CGFloat)tension friction:(CGFloat)friction toBounciness:(CGFloat *)outBounciness speed:(CGFloat *)outSpeed
80 | {
81 | // Convert to QC values, in which our calculations are done.
82 | CGFloat qcFriction = QC_FRICTION_FOR_POP_ANIMATION_FRICTION(friction);
83 | CGFloat qcTension = QC_TENSION_FOR_POP_ANIMATION_TENSION(tension);
84 |
85 | // Friction is a function of bounciness and tension, according to the following:
86 | // friction = quadratic_out_interpolation(b, b3_nobounce(tension), POPBouncy3FrictionInterpolationMax);
87 | // Solve for bounciness, given a tension and friction.
88 |
89 | CGFloat nobounceTension = b3_nobounce(qcTension);
90 | CGFloat bounciness1, bounciness2;
91 |
92 | quadratic_solve((nobounceTension - POPBouncy3FrictionInterpolationMax), // a
93 | 2 * (POPBouncy3FrictionInterpolationMax - nobounceTension), // b
94 | (nobounceTension - qcFriction), // c
95 | bounciness1, // x1
96 | bounciness2); // x2
97 |
98 |
99 | // Choose the quadratic solution within the normalized bounciness range
100 | CGFloat projectedNormalizedBounciness = (bounciness2 < POPBouncy3BouncinessNormalizedMax) ? bounciness2 : bounciness1;
101 | CGFloat projectedNormalizedSpeed = qcTension;
102 |
103 | // Reverse projection + normalization
104 | CGFloat bounciness = ((POPBouncy3NormalizationRange * POPBouncy3NormalizationScale) / (POPBouncy3BouncinessNormalizedMax - POPBouncy3BouncinessNormalizedMin)) * (projectedNormalizedBounciness - POPBouncy3BouncinessNormalizedMin);
105 | CGFloat speed = ((POPBouncy3NormalizationRange * POPBouncy3NormalizationScale) / (POPBouncy3SpeedNormalizedMax - POPBouncy3SpeedNormalizedMin)) * (projectedNormalizedSpeed - POPBouncy3SpeedNormalizedMin);
106 |
107 | // Write back results
108 | if (outBounciness) {
109 | *outBounciness = bounciness;
110 | }
111 |
112 | if (outSpeed) {
113 | *outSpeed = speed;
114 | }
115 | }
116 |
117 | @end
118 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPAnimationInternal.h:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 |
12 | #import "POPAnimation.h"
13 | #import "POPAnimationRuntime.h"
14 | #import "POPAnimationTracer.h"
15 | #import "POPAnimationTracerInternal.h"
16 | #import "POPSpringSolver.h"
17 | #import "POPVector.h"
18 | #import "POPAction.h"
19 | #import "POPMath.h"
20 |
21 | using namespace POP;
22 |
23 | /**
24 | Enumeration of supported animation types.
25 | */
26 | enum POPAnimationType
27 | {
28 | kPOPAnimationSpring,
29 | kPOPAnimationDecay,
30 | kPOPAnimationBasic,
31 | kPOPAnimationCustom,
32 | };
33 |
34 | typedef struct
35 | {
36 | CGFloat progress;
37 | bool reached;
38 | } POPProgressMarker;
39 |
40 | typedef void (^POPAnimationCompletionBlock)(POPAnimation *anim, BOOL finished);
41 |
42 | @interface POPAnimation()
43 | - (instancetype)_init;
44 |
45 | @property (assign, nonatomic) SpringSolver4d *solver;
46 | @property (readonly, nonatomic) POPAnimationType type;
47 |
48 | /**
49 | The current animation value, updated while animation is progressing.
50 | */
51 | @property (copy, nonatomic, readonly) id currentValue;
52 |
53 | /**
54 | An array of optional progress markers. For each marker specified, the animation delegate will be informed when progress meets or exceeds the value specified. Specifying values outside of the [0, 1] range will give undefined results.
55 | */
56 | @property (copy, nonatomic) NSArray *progressMarkers;
57 |
58 | /**
59 | Return YES to indicate animation should continue animating.
60 | */
61 | - (BOOL)_advance:(id)object currentTime:(CFTimeInterval)currentTime elapsedTime:(CFTimeInterval)elapsedTime;
62 |
63 | /**
64 | Subclass override point to append animation description.
65 | */
66 | - (void)_appendDescription:(NSMutableString *)s debug:(BOOL)debug;
67 |
68 | @end
69 |
70 | NS_INLINE NSString *describe(VectorConstRef vec)
71 | {
72 | return NULL == vec ? @"null" : vec->toString();
73 | }
74 |
75 | NS_INLINE Vector4r vector4(VectorConstRef vec)
76 | {
77 | return NULL == vec ? Vector4r::Zero() : vec->vector4r();
78 | }
79 |
80 | NS_INLINE Vector4d vector4d(VectorConstRef vec)
81 | {
82 | if (NULL == vec) {
83 | return Vector4d::Zero();
84 | } else {
85 | return vec->vector4r().cast();
86 | }
87 | }
88 |
89 | NS_INLINE bool vec_equal(VectorConstRef v1, VectorConstRef v2)
90 | {
91 | if (v1 == v2) {
92 | return true;
93 | }
94 | if (!v1 || !v2) {
95 | return false;
96 | }
97 | return *v1 == *v2;
98 | }
99 |
100 | NS_INLINE CGFloat * vec_data(VectorRef vec)
101 | {
102 | return NULL == vec ? NULL : vec->data();
103 | }
104 |
105 | template
106 | struct ComputeProgressFunctor {
107 | CGFloat operator()(const T &value, const T &start, const T &end) const {
108 | return 0;
109 | }
110 | };
111 |
112 | template<>
113 | struct ComputeProgressFunctor {
114 | CGFloat operator()(const Vector4r &value, const Vector4r &start, const Vector4r &end) const {
115 | CGFloat s = (value - start).squaredNorm(); // distance from start
116 | CGFloat e = (value - end).squaredNorm(); // distance from end
117 | CGFloat d = (end - start).squaredNorm(); // distance from start to end
118 |
119 | if (0 == d) {
120 | return 1;
121 | } else if (s > e) {
122 | // s -------- p ---- e OR s ------- e ---- p
123 | return sqrtr(s/d);
124 | } else {
125 | // s --- p --------- e OR p ---- s ------- e
126 | return 1 - sqrtr(e/d);
127 | }
128 | }
129 | };
130 |
131 | struct _POPAnimationState;
132 | struct _POPDecayAnimationState;
133 | struct _POPPropertyAnimationState;
134 |
135 | extern _POPAnimationState *POPAnimationGetState(POPAnimation *a);
136 |
137 |
138 | #define FB_FLAG_GET(stype, flag, getter) \
139 | - (BOOL)getter { \
140 | return ((stype *)_state)->flag; \
141 | }
142 |
143 | #define FB_FLAG_SET(stype, flag, mutator) \
144 | - (void)mutator (BOOL)value { \
145 | if (value == ((stype *)_state)->flag) \
146 | return; \
147 | ((stype *)_state)->flag = value; \
148 | }
149 |
150 | #define DEFINE_RW_FLAG(stype, flag, getter, mutator) \
151 | FB_FLAG_GET (stype, flag, getter) \
152 | FB_FLAG_SET (stype, flag, mutator)
153 |
154 | #define FB_PROPERTY_GET(stype, property, ctype) \
155 | - (ctype)property { \
156 | return ((stype *)_state)->property; \
157 | }
158 |
159 | #define FB_PROPERTY_SET(stype, property, mutator, ctype, ...) \
160 | - (void)mutator (ctype)value { \
161 | if (value == ((stype *)_state)->property) \
162 | return; \
163 | ((stype *)_state)->property = value; \
164 | __VA_ARGS__ \
165 | }
166 |
167 | #define FB_PROPERTY_SET_OBJ_COPY(stype, property, mutator, ctype, ...) \
168 | - (void)mutator (ctype)value { \
169 | if (value == ((stype *)_state)->property) \
170 | return; \
171 | ((stype *)_state)->property = [value copy]; \
172 | __VA_ARGS__ \
173 | }
174 |
175 | #define DEFINE_RW_PROPERTY(stype, flag, mutator, ctype, ...) \
176 | FB_PROPERTY_GET (stype, flag, ctype) \
177 | FB_PROPERTY_SET (stype, flag, mutator, ctype, __VA_ARGS__)
178 |
179 | #define DEFINE_RW_PROPERTY_OBJ(stype, flag, mutator, ctype, ...) \
180 | FB_PROPERTY_GET (stype, flag, ctype) \
181 | FB_PROPERTY_SET (stype, flag, mutator, ctype, __VA_ARGS__)
182 |
183 | #define DEFINE_RW_PROPERTY_OBJ_COPY(stype, flag, mutator, ctype, ...) \
184 | FB_PROPERTY_GET (stype, flag, ctype) \
185 | FB_PROPERTY_SET_OBJ_COPY (stype, flag, mutator, ctype, __VA_ARGS__)
186 |
187 |
188 | /**
189 | Internal delegate definition.
190 | */
191 | @interface NSObject (POPAnimationDelegateInternal)
192 | - (void)pop_animation:(POPAnimation *)anim didReachProgress:(CGFloat)progress;
193 | @end
194 |
195 | struct _POPAnimationState
196 | {
197 | id __unsafe_unretained self;
198 | POPAnimationType type;
199 | NSString *name;
200 | NSUInteger ID;
201 | CFTimeInterval beginTime;
202 | CFTimeInterval startTime;
203 | CFTimeInterval lastTime;
204 | id __weak delegate;
205 | POPAnimationCompletionBlock completionBlock;
206 | NSMutableDictionary *dict;
207 | POPAnimationTracer *tracer;
208 | CGFloat progress;
209 |
210 | bool active:1;
211 | bool paused:1;
212 | bool removedOnCompletion:1;
213 |
214 | bool delegateDidStart:1;
215 | bool delegateDidStop:1;
216 | bool delegateDidProgress:1;
217 | bool delegateDidApply:1;
218 | bool delegateDidReachToValue:1;
219 |
220 | bool additive:1;
221 | bool didReachToValue:1;
222 | bool tracing:1; // corresponds to tracer started
223 | bool userSpecifiedDynamics:1;
224 | bool customFinished:1;
225 |
226 | _POPAnimationState(id __unsafe_unretained anim) :
227 | self(anim),
228 | type((POPAnimationType)0),
229 | name(nil),
230 | ID(0),
231 | beginTime(0),
232 | startTime(0),
233 | lastTime(0),
234 | delegate(nil),
235 | completionBlock(nil),
236 | dict(nil),
237 | tracer(nil),
238 | progress(0),
239 | active(false),
240 | paused(true),
241 | removedOnCompletion(true),
242 | delegateDidStart(false),
243 | delegateDidStop(false),
244 | delegateDidProgress(false),
245 | delegateDidApply(false),
246 | delegateDidReachToValue(false),
247 | additive(false),
248 | didReachToValue(false),
249 | tracing(false),
250 | userSpecifiedDynamics(false),
251 | customFinished(false) {}
252 |
253 | virtual ~_POPAnimationState()
254 | {
255 | name = nil;
256 | dict = nil;
257 | tracer = nil;
258 | completionBlock = NULL;
259 | }
260 |
261 | bool isCustom() {
262 | return kPOPAnimationCustom == type;
263 | }
264 |
265 | bool isStarted() {
266 | return 0 != startTime;
267 | }
268 |
269 | id getDelegate() {
270 | return delegate;
271 | }
272 |
273 | void setDelegate(id d) {
274 | if (d != delegate) {
275 | delegate = d;
276 | delegateDidStart = [d respondsToSelector:@selector(pop_animationDidStart:)];
277 | delegateDidStop = [d respondsToSelector:@selector(pop_animationDidStop:finished:)];
278 | delegateDidProgress = [d respondsToSelector:@selector(pop_animation:didReachProgress:)];
279 | delegateDidApply = [d respondsToSelector:@selector(pop_animationDidApply:)];
280 | delegateDidReachToValue = [d respondsToSelector:@selector(pop_animationDidReachToValue:)];
281 | }
282 | }
283 |
284 | bool getPaused() {
285 | return paused;
286 | }
287 |
288 | void setPaused(bool f) {
289 | if (f != paused) {
290 | paused = f;
291 | if (!paused) {
292 | reset(false);
293 | }
294 | }
295 | }
296 |
297 | CGFloat getProgress() {
298 | return progress;
299 | }
300 |
301 | /* returns true if started */
302 | bool startIfNeeded(id obj, CFTimeInterval time)
303 | {
304 | bool started = false;
305 |
306 | // detect start based on time
307 | if (0 == startTime && time >= beginTime) {
308 |
309 | // activate & unpause
310 | active = true;
311 | setPaused(false);
312 |
313 | // start us one frame in the past (when we added the animation)
314 | if (0 == beginTime) {
315 | time -= 1/60.;
316 | }
317 |
318 | // note start time
319 | startTime = lastTime = time;
320 | started = true;
321 | }
322 |
323 | // ensure values for running animation
324 | bool running = active && !paused;
325 | if (running) {
326 | willRun(started, obj);
327 | }
328 |
329 | // handle start
330 | if (started) {
331 | handleDidStart();
332 | }
333 |
334 | return started;
335 | }
336 |
337 | void stop(bool removing, bool done) {
338 | if (active)
339 | {
340 | // delegate progress one last time
341 | if (done) {
342 | delegateProgress();
343 | }
344 |
345 | if (removing) {
346 | active = false;
347 | }
348 |
349 | handleDidStop(done);
350 | } else {
351 |
352 | // stopped before even started
353 | // delegate start and stop regardless; matches CA behavior
354 | if (!isStarted()) {
355 | handleDidStart();
356 | handleDidStop(false);
357 | }
358 | }
359 |
360 | setPaused(true);
361 | }
362 |
363 | virtual void handleDidStart()
364 | {
365 | if (delegateDidStart) {
366 | ActionEnabler enabler;
367 | [delegate pop_animationDidStart:self];
368 | }
369 |
370 | if (tracing) {
371 | [tracer didStart];
372 | }
373 | }
374 |
375 | void handleDidStop(BOOL done)
376 | {
377 | if (delegateDidStop) {
378 | ActionEnabler enabler;
379 | [delegate pop_animationDidStop:self finished:done];
380 | }
381 |
382 | // add another strong reference to completion block before callout
383 | POPAnimationCompletionBlock block = completionBlock;
384 | if (block != NULL) {
385 | ActionEnabler enabler;
386 | block(self, done);
387 | }
388 |
389 | if (tracing) {
390 | [tracer didStop:done];
391 | }
392 | }
393 |
394 | /* virtual functions */
395 | virtual bool isDone() {
396 | if (isCustom()) {
397 | return customFinished;
398 | }
399 |
400 | return false;
401 | }
402 |
403 | bool advanceTime(CFTimeInterval time, id obj) {
404 | bool advanced = false;
405 | bool computedProgress = false;
406 |
407 | CFTimeInterval dt = time - lastTime;
408 | if (dt < 0.001)
409 | return advanced;
410 |
411 | switch (type) {
412 | case kPOPAnimationSpring:
413 | advanced = advance(time, dt, obj);
414 | break;
415 | case kPOPAnimationDecay:
416 | advanced = advance(time, dt, obj);
417 | break;
418 | case kPOPAnimationBasic: {
419 | advanced = advance(time, dt, obj);
420 | computedProgress = true;
421 | break;
422 | }
423 | case kPOPAnimationCustom: {
424 | customFinished = [self _advance:obj currentTime:time elapsedTime:dt] ? false : true;
425 | advanced = true;
426 | break;
427 | }
428 | default:
429 | break;
430 | }
431 |
432 | if (advanced) {
433 |
434 | // estimate progress
435 | if (!computedProgress) {
436 | computeProgress();
437 | }
438 |
439 | // delegate progress
440 | delegateProgress();
441 |
442 | // update time
443 | lastTime = time;
444 | }
445 |
446 | return advanced;
447 | }
448 |
449 | virtual void willRun(bool started, id obj) {}
450 | virtual bool advance(CFTimeInterval time, CFTimeInterval dt, id obj) { return false; }
451 | virtual void computeProgress() {}
452 | virtual void delegateProgress() {}
453 |
454 | virtual void delegateApply() {
455 | if (delegateDidApply) {
456 | ActionEnabler enabler;
457 | [delegate pop_animationDidApply:self];
458 | }
459 | }
460 |
461 | virtual void reset(bool all) {
462 | startTime = 0;
463 | lastTime = 0;
464 | }
465 | };
466 |
467 | typedef struct _POPAnimationState POPAnimationState;
468 |
469 |
470 | @interface POPAnimation ()
471 | {
472 | @protected
473 | struct _POPAnimationState *_state;
474 | }
475 |
476 | @end
477 |
478 | // NSProxy extensions, for testing pursposes
479 | @interface NSProxy (POP)
480 | - (void)pop_addAnimation:(POPAnimation *)anim forKey:(NSString *)key;
481 | - (void)pop_removeAllAnimations;
482 | - (void)pop_removeAnimationForKey:(NSString *)key;
483 | - (NSArray *)pop_animationKeys;
484 | - (POPAnimation *)pop_animationForKey:(NSString *)key;
485 | @end
486 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPAnimationPrivate.h:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import "POPAnimation.h"
11 |
12 | #define POP_ANIMATION_FRICTION_FOR_QC_FRICTION(qcFriction) (25.0 + (((qcFriction - 8.0) / 2.0) * (25.0 - 19.0)))
13 | #define POP_ANIMATION_TENSION_FOR_QC_TENSION(qcTension) (194.0 + (((qcTension - 30.0) / 50.0) * (375.0 - 194.0)))
14 |
15 | #define QC_FRICTION_FOR_POP_ANIMATION_FRICTION(fbFriction) (8.0 + 2.0 * ((fbFriction - 25.0)/(25.0 - 19.0)))
16 | #define QC_TENSION_FOR_POP_ANIMATION_TENSION(fbTension) (30.0 + 50.0 * ((fbTension - 194.0)/(375.0 - 194.0)))
17 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPAnimationRuntime.h:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 | #include
12 |
13 | #import
14 |
15 | #import "POPMath.h"
16 | #import "POPVector.h"
17 |
18 | enum POPValueType
19 | {
20 | kPOPValueUnknown = 0,
21 | kPOPValueInteger,
22 | kPOPValueFloat,
23 | kPOPValuePoint,
24 | kPOPValueSize,
25 | kPOPValueRect,
26 | kPOPValueAffineTransform,
27 | kPOPValueTransform,
28 | kPOPValueRange,
29 | kPOPValueColor,
30 | };
31 |
32 | using namespace POP;
33 |
34 | /**
35 | Returns value type based on objc type description, given list of supported value types and length.
36 | */
37 | extern POPValueType POPSelectValueType(const char *objctype, const POPValueType *types, size_t length);
38 |
39 | /**
40 | Returns value type based on objc object, given a list of supported value types and length.
41 | */
42 | extern POPValueType POPSelectValueType(id obj, const POPValueType *types, size_t length);
43 |
44 | /**
45 | Array of all value types.
46 | */
47 | extern const POPValueType kPOPAnimatableAllTypes[9];
48 |
49 | /**
50 | Array of all value types supported for animation.
51 | */
52 | extern const POPValueType kPOPAnimatableSupportTypes[7];
53 |
54 | /**
55 | Returns a string description of a value type.
56 | */
57 | extern NSString *POPValueTypeToString(POPValueType t);
58 |
59 | /**
60 | Returns a mutable dictionary of weak pointer keys to weak pointer values.
61 | */
62 | extern CFMutableDictionaryRef POPDictionaryCreateMutableWeakPointerToWeakPointer(NSUInteger capacity) CF_RETURNS_RETAINED;
63 |
64 | /**
65 | Returns a mutable dictionary of weak pointer keys to weak pointer values.
66 | */
67 | extern CFMutableDictionaryRef POPDictionaryCreateMutableWeakPointerToStrongObject(NSUInteger capacity) CF_RETURNS_RETAINED;
68 |
69 | /**
70 | Box a vector.
71 | */
72 | extern id POPBox(VectorConstRef vec, POPValueType type, bool force = false);
73 |
74 | /**
75 | Unbox a vector.
76 | */
77 | extern VectorRef POPUnbox(id value, POPValueType &type, NSUInteger &count, bool validate);
78 |
79 | /**
80 | Read/write block typedefs for convenience.
81 | */
82 | typedef void(^pop_animatable_read_block)(id obj, CGFloat *value);
83 | typedef void(^pop_animatable_write_block)(id obj, const CGFloat *value);
84 |
85 | /**
86 | Read object value and return a Vector4r.
87 | */
88 | NS_INLINE Vector4r read_values(pop_animatable_read_block read, id obj, size_t count)
89 | {
90 | Vector4r vec = Vector4r::Zero();
91 | if (0 == count)
92 | return vec;
93 |
94 | read(obj, vec.data());
95 |
96 | return vec;
97 | }
98 |
99 | NS_INLINE NSString *POPStringFromBOOL(BOOL value)
100 | {
101 | return value ? @"YES" : @"NO";
102 | }
103 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPAnimationRuntime.mm:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import "POPAnimationRuntime.h"
11 |
12 | #import
13 |
14 | #import
15 |
16 | #if TARGET_OS_IPHONE
17 | #import
18 | #else
19 | #import
20 | #endif
21 |
22 | #import "POPVector.h"
23 | #import "POPAnimationRuntime.h"
24 | #import "POPGeometry.h"
25 |
26 | static Boolean pointerEqual(const void *ptr1, const void *ptr2) {
27 | return ptr1 == ptr2;
28 | }
29 |
30 | static CFHashCode pointerHash(const void *ptr) {
31 | return (CFHashCode)(ptr);
32 | }
33 |
34 | CFMutableDictionaryRef POPDictionaryCreateMutableWeakPointerToWeakPointer(NSUInteger capacity)
35 | {
36 | CFDictionaryKeyCallBacks kcb = kCFTypeDictionaryKeyCallBacks;
37 |
38 | // weak, pointer keys
39 | kcb.retain = NULL;
40 | kcb.retain = NULL;
41 | kcb.equal = pointerEqual;
42 | kcb.hash = pointerHash;
43 |
44 | CFDictionaryValueCallBacks vcb = kCFTypeDictionaryValueCallBacks;
45 |
46 | // weak, pointer values
47 | vcb.retain = NULL;
48 | vcb.release = NULL;
49 | vcb.equal = pointerEqual;
50 |
51 | return CFDictionaryCreateMutable(NULL, capacity, &kcb, &vcb);
52 | }
53 |
54 | CFMutableDictionaryRef POPDictionaryCreateMutableWeakPointerToStrongObject(NSUInteger capacity)
55 | {
56 | CFDictionaryKeyCallBacks kcb = kCFTypeDictionaryKeyCallBacks;
57 |
58 | // weak, pointer keys
59 | kcb.retain = NULL;
60 | kcb.release = NULL;
61 | kcb.equal = pointerEqual;
62 | kcb.hash = pointerHash;
63 |
64 | // strong, object values
65 | CFDictionaryValueCallBacks vcb = kCFTypeDictionaryValueCallBacks;
66 |
67 | return CFDictionaryCreateMutable(NULL, capacity, &kcb, &vcb);
68 | }
69 |
70 | static bool FBCompareTypeEncoding(const char *objctype, POPValueType type)
71 | {
72 | switch (type)
73 | {
74 | case kPOPValueFloat:
75 | return (strcmp(objctype, @encode(float)) == 0
76 | || strcmp(objctype, @encode(double)) == 0
77 | );
78 |
79 | case kPOPValuePoint:
80 | return (strcmp(objctype, @encode(CGPoint)) == 0
81 | #if !TARGET_OS_IPHONE
82 | || strcmp(objctype, @encode(NSPoint)) == 0
83 | #endif
84 | );
85 |
86 | case kPOPValueSize:
87 | return (strcmp(objctype, @encode(CGSize)) == 0
88 | #if !TARGET_OS_IPHONE
89 | || strcmp(objctype, @encode(NSSize)) == 0
90 | #endif
91 | );
92 |
93 | case kPOPValueRect:
94 | return (strcmp(objctype, @encode(CGRect)) == 0
95 | #if !TARGET_OS_IPHONE
96 | || strcmp(objctype, @encode(NSRect)) == 0
97 | #endif
98 | );
99 |
100 | case kPOPValueAffineTransform:
101 | return strcmp(objctype, @encode(CGAffineTransform)) == 0;
102 |
103 | case kPOPValueTransform:
104 | return strcmp(objctype, @encode(CATransform3D)) == 0;
105 |
106 | case kPOPValueRange:
107 | return strcmp(objctype, @encode(CFRange)) == 0
108 | || strcmp(objctype, @encode (NSRange)) == 0;
109 |
110 | case kPOPValueInteger:
111 | return (strcmp(objctype, @encode(int)) == 0
112 | || strcmp(objctype, @encode(unsigned int)) == 0
113 | || strcmp(objctype, @encode(short)) == 0
114 | || strcmp(objctype, @encode(unsigned short)) == 0
115 | || strcmp(objctype, @encode(long)) == 0
116 | || strcmp(objctype, @encode(unsigned long)) == 0
117 | || strcmp(objctype, @encode(long long)) == 0
118 | || strcmp(objctype, @encode(unsigned long long)) == 0
119 | );
120 | default:
121 | return false;
122 | }
123 | }
124 |
125 | POPValueType POPSelectValueType(const char *objctype, const POPValueType *types, size_t length)
126 | {
127 | if (NULL != objctype) {
128 | for (size_t idx = 0; idx < length; idx++) {
129 | if (FBCompareTypeEncoding(objctype, types[idx]))
130 | return types[idx];
131 | }
132 | }
133 | return kPOPValueUnknown;
134 | }
135 |
136 | POPValueType POPSelectValueType(id obj, const POPValueType *types, size_t length)
137 | {
138 | if ([obj isKindOfClass:[NSValue class]]) {
139 | return POPSelectValueType([obj objCType], types, length);
140 | } else if (CFGetTypeID((__bridge CFTypeRef)obj) == CGColorGetTypeID()) {
141 | return kPOPValueColor;
142 | }
143 | return kPOPValueUnknown;
144 | }
145 |
146 | const POPValueType kPOPAnimatableAllTypes[9] = {kPOPValueInteger, kPOPValueFloat, kPOPValuePoint, kPOPValueSize, kPOPValueRect, kPOPValueAffineTransform, kPOPValueTransform, kPOPValueRange, kPOPValueColor};
147 |
148 | const POPValueType kPOPAnimatableSupportTypes[7] = {kPOPValueInteger, kPOPValueFloat, kPOPValuePoint, kPOPValueSize, kPOPValueRect, kPOPValueColor};
149 |
150 | NSString *POPValueTypeToString(POPValueType t)
151 | {
152 | switch (t) {
153 | case kPOPValueUnknown:
154 | return @"unknown";
155 | case kPOPValueInteger:
156 | return @"int";
157 | case kPOPValueFloat:
158 | return @"CGFloat";
159 | case kPOPValuePoint:
160 | return @"CGPoint";
161 | case kPOPValueSize:
162 | return @"CGSize";
163 | case kPOPValueRect:
164 | return @"CGRect";
165 | case kPOPValueAffineTransform:
166 | return @"CGAffineTransform";
167 | case kPOPValueTransform:
168 | return @"CATransform3D";
169 | case kPOPValueRange:
170 | return @"CFRange";
171 | case kPOPValueColor:
172 | return @"CGColorRef";
173 | default:
174 | return nil;
175 | }
176 | }
177 |
178 | id POPBox(VectorConstRef vec, POPValueType type, bool force)
179 | {
180 | if (NULL == vec)
181 | return nil;
182 |
183 | switch (type) {
184 | case kPOPValueInteger:
185 | case kPOPValueFloat:
186 | return @(vec->data()[0]);
187 | break;
188 | case kPOPValuePoint:
189 | return [NSValue valueWithCGPoint:vec->cg_point()];
190 | break;
191 | case kPOPValueSize:
192 | return [NSValue valueWithCGSize:vec->cg_size()];
193 | break;
194 | case kPOPValueRect:
195 | return [NSValue valueWithCGRect:vec->cg_rect()];
196 | break;
197 | case kPOPValueColor: {
198 | return (__bridge_transfer id)vec->cg_color();
199 | break;
200 | }
201 | default:
202 | return force ? [NSValue valueWithCGPoint:vec->cg_point()] : nil;
203 | break;
204 | }
205 | }
206 |
207 | static VectorRef vectorize(id value, POPValueType type)
208 | {
209 | Vector *vec = NULL;
210 |
211 | switch (type) {
212 | case kPOPValueInteger:
213 | case kPOPValueFloat:
214 | vec = Vector::new_cg_float([value floatValue]);
215 | break;
216 | case kPOPValuePoint:
217 | vec = Vector::new_cg_point([value CGPointValue]);
218 | break;
219 | case kPOPValueSize:
220 | vec = Vector::new_cg_size([value CGSizeValue]);
221 | break;
222 | case kPOPValueRect:
223 | vec = Vector::new_cg_rect([value CGRectValue]);
224 | break;
225 | case kPOPValueAffineTransform:
226 | vec = Vector::new_cg_affine_transform([value CGAffineTransformValue]);
227 | break;
228 | case kPOPValueColor:
229 | vec = Vector::new_cg_color((__bridge CGColorRef)value);
230 | default:
231 | break;
232 | }
233 |
234 | return VectorRef(vec);
235 | }
236 |
237 | VectorRef POPUnbox(id value, POPValueType &animationType, NSUInteger &count, bool validate)
238 | {
239 | if (nil == value) {
240 | count = 0;
241 | return VectorRef(NULL);
242 | }
243 |
244 | // determine type of value
245 | POPValueType valueType = POPSelectValueType(value, kPOPAnimatableSupportTypes, POP_ARRAY_COUNT(kPOPAnimatableSupportTypes));
246 |
247 | // handle unknown types
248 | if (kPOPValueUnknown == valueType) {
249 | NSString *valueDesc = kPOPValueUnknown != valueType ? POPValueTypeToString(valueType) : [[value class] description];
250 | [NSException raise:@"Unsuported value" format:@"Animating %@ values is not supported", valueDesc];
251 | }
252 |
253 | // vectorize
254 | VectorRef vec = vectorize(value, valueType);
255 |
256 | if (kPOPValueUnknown == animationType || 0 == count) {
257 | // update animation type based on value type
258 | animationType = valueType;
259 | if (NULL != vec) {
260 | count = vec->size();
261 | }
262 | } else if (validate) {
263 | // allow for mismatched types, so long as vector size matches
264 | if (count != vec->size()) {
265 | [NSException raise:@"Invalid value" format:@"%@ should be of type %@", value, POPValueTypeToString(animationType)];
266 | }
267 | }
268 |
269 | return vec;
270 | }
271 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPAnimationTracer.h:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 |
12 | #import "POPAnimationEvent.h"
13 |
14 | @class POPAnimation;
15 |
16 | /**
17 | @abstract Tracer of animation events to fasciliate unit testing & debugging.
18 | */
19 | @interface POPAnimationTracer : NSObject
20 |
21 | /**
22 | @abstract Start recording events.
23 | */
24 | - (void)start;
25 |
26 | /**
27 | @abstract Stop recording events.
28 | */
29 | - (void)stop;
30 |
31 | /**
32 | @abstract Resets any recoded events. Continues recording events if already started.
33 | */
34 | - (void)reset;
35 |
36 | /**
37 | @abstract Property representing all recorded events.
38 | @discussion Events are returned in order of occurence.
39 | */
40 | @property (nonatomic, assign, readonly) NSArray *allEvents;
41 |
42 | /**
43 | @abstract Property representing all recorded write events for convenience.
44 | @discussion Events are returned in order of occurence.
45 | */
46 | @property (nonatomic, assign, readonly) NSArray *writeEvents;
47 |
48 | /**
49 | @abstract Queries for events of specified type.
50 | @param type The type of event to return.
51 | @returns An array of events of specified type in order of occurence.
52 | */
53 | - (NSArray *)eventsWithType:(POPAnimationEventType)type;
54 |
55 | /**
56 | @abstract Property indicating whether tracer should automatically log events and reset collection on animation completion.
57 | */
58 | @property (nonatomic, assign) BOOL shouldLogAndResetOnCompletion;
59 |
60 | @end
61 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPAnimationTracer.mm:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import "POPAnimationTracer.h"
11 |
12 | #import
13 |
14 | #import "POPAnimationEventInternal.h"
15 | #import "POPAnimationInternal.h"
16 | #import "POPSpringAnimation.h"
17 |
18 | @implementation POPAnimationTracer
19 | {
20 | __weak POPAnimation *_animation;
21 | POPAnimationState *_animationState;
22 | NSMutableArray *_events;
23 | BOOL _animationHasVelocity;
24 | }
25 |
26 | static POPAnimationEvent *create_event(POPAnimationTracer *self, POPAnimationEventType type, id value = nil, bool recordAnimation = false)
27 | {
28 | bool useLocalTime = 0 != self->_animationState->startTime;
29 | CFTimeInterval time = useLocalTime
30 | ? self->_animationState->lastTime - self->_animationState->startTime
31 | : self->_animationState->lastTime;
32 |
33 | POPAnimationEvent *event;
34 |
35 | if (!value) {
36 | event = [[POPAnimationEvent alloc] initWithType:type time:time];
37 | } else {
38 | event = [[POPAnimationValueEvent alloc] initWithType:type time:time value:value];
39 | if (self->_animationHasVelocity) {
40 | [(POPAnimationValueEvent *)event setVelocity:[(POPSpringAnimation *)self->_animation velocity]];
41 | }
42 | }
43 |
44 | if (recordAnimation) {
45 | event.animationDescription = [self->_animation description];
46 | }
47 |
48 | return event;
49 | }
50 |
51 | - (id)initWithAnimation:(POPAnimation *)anAnim
52 | {
53 | self = [super init];
54 | if (nil != self) {
55 | _animation = anAnim;
56 | _animationState = POPAnimationGetState(anAnim);
57 | _events = [[NSMutableArray alloc] initWithCapacity:50];
58 | _animationHasVelocity = [anAnim respondsToSelector:@selector(velocity)];
59 | }
60 | return self;
61 | }
62 |
63 | - (void)readPropertyValue:(id)aValue
64 | {
65 | POPAnimationEvent *event = create_event(self, kPOPAnimationEventPropertyRead, aValue);
66 | [_events addObject:event];
67 | }
68 |
69 | - (void)writePropertyValue:(id)aValue
70 | {
71 | POPAnimationEvent *event = create_event(self, kPOPAnimationEventPropertyWrite, aValue);
72 | [_events addObject:event];
73 | }
74 |
75 | - (void)updateToValue:(id)aValue
76 | {
77 | POPAnimationEvent *event = create_event(self, kPOPAnimationEventToValueUpdate, aValue);
78 | [_events addObject:event];
79 | }
80 |
81 | - (void)updateFromValue:(id)aValue
82 | {
83 | POPAnimationEvent *event = create_event(self, kPOPAnimationEventFromValueUpdate, aValue);
84 | [_events addObject:event];
85 | }
86 |
87 | - (void)updateVelocity:(id)aValue
88 | {
89 | POPAnimationEvent *event = create_event(self, kPOPAnimationEventVelocityUpdate, aValue);
90 | [_events addObject:event];
91 | }
92 |
93 | - (void)updateSpeed:(float)aFloat
94 | {
95 | POPAnimationEvent *event = create_event(self, kPOPAnimationEventSpeedUpdate, @(aFloat));
96 | [_events addObject:event];
97 | }
98 |
99 | - (void)updateBounciness:(float)aFloat
100 | {
101 | POPAnimationEvent *event = create_event(self, kPOPAnimationEventBouncinessUpdate, @(aFloat));
102 | [_events addObject:event];
103 | }
104 |
105 | - (void)updateFriction:(float)aFloat
106 | {
107 | POPAnimationEvent *event = create_event(self, kPOPAnimationEventFrictionUpdate, @(aFloat));
108 | [_events addObject:event];
109 | }
110 |
111 | - (void)updateMass:(float)aFloat
112 | {
113 | POPAnimationEvent *event = create_event(self, kPOPAnimationEventMassUpdate, @(aFloat));
114 | [_events addObject:event];
115 | }
116 |
117 | - (void)updateTension:(float)aFloat
118 | {
119 | POPAnimationEvent *event = create_event(self, kPOPAnimationEventTensionUpdate, @(aFloat));
120 | [_events addObject:event];
121 | }
122 |
123 | - (void)didStart
124 | {
125 | POPAnimationEvent *event = create_event(self, kPOPAnimationEventDidStart, nil, true);
126 | [_events addObject:event];
127 | }
128 |
129 | - (void)didStop:(BOOL)finished
130 | {
131 | POPAnimationEvent *event = create_event(self, kPOPAnimationEventDidStop, @(finished), true);
132 | [_events addObject:event];
133 |
134 | if (_shouldLogAndResetOnCompletion) {
135 | NSLog(@"events:%@", self.allEvents);
136 | [self reset];
137 | }
138 | }
139 |
140 | - (void)didReachToValue:(id)aValue
141 | {
142 | POPAnimationEvent *event = create_event(self, kPOPAnimationEventDidReachToValue, aValue);
143 | [_events addObject:event];
144 | }
145 |
146 | - (void)start
147 | {
148 | POPAnimationState *s = POPAnimationGetState(_animation);
149 | s->tracing = true;
150 | }
151 |
152 | - (void)stop
153 | {
154 | POPAnimationState *s = POPAnimationGetState(_animation);
155 | s->tracing = false;
156 | }
157 |
158 | - (void)reset
159 | {
160 | [_events removeAllObjects];
161 | }
162 |
163 | - (NSArray *)allEvents
164 | {
165 | return [_events copy];
166 | }
167 |
168 | - (NSArray *)writeEvents
169 | {
170 | return [self eventsWithType:kPOPAnimationEventPropertyWrite];
171 | }
172 |
173 | - (NSArray *)eventsWithType:(POPAnimationEventType)aType
174 | {
175 | NSMutableArray *array = [NSMutableArray array];
176 | for (POPAnimationEvent *event in _events) {
177 | if (aType == event.type) {
178 | [array addObject:event];
179 | }
180 | }
181 | return array;
182 | }
183 |
184 | @end
185 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPAnimationTracerInternal.h:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 |
12 | #import "POPAnimationTracer.h"
13 |
14 | @interface POPAnimationTracer (Internal)
15 |
16 | /**
17 | @abstract Designated initalizer. Pass the animation being traced.
18 | */
19 | - (instancetype)initWithAnimation:(POPAnimation *)anAnim;
20 |
21 | /**
22 | @abstract Records read value.
23 | */
24 | - (void)readPropertyValue:(id)aValue;
25 |
26 | /**
27 | @abstract Records write value.
28 | */
29 | - (void)writePropertyValue:(id)aValue;
30 |
31 | /**
32 | Records to value update.
33 | */
34 | - (void)updateToValue:(id)aValue;
35 |
36 | /**
37 | @abstract Records from value update.
38 | */
39 | - (void)updateFromValue:(id)aValue;
40 |
41 | /**
42 | @abstract Records from value update.
43 | */
44 | - (void)updateVelocity:(id)aValue;
45 |
46 | /**
47 | @abstract Records bounciness update.
48 | */
49 | - (void)updateBounciness:(float)aFloat;
50 |
51 | /**
52 | @abstract Records speed update.
53 | */
54 | - (void)updateSpeed:(float)aFloat;
55 |
56 | /**
57 | @abstract Records friction update.
58 | */
59 | - (void)updateFriction:(float)aFloat;
60 |
61 | /**
62 | @abstract Records mass update.
63 | */
64 | - (void)updateMass:(float)aFloat;
65 |
66 | /**
67 | @abstract Records tension update.
68 | */
69 | - (void)updateTension:(float)aFloat;
70 |
71 | /**
72 | @abstract Records did add.
73 | */
74 | - (void)didAdd;
75 |
76 | /**
77 | @abstract Records did start.
78 | */
79 | - (void)didStart;
80 |
81 | /**
82 | @abstract Records did stop.
83 | */
84 | - (void)didStop:(BOOL)finished;
85 |
86 | /**
87 | @abstract Records did reach to value.
88 | */
89 | - (void)didReachToValue:(id)aValue;
90 |
91 | @end
92 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPAnimator.h:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 |
12 | @protocol POPAnimatorDelegate;
13 |
14 | /**
15 | @abstract The animator class renders animations.
16 | */
17 | @interface POPAnimator : NSObject
18 |
19 | /**
20 | @abstract The shared animator instance.
21 | @discussion Consumers should generally use the shared instance in lieu of creating new instances.
22 | */
23 | + (instancetype)sharedAnimator;
24 |
25 | /**
26 | @abstract The optional animator delegate.
27 | */
28 | @property (weak, nonatomic) id delegate;
29 |
30 | @end
31 |
32 | /**
33 | @abstract The animator delegate.
34 | */
35 | @protocol POPAnimatorDelegate
36 |
37 | /**
38 | @abstract Called on each frame before animation application.
39 | */
40 | - (void)animatorWillAnimate:(POPAnimator *)animator;
41 |
42 | /**
43 | @abstract Called on each frame after animation application.
44 | */
45 | - (void)animatorDidAnimate:(POPAnimator *)animator;
46 |
47 | @end
48 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPAnimator.mm:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import "POPAnimator.h"
11 | #import "POPAnimatorPrivate.h"
12 |
13 | #import
14 | #import
15 | #import
16 |
17 | #import
18 |
19 | #import "POPAnimation.h"
20 | #import "POPAnimationExtras.h"
21 | #import "POPAnimationInternal.h"
22 | #import "POPAnimationRuntime.h"
23 | #import "POPBasicAnimationInternal.h"
24 | #import "POPDecayAnimationInternal.h"
25 | #import "POPSpringAnimationInternal.h"
26 | #import "POPSpringSolver.h"
27 |
28 | using namespace std;
29 | using namespace POP;
30 |
31 | #define ENABLE_LOGGING_DEBUG 0
32 | #define ENABLE_LOGGING_INFO 0
33 |
34 | #if ENABLE_LOGGING_DEBUG
35 | #define FBLogAnimDebug NSLog
36 | #else
37 | #define FBLogAnimDebug(...)
38 | #endif
39 |
40 | #if ENABLE_LOGGING_INFO
41 | #define FBLogAnimInfo NSLog
42 | #else
43 | #define FBLogAnimInfo(...)
44 | #endif
45 |
46 | class POPAnimatorItem
47 | {
48 | public:
49 | id __weak object;
50 | NSString *key;
51 | POPAnimation *animation;
52 | NSInteger refCount;
53 | id __unsafe_unretained unretainedObject;
54 |
55 | POPAnimatorItem(id o, NSString *k, POPAnimation *a) POP_NOTHROW
56 | {
57 | object = o;
58 | key = [k copy];
59 | animation = a;
60 | refCount = 1;
61 | unretainedObject = o;
62 | }
63 |
64 | ~POPAnimatorItem()
65 | {
66 | }
67 |
68 | bool operator==(const POPAnimatorItem& o) const {
69 | return unretainedObject == o.unretainedObject && animation == o.animation && [key isEqualToString:o.key];
70 | }
71 |
72 | };
73 |
74 | typedef std::shared_ptr POPAnimatorItemRef;
75 | typedef std::shared_ptr POPAnimatorItemConstRef;
76 |
77 | typedef std::list POPAnimatorItemList;
78 | typedef POPAnimatorItemList::iterator POPAnimatorItemListIterator;
79 | typedef POPAnimatorItemList::const_iterator POPAnimatorItemListConstIterator;
80 |
81 | static BOOL _disableBackgroundThread = YES;
82 |
83 | @interface POPAnimator ()
84 | {
85 | #if TARGET_OS_IPHONE
86 | CADisplayLink *_displayLink;
87 | #else
88 | CVDisplayLinkRef _displayLink;
89 | #endif
90 | POPAnimatorItemList _list;
91 | CFMutableDictionaryRef _dict;
92 | NSMutableSet *_observers;
93 | CFTimeInterval _slowMotionStartTime;
94 | CFTimeInterval _slowMotionLastTime;
95 | CFTimeInterval _slowMotionAccumulator;
96 | }
97 | @end
98 |
99 | @implementation POPAnimator
100 |
101 | #if !TARGET_OS_IPHONE
102 | static CVReturn displayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp *now, const CVTimeStamp *outputTime, CVOptionFlags flagsIn, CVOptionFlags *flagsOut, void *context)
103 | {
104 | if (_disableBackgroundThread) {
105 | dispatch_async(dispatch_get_main_queue(), ^{
106 | [(__bridge POPAnimator*)context render];
107 | });
108 | } else {
109 | [(__bridge POPAnimator*)context render];
110 | }
111 | return kCVReturnSuccess;
112 | }
113 | #endif
114 |
115 | static void updateAnimating(POPAnimator *self)
116 | {
117 | BOOL paused = 0 == self->_observers.count && self->_list.empty();
118 |
119 | #if TARGET_OS_IPHONE
120 | if (paused != self->_displayLink.paused) {
121 | FBLogAnimInfo(paused ? @"pausing display link" : @"unpausing display link");
122 | self->_displayLink.paused = paused;
123 | }
124 | #else
125 | if (paused == CVDisplayLinkIsRunning(self->_displayLink)) {
126 | FBLogAnimInfo(paused ? @"pausing display link" : @"unpausing display link");
127 | if (paused) {
128 | CVDisplayLinkStop(self->_displayLink);
129 | } else {
130 | CVDisplayLinkStart(self->_displayLink);
131 | }
132 | }
133 | #endif
134 | }
135 |
136 | static void updateAnimatable(id obj, POPPropertyAnimationState *anim)
137 | {
138 | // handle user-initiated stop or pause; hault animation
139 | if (!anim->active || anim->paused)
140 | return;
141 |
142 | if (anim->hasValue()) {
143 | pop_animatable_write_block write = anim->property.writeBlock;
144 | if (NULL == write)
145 | return;
146 |
147 | if (!anim->additive) {
148 |
149 | VectorRef currentVec = anim->currentValue();
150 |
151 | // update previous values; support animation convergence
152 | anim->previous2Vec = anim->previousVec;
153 | anim->previousVec = currentVec;
154 |
155 | // write value
156 | write(obj, currentVec->data());
157 | if (anim->tracing) {
158 | [anim->tracer writePropertyValue:POPBox(currentVec, anim->valueType, true)];
159 | }
160 | } else {
161 | pop_animatable_read_block read = anim->property.readBlock;
162 | if (NULL == read)
163 | return;
164 |
165 | // object value
166 | Vector4r objectValue = read_values(read, obj, anim->valueCount);
167 |
168 | // current animation value
169 | VectorRef currentVec = anim->currentValue();
170 | Vector4r currentValue = currentVec->vector4r();
171 |
172 | // determine animation change
173 | if (anim->previousVec) {
174 | Vector4r previousValue = anim->previousVec->vector4r();
175 | currentValue -= previousValue;
176 | }
177 |
178 | // add to object value
179 | currentValue += objectValue;
180 |
181 | // update previous values; support animation convergence
182 | anim->previous2Vec = anim->previousVec;
183 | anim->previousVec = currentVec;
184 |
185 | // write value
186 | write(obj, currentValue.data());
187 | if (anim->tracing) {
188 | [anim->tracer writePropertyValue:POPBox(currentVec, anim->valueType, true)];
189 | }
190 | }
191 | }
192 | }
193 |
194 | static void applyAnimationTime(id obj, POPAnimationState *state, CFTimeInterval time)
195 | {
196 | if (!state->advanceTime(time, obj)) {
197 | return;
198 | }
199 |
200 | POPPropertyAnimationState *ps = dynamic_cast(state);
201 | if (NULL != ps) {
202 | updateAnimatable(obj, ps);
203 | }
204 |
205 | state->delegateApply();
206 | }
207 |
208 | static void applyAnimationProgress(id obj, POPAnimationState *state, CGFloat progress)
209 | {
210 | POPPropertyAnimationState *ps = dynamic_cast(state);
211 | if (ps && !ps->advanceProgress(progress)) {
212 | return;
213 | }
214 |
215 | if (NULL != ps) {
216 | updateAnimatable(obj, ps);
217 | }
218 |
219 | state->delegateApply();
220 | }
221 |
222 | static POPAnimation *deleteDictEntry(POPAnimator *self, id __unsafe_unretained obj, NSString *key, BOOL cleanup = YES)
223 | {
224 | NSMutableDictionary *animations = (__bridge id)CFDictionaryGetValue(self->_dict, (__bridge void *)obj);
225 | if (nil == animations)
226 | return nil;
227 |
228 | POPAnimation *anim = animations[key];
229 | if (nil == anim)
230 | return nil;
231 |
232 | // remove key
233 | [animations removeObjectForKey:key];
234 |
235 | // cleanup empty dictionaries
236 | if (cleanup && 0 == animations.count)
237 | CFDictionaryRemoveValue(self->_dict, (__bridge void *)obj);
238 |
239 | return anim;
240 | }
241 |
242 | static void stopAndCleanup(POPAnimator *self, POPAnimatorItemRef item, bool shouldRemove, bool finished)
243 | {
244 | // remove
245 | if (shouldRemove) {
246 | deleteDictEntry(self, item->unretainedObject, item->key);
247 | }
248 |
249 | // stop
250 | POPAnimationState *state = POPAnimationGetState(item->animation);
251 | state->stop(shouldRemove, finished);
252 |
253 | if (shouldRemove) {
254 | // find item im list
255 | // may have already been removed on animationDidStop:
256 | POPAnimatorItemListIterator find_iter = find(self->_list.begin(), self->_list.end(), item);
257 | BOOL found = find_iter != self->_list.end();
258 |
259 | if (found) {
260 | self->_list.erase(find_iter);
261 | }
262 | }
263 | }
264 |
265 | + (id)sharedAnimator
266 | {
267 | static POPAnimator* _animator = nil;
268 | static dispatch_once_t onceToken;
269 | dispatch_once(&onceToken, ^{
270 | _animator = [[POPAnimator alloc] init];
271 | });
272 | return _animator;
273 | }
274 |
275 | + (BOOL)disableBackgroundThread
276 | {
277 | return _disableBackgroundThread;
278 | }
279 |
280 | + (void)setDisableBackgroundThread:(BOOL)flag
281 | {
282 | _disableBackgroundThread = flag;
283 | }
284 |
285 | - (id)init
286 | {
287 | self = [super init];
288 | if (nil == self) return nil;
289 |
290 | #if TARGET_OS_IPHONE
291 | _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(render)];
292 | _displayLink.paused = YES;
293 | [_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
294 | #else
295 | CVReturn ret = CVDisplayLinkCreateWithActiveCGDisplays(&_displayLink);
296 | ret = CVDisplayLinkSetOutputCallback(_displayLink, displayLinkCallback, (__bridge void *)self);
297 | #endif
298 |
299 | _dict = POPDictionaryCreateMutableWeakPointerToStrongObject(5);
300 |
301 | return self;
302 | }
303 |
304 | - (void)dealloc
305 | {
306 | #if TARGET_OS_IPHONE
307 | [_displayLink invalidate];
308 | #else
309 | CVDisplayLinkStop(_displayLink);
310 | CVDisplayLinkRelease(_displayLink);
311 | #endif
312 | }
313 |
314 | - (void)addAnimation:(POPAnimation *)anim forObject:(id)obj key:(NSString *)key
315 | {
316 | if (!anim || !obj) {
317 | return;
318 | }
319 |
320 | // support arbitrarily many nil keys
321 | if (!key) {
322 | key = [[NSUUID UUID] UUIDString];
323 | }
324 |
325 | NSMutableDictionary *animations = (__bridge id)CFDictionaryGetValue(_dict, (__bridge void *)obj);
326 |
327 | // update associated animation state
328 | if (nil == animations) {
329 | animations = [NSMutableDictionary dictionary];
330 | CFDictionarySetValue(_dict, (__bridge void *)obj, (__bridge void *)animations);
331 | } else {
332 | // if the animation instance already exists, avoid cancelling only to restart
333 | POPAnimation *existingAnim = animations[key];
334 | if (existingAnim) {
335 | if (existingAnim == anim) {
336 | return;
337 | }
338 | [self removeAnimationForObject:obj key:key cleanupDict:NO];
339 | }
340 | }
341 | animations[key] = anim;
342 |
343 | // create entry after potential removal
344 | POPAnimatorItemRef item(new POPAnimatorItem(obj, key, anim));
345 | _list.push_back(item);
346 |
347 | // support animation re-use, reset all animation state
348 | POPAnimationGetState(anim)->reset(true);
349 |
350 | // start animating if necessary
351 | updateAnimating(self);
352 | }
353 |
354 | - (void)removeAllAnimationsForObject:(id)obj
355 | {
356 | NSArray *animations = [(__bridge id)CFDictionaryGetValue(_dict, (__bridge void *)obj) allValues];
357 | CFDictionaryRemoveValue(_dict, (__bridge void *)obj);
358 |
359 | if (0 == animations.count)
360 | return;
361 |
362 | NSHashTable *animationSet = [[NSHashTable alloc] initWithOptions:NSHashTableObjectPointerPersonality capacity:animations.count];
363 | for (id animation in animations) {
364 | [animationSet addObject:animation];
365 | }
366 |
367 | POPAnimatorItemRef item;
368 | for (auto iter = _list.begin(); iter != _list.end();) {
369 | item = *iter;
370 | if(![animationSet containsObject:item->animation]) {
371 | iter++;
372 | } else {
373 | POPAnimationState *state = POPAnimationGetState(item->animation);
374 | state->stop(true, !state->active);
375 | iter = _list.erase(iter);
376 | }
377 | }
378 |
379 |
380 | for (POPAnimation *anim in animations) {
381 | POPAnimationState *state = POPAnimationGetState(anim);
382 | state->stop(true, !state->active);
383 | }
384 | }
385 |
386 | - (void)removeAnimationForObject:(id)obj key:(NSString *)key cleanupDict:(BOOL)cleanupDict
387 | {
388 | POPAnimation *anim = deleteDictEntry(self, obj, key, cleanupDict);
389 | if (nil == anim)
390 | return;
391 |
392 | POPAnimatorItemRef item;
393 | for (auto iter = _list.begin(); iter != _list.end();) {
394 | item = *iter;
395 | if(anim == item->animation) {
396 | POPAnimationState *state = POPAnimationGetState(item->animation);
397 | state->stop(true, (!state->active && !state->paused));
398 | iter = _list.erase(iter);
399 | break;
400 | } else {
401 | iter++;
402 | }
403 | }
404 | }
405 |
406 | - (void)removeAnimationForObject:(id)obj key:(NSString *)key
407 | {
408 | [self removeAnimationForObject:obj key:key cleanupDict:YES];
409 | }
410 |
411 | - (NSArray *)animationKeysForObject:(id)obj
412 | {
413 | NSArray *keys = [(__bridge id)CFDictionaryGetValue(_dict, (__bridge void *)obj) allKeys];
414 | return keys;
415 | }
416 |
417 | - (id)animationForObject:(id)obj key:(NSString *)key
418 | {
419 | NSDictionary *animations = (__bridge id)CFDictionaryGetValue(_dict, (__bridge void *)obj);
420 | return animations[key];
421 | }
422 |
423 | - (void)render
424 | {
425 | CFTimeInterval time = CACurrentMediaTime();
426 |
427 | #if TARGET_IPHONE_SIMULATOR
428 | // support slow-motion animations
429 | time += _slowMotionAccumulator;
430 | float f = POPAnimationDragCoefficient();
431 |
432 | if (f > 1.0) {
433 | if (!_slowMotionStartTime) {
434 | _slowMotionStartTime = time;
435 | } else {
436 | time = (time - _slowMotionStartTime) / f + _slowMotionStartTime;
437 | _slowMotionLastTime = time;
438 | }
439 | } else if (_slowMotionStartTime) {
440 | CFTimeInterval dt = (_slowMotionLastTime - time);
441 | time += dt;
442 | _slowMotionAccumulator += dt;
443 | _slowMotionStartTime = 0;
444 | }
445 | #endif
446 |
447 | [self renderTime:time];
448 | }
449 |
450 | - (void)renderTime:(CFTimeInterval)time
451 | {
452 | [CATransaction begin];
453 | [CATransaction setDisableActions:YES];
454 |
455 | [_delegate animatorWillAnimate:self];
456 |
457 | const NSUInteger count = _list.size();
458 | if (0 != count) {
459 |
460 | std::vector vector{ std::begin(_list), std::end(_list) };
461 |
462 | id obj;
463 | POPAnimation *anim;
464 | POPAnimationState *state;
465 |
466 | for (auto item : vector) {
467 | obj = item->object;
468 | anim = item->animation;
469 | state = POPAnimationGetState(anim);
470 |
471 | if (nil == obj) {
472 |
473 | // object exists not; stop animating
474 | NSAssert(item->unretainedObject, @"object should exist");
475 | stopAndCleanup(self, item, true, false);
476 |
477 | } else {
478 | // start if needed
479 | state->startIfNeeded(obj, time);
480 |
481 | // only run active, not paused animations
482 | if (state->active && !state->paused) {
483 | // object exists; animate
484 | applyAnimationTime(obj, state, time);
485 |
486 | FBLogAnimDebug(@"time:%f running:%@", time, item->animation);
487 |
488 | if (state->isDone()) {
489 | // set end value
490 | applyAnimationProgress(obj, state, 1.0);
491 |
492 | // finished succesfully, cleanup
493 | stopAndCleanup(self, item, state->removedOnCompletion, YES);
494 | }
495 | }
496 | }
497 | }
498 | }
499 |
500 | for (id observer in _observers) {
501 | [observer animatorDidAnimate:(id)self];
502 | }
503 |
504 | updateAnimating(self);
505 | [_delegate animatorDidAnimate:self];
506 |
507 | [CATransaction commit];
508 | }
509 |
510 | - (void)addObserver:(id)observer
511 | {
512 | NSAssert([NSThread isMainThread], @"unexpected thread %@", [NSThread currentThread]);
513 | NSAssert(nil != observer, @"attempting to add nil %@ observer", self);
514 | if (nil == observer)
515 | return;
516 |
517 | NSMutableSet *observers = _observers ? [_observers mutableCopy] : [[NSMutableSet alloc] initWithCapacity:1];
518 | [observers addObject:observer];
519 | _observers = observers;
520 | updateAnimating(self);
521 | }
522 |
523 | - (void)removeObserver:(id)observer
524 | {
525 | NSAssert([NSThread isMainThread], @"unexpected thread %@", [NSThread currentThread]);
526 | NSAssert(nil != observer, @"attempting to remove nil %@ observer", self);
527 | if (nil == observer)
528 | return;
529 |
530 | NSMutableSet *observers = [_observers mutableCopy];
531 | [observers removeObject:observer];
532 | _observers = observers;
533 | updateAnimating(self);
534 | }
535 |
536 | @end
537 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPAnimatorPrivate.h:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import "POPAnimator.h"
11 |
12 | @class POPAnimation;
13 |
14 | @protocol POPAnimatorObserving
15 | @required
16 |
17 | /**
18 | @abstract Called on each observer after animator has advanced. Core Animation actions are disabled by default.
19 | */
20 | - (void)animatorDidAnimate:(POPAnimator *)animator;
21 |
22 | @end
23 |
24 | @interface POPAnimator ()
25 |
26 | #if !TARGET_OS_PHONE
27 | /**
28 | 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.
29 | */
30 | + (BOOL)disableBackgroundThread;
31 | + (void)setDisableBackgroundThread:(BOOL)flag;
32 | #endif
33 |
34 | /**
35 | Exposed for unit testing.
36 | */
37 | - (void)renderTime:(CFTimeInterval)time;
38 |
39 | /**
40 | Funnel methods for category additions.
41 | */
42 | - (void)addAnimation:(POPAnimation *)anim forObject:(id)obj key:(NSString *)key;
43 | - (void)removeAllAnimationsForObject:(id)obj;
44 | - (void)removeAnimationForObject:(id)obj key:(NSString *)key;
45 | - (NSArray *)animationKeysForObject:(id)obj;
46 | - (POPAnimation *)animationForObject:(id)obj key:(NSString *)key;
47 |
48 | /**
49 | @abstract Add an animator observer. Observer will be notified of each subsequent animator advance until removal.
50 | */
51 | - (void)addObserver:(id)observer;
52 |
53 | /**
54 | @abstract Remove an animator observer.
55 | */
56 | - (void)removeObserver:(id)observer;
57 |
58 | @end
59 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPBasicAnimation.h:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import "POPPropertyAnimation.h"
11 |
12 | /**
13 | @abstract A concrete basic animation class.
14 | @discussion Animation is achieved through interpolation.
15 | */
16 | @interface POPBasicAnimation : POPPropertyAnimation
17 |
18 | /**
19 | @abstract The designated initializer.
20 | @returns An instance of a basic animation.
21 | */
22 | + (instancetype)animation;
23 |
24 | /**
25 | @abstract Convenience initializer that returns an animation with animatable property of name.
26 | @param name The name of the animatable property.
27 | @returns An instance of a basic animation configured with specified animatable property.
28 | */
29 | + (instancetype)animationWithPropertyNamed:(NSString *)name;
30 |
31 | /**
32 | @abstract Convenience constructor.
33 | @returns Returns a basic animation with kCAMediaTimingFunctionDefault timing function.
34 | */
35 | + (instancetype)defaultAnimation;
36 |
37 | /**
38 | @abstract Convenience constructor.
39 | @returns Returns a basic animation with kCAMediaTimingFunctionLinear timing function.
40 | */
41 | + (instancetype)linearAnimation;
42 |
43 | /**
44 | @abstract Convenience constructor.
45 | @returns Returns a basic animation with kCAMediaTimingFunctionEaseIn timing function.
46 | */
47 | + (instancetype)easeInAnimation;
48 |
49 | /**
50 | @abstract Convenience constructor.
51 | @returns Returns a basic animation with kCAMediaTimingFunctionEaseOut timing function.
52 | */
53 | + (instancetype)easeOutAnimation;
54 |
55 | /**
56 | @abstract Convenience constructor.
57 | @returns Returns a basic animation with kCAMediaTimingFunctionEaseInEaseOut timing function.
58 | */
59 | + (instancetype)easeInEaseOutAnimation;
60 |
61 | /**
62 | @abstract The duration in seconds. Defaults to 0.4.
63 | */
64 | @property (assign, nonatomic) CFTimeInterval duration;
65 |
66 | /**
67 | @abstract A timing function defining the pacing of the animation. Defaults to nil indicating pacing according to kCAMediaTimingFunctionDefault.
68 | */
69 | @property (strong, nonatomic) CAMediaTimingFunction *timingFunction;
70 |
71 | @end
72 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPBasicAnimation.mm:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import "POPBasicAnimationInternal.h"
11 |
12 | @implementation POPBasicAnimation
13 |
14 | #undef __state
15 | #define __state ((POPBasicAnimationState *)_state)
16 |
17 | #pragma mark - Lifecycle
18 |
19 | + (instancetype)animation
20 | {
21 | return [[self alloc] init];
22 | }
23 |
24 | + (instancetype)animationWithPropertyNamed:(NSString *)aName
25 | {
26 | POPBasicAnimation *anim = [self animation];
27 | anim.property = [POPAnimatableProperty propertyWithName:aName];
28 | return anim;
29 | }
30 |
31 | - (void)_initState
32 | {
33 | _state = new POPBasicAnimationState(self);
34 | }
35 |
36 | + (instancetype)linearAnimation
37 | {
38 | POPBasicAnimation *anim = [self animation];
39 | anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
40 | return anim;
41 | }
42 |
43 | + (instancetype)easeInAnimation
44 | {
45 | POPBasicAnimation *anim = [self animation];
46 | anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
47 | return anim;
48 | }
49 |
50 | + (instancetype)easeOutAnimation
51 | {
52 | POPBasicAnimation *anim = [self animation];
53 | anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
54 | return anim;
55 | }
56 |
57 | + (instancetype)easeInEaseOutAnimation
58 | {
59 | POPBasicAnimation *anim = [self animation];
60 | anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
61 | return anim;
62 | }
63 |
64 | + (instancetype)defaultAnimation
65 | {
66 | POPBasicAnimation *anim = [self animation];
67 | anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault];
68 | return anim;
69 | }
70 |
71 | - (id)init
72 | {
73 | return [self _init];
74 | }
75 |
76 | #pragma mark - Properties
77 |
78 | DEFINE_RW_PROPERTY(POPBasicAnimationState, duration, setDuration:, CFTimeInterval);
79 | DEFINE_RW_PROPERTY_OBJ(POPBasicAnimationState, timingFunction, setTimingFunction:, CAMediaTimingFunction*, __state->updatedTimingFunction(););
80 |
81 | #pragma mark - Utility
82 |
83 | - (void)_appendDescription:(NSMutableString *)s debug:(BOOL)debug
84 | {
85 | [super _appendDescription:s debug:debug];
86 | if (__state->duration)
87 | [s appendFormat:@"; duration = %f", __state->duration];
88 | }
89 |
90 | @end
91 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPBasicAnimationInternal.h:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import "POPBasicAnimation.h"
11 | #import "POPPropertyAnimationInternal.h"
12 |
13 | // default animation duration
14 | static CGFloat kPOPAnimationDurationDefault = 0.4;
15 |
16 | static void interpolate(POPValueType valueType, NSUInteger count, const CGFloat *fromVec, const CGFloat *toVec, CGFloat *outVec, double p)
17 | {
18 | switch (valueType) {
19 | case kPOPValueInteger:
20 | case kPOPValueFloat:
21 | case kPOPValuePoint:
22 | case kPOPValueSize:
23 | case kPOPValueRect:
24 | interpolate_vector(count, outVec, fromVec, toVec, p);
25 | break;
26 | default:
27 | NSCAssert(false, @"unhandled type %d", valueType);
28 | break;
29 | }
30 | }
31 |
32 | struct _POPBasicAnimationState : _POPPropertyAnimationState
33 | {
34 | CAMediaTimingFunction *timingFunction;
35 | double timingControlPoints[4];
36 | CFTimeInterval duration;
37 |
38 | _POPBasicAnimationState(id __unsafe_unretained anim) : _POPPropertyAnimationState(anim),
39 | duration(kPOPAnimationDurationDefault),
40 | timingFunction(nil)
41 | {
42 | type = kPOPAnimationBasic;
43 | memset(timingControlPoints, 0, sizeof(timingControlPoints));
44 | }
45 |
46 | bool isDone() {
47 | if (_POPPropertyAnimationState::isDone()) {
48 | return true;
49 | }
50 | return _EQLF_(progress, 1., 1e-2);
51 | }
52 |
53 | void updatedTimingFunction()
54 | {
55 | float vec[4] = {0., 0., 0., 0.};
56 | [timingFunction getControlPointAtIndex:1 values:&vec[0]];
57 | [timingFunction getControlPointAtIndex:2 values:&vec[2]];
58 | for (NSUInteger idx = 0; idx < POP_ARRAY_COUNT(vec); idx++) {
59 | timingControlPoints[idx] = vec[idx];
60 | }
61 | }
62 |
63 | bool advance(CFTimeInterval time, CFTimeInterval dt, id obj) {
64 | // default timing function
65 | if (!timingFunction) {
66 | ((POPBasicAnimation *)self).timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault];
67 | }
68 |
69 | // cap local time to duration
70 | CFTimeInterval t = MIN(time - startTime, duration) / duration;
71 |
72 | // solve for normalized time, aka progresss [0, 1]
73 | double p = timing_function_solve(timingControlPoints, t, SOLVE_EPS(duration));
74 |
75 | // interpolate and advance
76 | if (p != progress) {
77 | interpolate(valueType, valueCount, fromVec->data(), toVec->data(), currentVec->data(), p);
78 | progress = p;
79 | return true;
80 | }
81 |
82 | clampCurrentValue();
83 |
84 | return false;
85 | }
86 | };
87 |
88 | typedef struct _POPBasicAnimationState POPBasicAnimationState;
89 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPCGUtils.h:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 | #import "POPDefines.h"
12 |
13 | #if TARGET_OS_IPHONE
14 | @class UIColor;
15 | #endif
16 |
17 | POP_EXTERN_C_BEGIN
18 |
19 | NS_INLINE CGPoint values_to_point(const CGFloat values[])
20 | {
21 | return CGPointMake(values[0], values[1]);
22 | }
23 |
24 | NS_INLINE CGSize values_to_size(const CGFloat values[])
25 | {
26 | return CGSizeMake(values[0], values[1]);
27 | }
28 |
29 | NS_INLINE CGRect values_to_rect(const CGFloat values[])
30 | {
31 | return CGRectMake(values[0], values[1], values[2], values[3]);
32 | }
33 |
34 | NS_INLINE void values_from_point(CGFloat values[], CGPoint p)
35 | {
36 | values[0] = p.x;
37 | values[1] = p.y;
38 | }
39 |
40 | NS_INLINE void values_from_size(CGFloat values[], CGSize s)
41 | {
42 | values[0] = s.width;
43 | values[1] = s.height;
44 | }
45 |
46 | NS_INLINE void values_from_rect(CGFloat values[], CGRect r)
47 | {
48 | values[0] = r.origin.x;
49 | values[1] = r.origin.y;
50 | values[2] = r.size.width;
51 | values[3] = r.size.height;
52 | }
53 |
54 | /**
55 | Takes a CGColorRef and converts it into RGBA components, if necessary.
56 | */
57 | extern void POPCGColorGetRGBAComponents(CGColorRef color, CGFloat components[]);
58 |
59 | /**
60 | Takes RGBA components and returns a CGColorRef.
61 | */
62 | extern CGColorRef POPCGColorRGBACreate(const CGFloat components[]) CF_RETURNS_RETAINED;
63 |
64 | #if TARGET_OS_IPHONE
65 |
66 | /**
67 | Takes a UIColor and converts it into RGBA components, if necessary.
68 | */
69 | extern void POPUIColorGetRGBAComponents(UIColor *color, CGFloat components[]);
70 |
71 | /**
72 | Takes RGBA components and returns a UIColor.
73 | */
74 | extern UIColor *POPUIColorRGBACreate(const CGFloat components[]) NS_RETURNS_RETAINED;
75 |
76 | #endif
77 |
78 | POP_EXTERN_C_END
79 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPCGUtils.mm:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import "POPCGUtils.h"
11 |
12 | #if TARGET_OS_IPHONE
13 | #import
14 | #else
15 | #import
16 | #endif
17 |
18 | void POPCGColorGetRGBAComponents(CGColorRef color, CGFloat components[])
19 | {
20 | if (!color) {
21 | #if TARGET_OS_IPHONE
22 | color = [UIColor clearColor].CGColor;
23 | #else
24 | color = [NSColor clearColor].CGColor;
25 | #endif
26 | }
27 |
28 | const CGFloat *colors = CGColorGetComponents(color);
29 | size_t count = CGColorGetNumberOfComponents(color);
30 |
31 | if (4 == count) {
32 | // RGB colorspace
33 | components[0] = colors[0];
34 | components[1] = colors[1];
35 | components[2] = colors[2];
36 | components[3] = colors[3];
37 | } else if (2 == count) {
38 | // Grey colorspace
39 | components[0] = components[1] = components[2] = colors[0];
40 | components[3] = colors[1];
41 | } else {
42 | // TODO HSV and CMYK conversion
43 | NSCAssert(NO, @"unsuported color space conversion, component count:%lu", count);
44 | }
45 | }
46 |
47 | CGColorRef POPCGColorRGBACreate(const CGFloat components[])
48 | {
49 | #if TARGET_OS_IPHONE
50 | CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
51 | CGColorRef color = CGColorCreate(space, components);
52 | CGColorSpaceRelease(space);
53 | return color;
54 | #else
55 | return CGColorCreateGenericRGB(components[0], components[1], components[2], components[3]);
56 | #endif
57 | }
58 |
59 | #if TARGET_OS_IPHONE
60 |
61 | void POPUIColorGetRGBAComponents(UIColor *color, CGFloat components[])
62 | {
63 | return POPCGColorGetRGBAComponents(color.CGColor, components);
64 | }
65 |
66 | UIColor *POPUIColorRGBACreate(const CGFloat components[])
67 | {
68 | CGColorRef colorRef = POPCGColorRGBACreate(components);
69 | UIColor *color = [[UIColor alloc] initWithCGColor:colorRef];
70 | CGColorRelease(colorRef);
71 | return color;
72 | }
73 |
74 | #endif
75 |
76 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPCustomAnimation.h:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import "POPAnimation.h"
11 |
12 | @class POPCustomAnimation;
13 |
14 | /**
15 | @abstract POPCustomAnimationBlock is the callback block of a custom animation.
16 | @discussion This block will be executed for each animation frame and should update the property or properties being animated based on current timing.
17 | @param target The object being animated. Reference the passed in target to help avoid retain loops.
18 | @param target 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.
19 | @return Flag indicating whether the animation should continue animating. Return NO to indicate animation is done.
20 | */
21 | typedef BOOL (^POPCustomAnimationBlock)(id target, POPCustomAnimation *animation);
22 |
23 | /**
24 | @abstract POPCustomAnimation is a concrete animation subclass for custom animations.
25 | */
26 | @interface POPCustomAnimation : POPAnimation
27 |
28 | /**
29 | @abstract Creates and returns an initialized custom animation instance.
30 | @discussion This is the designated initializer.
31 | @param block The custom animation callback block. See {@ref POPCustomAnimationBlock}.
32 | @return The initialized custom animation instance.
33 | */
34 | + (instancetype)animationWithBlock:(POPCustomAnimationBlock)block;
35 |
36 | /**
37 | @abstract The current animation time at time of callback.
38 | */
39 | @property (readonly, nonatomic) CFTimeInterval currentTime;
40 |
41 | /**
42 | @abstract The elapsed animation time since last callback.
43 | */
44 | @property (readonly, nonatomic) CFTimeInterval elapsedTime;
45 |
46 | @end
47 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPCustomAnimation.mm:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import "POPCustomAnimation.h"
11 | #import "POPAnimationInternal.h"
12 |
13 | @interface POPCustomAnimation ()
14 | @property (nonatomic, copy) POPCustomAnimationBlock animate;
15 | @end
16 |
17 | @implementation POPCustomAnimation
18 |
19 | + (instancetype)animationWithBlock:(BOOL(^)(id target, POPCustomAnimation *))block
20 | {
21 | POPCustomAnimation *b = [[self alloc] _init];
22 | b.animate = block;
23 | return b;
24 | }
25 |
26 | - (id)_init
27 | {
28 | self = [super _init];
29 | if (nil != self) {
30 | _state->type = kPOPAnimationCustom;
31 | }
32 | return self;
33 | }
34 |
35 | - (CFTimeInterval)beginTime
36 | {
37 | POPAnimationState *s = POPAnimationGetState(self);
38 | return s->startTime > 0 ? s->startTime : s->beginTime;
39 | }
40 |
41 | - (BOOL)_advance:(id)object currentTime:(CFTimeInterval)currentTime elapsedTime:(CFTimeInterval)elapsedTime
42 | {
43 | _currentTime = currentTime;
44 | _elapsedTime = elapsedTime;
45 | return _animate(object, self);
46 | }
47 |
48 | - (void)_appendDescription:(NSMutableString *)s debug:(BOOL)debug
49 | {
50 | [s appendFormat:@"; elapsedTime = %f; currentTime = %f;", _elapsedTime, _currentTime];
51 | }
52 |
53 | @end
54 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPDecayAnimation.h:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import "POPPropertyAnimation.h"
11 |
12 | /**
13 | @abstract A concrete decay animation class.
14 | @discussion Animation is achieved through gradual decay of animation value.
15 | */
16 | @interface POPDecayAnimation : POPPropertyAnimation
17 |
18 | /**
19 | @abstract The designated initializer.
20 | @returns An instance of a decay animation.
21 | */
22 | + (instancetype)animation;
23 |
24 | /**
25 | @abstract Convenience initializer that returns an animation with animatable property of name.
26 | @param name The name of the animatable property.
27 | @returns An instance of a decay animation configured with specified animatable property.
28 | */
29 | + (instancetype)animationWithPropertyNamed:(NSString *)name;
30 |
31 | /**
32 | @abstract The current velocity value.
33 | @discussion Set before animation start to account for initial velocity. Expressed in change of value units per second.
34 | */
35 | @property (copy, nonatomic) id velocity;
36 |
37 | /**
38 | @abstract The deceleration factor.
39 | @discussion Values specifies should be in the range [0, 1]. Lower values results in faster deceleration. Defaults to 0.998.
40 | */
41 | @property (assign, nonatomic) CGFloat deceleration;
42 |
43 | /**
44 | @abstract The expected duration.
45 | @discussion Derived based on input velocity and deceleration values.
46 | */
47 | @property (readonly, assign, nonatomic) CFTimeInterval duration;
48 |
49 | /**
50 | The to value is derived based on input velocity and deceleration.
51 | */
52 | - (void)setToValue:(id)toValue NS_UNAVAILABLE;
53 |
54 | @end
55 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPDecayAnimation.mm:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import "POPDecayAnimationInternal.h"
11 |
12 | @implementation POPDecayAnimation
13 |
14 | #pragma mark - Lifecycle
15 |
16 | #undef __state
17 | #define __state ((POPDecayAnimationState *)_state)
18 |
19 | + (instancetype)animation
20 | {
21 | return [[self alloc] init];
22 | }
23 |
24 | + (instancetype)animationWithPropertyNamed:(NSString *)aName
25 | {
26 | POPDecayAnimation *anim = [self animation];
27 | anim.property = [POPAnimatableProperty propertyWithName:aName];
28 | return anim;
29 | }
30 |
31 | - (id)init
32 | {
33 | return [self _init];
34 | }
35 |
36 | - (void)_initState
37 | {
38 | _state = new POPDecayAnimationState(self);
39 | }
40 |
41 | #pragma mark - Properties
42 |
43 | DEFINE_RW_PROPERTY(POPDecayAnimationState, deceleration, setDeceleration:, CGFloat, __state->toVec = NULL;);
44 |
45 | @dynamic velocity;
46 |
47 | - (id)toValue
48 | {
49 | [self _ensureComputedProperties];
50 | return POPBox(__state->toVec, __state->valueType);
51 | }
52 |
53 | - (CFTimeInterval)duration
54 | {
55 | [self _ensureComputedProperties];
56 | return __state->duration;
57 | }
58 |
59 | - (void)setFromValue:(id)fromValue
60 | {
61 | super.fromValue = fromValue;
62 | [self _invalidateComputedProperties];
63 | }
64 |
65 | - (void)setToValue:(id)aValue
66 | {
67 | // no-op
68 | NSLog(@"ignoring to value on decay animation %@", self);
69 | }
70 |
71 | - (id)velocity
72 | {
73 | return POPBox(__state->velocityVec, __state->valueType);
74 | }
75 |
76 | - (void)setVelocity:(id)aValue
77 | {
78 | VectorRef vec = POPUnbox(aValue, __state->valueType, __state->valueCount, YES);
79 |
80 | if (!vec_equal(vec, __state->velocityVec)) {
81 | __state->velocityVec = vec;
82 |
83 | if (__state->tracing) {
84 | [__state->tracer updateVelocity:aValue];
85 | }
86 |
87 | [self _invalidateComputedProperties];
88 |
89 | // automatically unpause active animations
90 | if (__state->active && __state->paused) {
91 | __state->fromVec = NULL;
92 | __state->setPaused(false);
93 | }
94 | }
95 | }
96 |
97 | #pragma mark - Utility
98 |
99 | - (void)_ensureComputedProperties
100 | {
101 | if (NULL == __state->toVec) {
102 | __state->computeDestinationValues();
103 | }
104 | }
105 |
106 | - (void)_invalidateComputedProperties
107 | {
108 | __state->toVec = NULL;
109 | __state->duration = 0;
110 | }
111 |
112 | - (void)_appendDescription:(NSMutableString *)s debug:(BOOL)debug
113 | {
114 | [super _appendDescription:s debug:debug];
115 |
116 | if (NULL != __state->toVec)
117 | [s appendFormat:@"; duration = %f", self.duration];
118 |
119 | if (__state->deceleration)
120 | [s appendFormat:@"; deceleration = %f", __state->deceleration];
121 | }
122 |
123 | @end
124 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPDecayAnimationInternal.h:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import "POPDecayAnimation.h"
11 | #import "POPPropertyAnimationInternal.h"
12 |
13 | // minimal velocity factor before decay animation is considered complete, in units / s
14 | static CGFloat kPOPAnimationDecayMinimalVelocityFactor = 5.;
15 |
16 | // default decay animation deceleration
17 | static CGFloat kPOPAnimationDecayDecelerationDefault = 0.998;
18 |
19 | static void decay_position(CGFloat *x, CGFloat *v, NSUInteger count, CFTimeInterval dt, CGFloat deceleration)
20 | {
21 | dt *= 1000;
22 |
23 | // v0 = v / 1000
24 | // v = v0 * powf(deceleration, dt);
25 | // v = v * 1000;
26 |
27 | // x0 = x;
28 | // x = x0 + v0 * deceleration * (1 - powf(deceleration, dt)) / (1 - deceleration)
29 | float v0[count];
30 | float kv = powf(deceleration, dt);
31 | float kx = deceleration * (1 - kv) / (1 - deceleration);
32 |
33 | for (NSUInteger idx = 0; idx < count; idx++) {
34 | v0[idx] = v[idx] / 1000.;
35 | v[idx] = v0[idx] * kv * 1000.;
36 | x[idx] = x[idx] + v0[idx] * kx;
37 | }
38 | }
39 |
40 | struct _POPDecayAnimationState : _POPPropertyAnimationState
41 | {
42 | double deceleration;
43 | CFTimeInterval duration;
44 |
45 | _POPDecayAnimationState(id __unsafe_unretained anim) :
46 | _POPPropertyAnimationState(anim),
47 | duration(0),
48 | deceleration(kPOPAnimationDecayDecelerationDefault) {
49 | type = kPOPAnimationDecay;
50 | }
51 |
52 | bool isDone() {
53 | if (_POPPropertyAnimationState::isDone()) {
54 | return true;
55 | }
56 |
57 | CGFloat f = dynamicsThreshold * kPOPAnimationDecayMinimalVelocityFactor;
58 | const CGFloat *velocityValues = vec_data(velocityVec);
59 | for (NSUInteger idx = 0; idx < valueCount; idx++) {
60 | if (fabsf(velocityValues[idx]) >= f)
61 | return false;
62 | }
63 | return true;
64 |
65 | }
66 |
67 | void computeDestinationValues() {
68 | // to value assuming final velocity as a factor of dynamics threshold
69 | // derived from v' = v * d^dt used in decay_position
70 | // to compute the to value with maximal dt, p' = p + (v * d) / (1 - d)
71 | VectorRef fromValue = NULL != currentVec ? currentVec : fromVec;
72 | if (!fromValue) {
73 | return;
74 | }
75 |
76 | VectorRef toValue(Vector::new_vector(fromValue.get()));
77 |
78 | // compute duration till threshold velocity
79 | Vector4r scaledVelocity = vector4(velocityVec) / 1000.;
80 |
81 | double k = dynamicsThreshold * kPOPAnimationDecayMinimalVelocityFactor / 1000.;
82 | double vx = k / scaledVelocity.x;
83 | double vy = k / scaledVelocity.y;
84 | double vz = k / scaledVelocity.z;
85 | double vw = k / scaledVelocity.w;
86 | double d = log(deceleration) * 1000.;
87 | duration = MAX(MAX(MAX(log(fabs(vx)) / d, log(fabs(vy)) / d), log(fabs(vz)) / d), log(fabs(vw)) / d);
88 |
89 | // ensure velocity threshold is exceeded
90 | if (isnan(duration) || duration < 0) {
91 | duration = 0;
92 | } else {
93 | // compute to value
94 | Vector4r velocity = velocityVec->vector4r();
95 | decay_position(toValue->data(), velocity.data(), valueCount, duration, deceleration);
96 | }
97 |
98 | toVec = toValue;
99 | }
100 |
101 | bool advance(CFTimeInterval time, CFTimeInterval dt, id obj) {
102 | // advance past not yet initialized animations
103 | if (NULL == currentVec) {
104 | return false;
105 | }
106 |
107 | decay_position(currentVec->data(), velocityVec->data(), valueCount, dt, deceleration);
108 |
109 | // clamp to compute end value; avoid possibility of decaying past
110 | clampCurrentValue(kPOPAnimationClampEnd | clampMode);
111 |
112 | return true;
113 | }
114 |
115 | };
116 |
117 | typedef struct _POPDecayAnimationState POPDecayAnimationState;
118 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPDefines.h:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #ifndef POP_POPDefines_h
11 | #define POP_POPDefines_h
12 |
13 | #ifdef __cplusplus
14 | # define POP_EXTERN_C_BEGIN extern "C" {
15 | # define POP_EXTERN_C_END }
16 | #else
17 | # define POP_EXTERN_C_BEGIN
18 | # define POP_EXTERN_C_END
19 | #endif
20 |
21 | #define POP_ARRAY_COUNT(x) sizeof(x) / sizeof(x[0])
22 |
23 | #if defined (__cplusplus) && defined (__GNUC__)
24 | # define POP_NOTHROW __attribute__ ((nothrow))
25 | #else
26 | # define POP_NOTHROW
27 | #endif
28 |
29 | #endif
30 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPGeometry.h:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 |
12 | #if TARGET_OS_IPHONE
13 | #import
14 | #endif
15 |
16 | #if !TARGET_OS_IPHONE
17 |
18 | /** NSValue extensions to support animatable types. */
19 | @interface NSValue (POP)
20 |
21 | /**
22 | @abstract Creates an NSValue given a CGPoint.
23 | */
24 | + (NSValue *)valueWithCGPoint:(CGPoint)point;
25 |
26 | /**
27 | @abstract Creates an NSValue given a CGSize.
28 | */
29 | + (NSValue *)valueWithCGSize:(CGSize)size;
30 |
31 | /**
32 | @abstract Creates an NSValue given a CGRect.
33 | */
34 | + (NSValue *)valueWithCGRect:(CGRect)rect;
35 |
36 | /**
37 | @abstract Returns the underlying CGPoint value.
38 | */
39 | - (CGPoint)CGPointValue;
40 |
41 | /**
42 | @abstract Returns the underlying CGSize value.
43 | */
44 | - (CGSize)CGSizeValue;
45 |
46 | /**
47 | @abstract Returns the underlying CGRect value.
48 | */
49 | - (CGRect)CGRectValue;
50 |
51 | @end
52 |
53 | #endif
54 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPGeometry.mm:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import "POPGeometry.h"
11 |
12 | #if !TARGET_OS_IPHONE
13 | @implementation NSValue (POP)
14 |
15 | + (NSValue *)valueWithCGPoint:(CGPoint)point {
16 | return [NSValue valueWithBytes:&point objCType:@encode(CGPoint)];
17 | }
18 |
19 | + (NSValue *)valueWithCGSize:(CGSize)size {
20 | return [NSValue valueWithBytes:&size objCType:@encode(CGSize)];
21 | }
22 |
23 | + (NSValue *)valueWithCGRect:(CGRect)rect {
24 | return [NSValue valueWithBytes:&rect objCType:@encode(CGRect)];
25 | }
26 |
27 | + (NSValue *)valueWithCFRange:(CFRange)range {
28 | return [NSValue valueWithBytes:&range objCType:@encode(CFRange)];
29 | }
30 |
31 | + (NSValue *)valueWithCGAffineTransform:(CGAffineTransform)transform
32 | {
33 | return [NSValue valueWithBytes:&transform objCType:@encode(CGAffineTransform)];
34 | }
35 |
36 | - (CGPoint)CGPointValue {
37 | CGPoint result;
38 | [self getValue:&result];
39 | return result;
40 | }
41 |
42 | - (CGSize)CGSizeValue {
43 | CGSize result;
44 | [self getValue:&result];
45 | return result;
46 | }
47 |
48 | - (CGRect)CGRectValue {
49 | CGRect result;
50 | [self getValue:&result];
51 | return result;
52 | }
53 |
54 | - (CFRange)CFRangeValue {
55 | CFRange result;
56 | [self getValue:&result];
57 | return result;
58 | }
59 |
60 | - (CGAffineTransform)CGAffineTransformValue {
61 | CGAffineTransform result;
62 | [self getValue:&result];
63 | return result;
64 | }
65 | @end
66 |
67 | #endif
68 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPLayerExtras.h:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 |
12 | #import "POPDefines.h"
13 |
14 | POP_EXTERN_C_BEGIN
15 |
16 | #pragma mark - Scale
17 |
18 | /**
19 | @abstract Returns layer scale factor for the x axis.
20 | */
21 | extern CGFloat POPLayerGetScaleX(CALayer *l);
22 |
23 | /**
24 | @abstract Set layer scale factor for the x axis.
25 | */
26 | extern void POPLayerSetScaleX(CALayer *l, CGFloat f);
27 |
28 | /**
29 | @abstract Returns layer scale factor for the y axis.
30 | */
31 | extern CGFloat POPLayerGetScaleY(CALayer *l);
32 |
33 | /**
34 | @abstract Set layer scale factor for the y axis.
35 | */
36 | extern void POPLayerSetScaleY(CALayer *l, CGFloat f);
37 |
38 | /**
39 | @abstract Returns layer scale factor for the z axis.
40 | */
41 | extern CGFloat POPLayerGetScaleZ(CALayer *l);
42 |
43 | /**
44 | @abstract Set layer scale factor for the z axis.
45 | */
46 | extern void POPLayerSetScaleZ(CALayer *l, CGFloat f);
47 |
48 | /**
49 | @abstract Returns layer scale factors for x and y access as point.
50 | */
51 | extern CGPoint POPLayerGetScaleXY(CALayer *l);
52 |
53 | /**
54 | @abstract Sets layer x and y scale factors given point.
55 | */
56 | extern void POPLayerSetScaleXY(CALayer *l, CGPoint p);
57 |
58 | #pragma mark - Translation
59 |
60 | /**
61 | @abstract Returns layer translation factor for the x axis.
62 | */
63 | extern CGFloat POPLayerGetTranslationX(CALayer *l);
64 |
65 | /**
66 | @abstract Set layer translation factor for the x axis.
67 | */
68 | extern void POPLayerSetTranslationX(CALayer *l, CGFloat f);
69 |
70 | /**
71 | @abstract Returns layer translation factor for the y axis.
72 | */
73 | extern CGFloat POPLayerGetTranslationY(CALayer *l);
74 |
75 | /**
76 | @abstract Set layer translation factor for the y axis.
77 | */
78 | extern void POPLayerSetTranslationY(CALayer *l, CGFloat f);
79 |
80 | /**
81 | @abstract Returns layer translation factor for the z axis.
82 | */
83 | extern CGFloat POPLayerGetTranslationZ(CALayer *l);
84 |
85 | /**
86 | @abstract Set layer translation factor for the z axis.
87 | */
88 | extern void POPLayerSetTranslationZ(CALayer *l, CGFloat f);
89 |
90 | /**
91 | @abstract Returns layer translation factors for x and y access as point.
92 | */
93 | extern CGPoint POPLayerGetTranslationXY(CALayer *l);
94 |
95 | /**
96 | @abstract Sets layer x and y translation factors given point.
97 | */
98 | extern void POPLayerSetTranslationXY(CALayer *l, CGPoint p);
99 |
100 | #pragma mark - Rotation
101 |
102 | /**
103 | @abstract Returns layer rotation, in radians, in the X axis.
104 | */
105 | extern CGFloat POPLayerGetRotationX(CALayer *l);
106 |
107 | /**
108 | @abstract Sets layer rotation, in radians, in the X axis.
109 | */
110 | extern void POPLayerSetRotationX(CALayer *l, CGFloat f);
111 |
112 | /**
113 | @abstract Returns layer rotation, in radians, in the Y axis.
114 | */
115 | extern CGFloat POPLayerGetRotationY(CALayer *l);
116 |
117 | /**
118 | @abstract Sets layer rotation, in radians, in the Y axis.
119 | */
120 | extern void POPLayerSetRotationY(CALayer *l, CGFloat f);
121 |
122 | /**
123 | @abstract Returns layer rotation, in radians, in the Z axis.
124 | */
125 | extern CGFloat POPLayerGetRotationZ(CALayer *l);
126 |
127 | /**
128 | @abstract Sets layer rotation, in radians, in the Z axis.
129 | */
130 | extern void POPLayerSetRotationZ(CALayer *l, CGFloat f);
131 |
132 | /**
133 | @abstract Returns layer rotation, in radians, in the Z axis.
134 | */
135 | extern CGFloat POPLayerGetRotation(CALayer *l);
136 |
137 | /**
138 | @abstract Sets layer rotation, in radians, in the Z axis.
139 | */
140 | extern void POPLayerSetRotation(CALayer *l, CGFloat f);
141 |
142 | #pragma mark - Sublayer Scale
143 |
144 | /**
145 | @abstract Returns sublayer scale factors for x and y access as point.
146 | */
147 | extern CGPoint POPLayerGetSubScaleXY(CALayer *l);
148 |
149 | /**
150 | @abstract Sets sublayer x and y scale factors given point.
151 | */
152 | extern void POPLayerSetSubScaleXY(CALayer *l, CGPoint p);
153 |
154 | #pragma mark - Sublayer Translation
155 |
156 | /**
157 | @abstract Returns sublayer translation factor for the x axis.
158 | */
159 | extern CGFloat POPLayerGetSubTranslationX(CALayer *l);
160 |
161 | /**
162 | @abstract Set sublayer translation factor for the x axis.
163 | */
164 | extern void POPLayerSetSubTranslationX(CALayer *l, CGFloat f);
165 |
166 | /**
167 | @abstract Returns sublayer translation factor for the y axis.
168 | */
169 | extern CGFloat POPLayerGetSubTranslationY(CALayer *l);
170 |
171 | /**
172 | @abstract Set sublayer translation factor for the y axis.
173 | */
174 | extern void POPLayerSetSubTranslationY(CALayer *l, CGFloat f);
175 |
176 | /**
177 | @abstract Returns sublayer translation factor for the z axis.
178 | */
179 | extern CGFloat POPLayerGetSubTranslationZ(CALayer *l);
180 |
181 | /**
182 | @abstract Set sublayer translation factor for the z axis.
183 | */
184 | extern void POPLayerSetSubTranslationZ(CALayer *l, CGFloat f);
185 |
186 | /**
187 | @abstract Returns sublayer translation factors for x and y access as point.
188 | */
189 | extern CGPoint POPLayerGetSubTranslationXY(CALayer *l);
190 |
191 | /**
192 | @abstract Sets sublayer x and y translation factors given point.
193 | */
194 | extern void POPLayerSetSubTranslationXY(CALayer *l, CGPoint p);
195 |
196 | POP_EXTERN_C_END
197 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPLayerExtras.mm:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import "POPLayerExtras.h"
11 |
12 | #include "TransformationMatrix.h"
13 |
14 | using namespace WebCore;
15 |
16 | #define DECOMPOSE_TRANSFORM(L) \
17 | TransformationMatrix _m(L.transform); \
18 | TransformationMatrix::DecomposedType _d; \
19 | _m.decompose(_d);
20 |
21 | #define RECOMPOSE_TRANSFORM(L) \
22 | _m.recompose(_d); \
23 | L.transform = _m.transform3d();
24 |
25 | #define RECOMPOSE_ROT_TRANSFORM(L) \
26 | _m.recompose(_d, true); \
27 | L.transform = _m.transform3d();
28 |
29 | #define DECOMPOSE_SUBLAYER_TRANSFORM(L) \
30 | TransformationMatrix _m(L.sublayerTransform); \
31 | TransformationMatrix::DecomposedType _d; \
32 | _m.decompose(_d);
33 |
34 | #define RECOMPOSE_SUBLAYER_TRANSFORM(L) \
35 | _m.recompose(_d); \
36 | L.sublayerTransform = _m.transform3d();
37 |
38 | #pragma mark - Scale
39 |
40 | CGFloat POPLayerGetScaleX(CALayer *l)
41 | {
42 | DECOMPOSE_TRANSFORM(l);
43 | return _d.scaleX;
44 | }
45 |
46 | void POPLayerSetScaleX(CALayer *l, CGFloat f)
47 | {
48 | DECOMPOSE_TRANSFORM(l);
49 | _d.scaleX = f;
50 | RECOMPOSE_TRANSFORM(l);
51 | }
52 |
53 | CGFloat POPLayerGetScaleY(CALayer *l)
54 | {
55 | DECOMPOSE_TRANSFORM(l);
56 | return _d.scaleY;
57 | }
58 |
59 | void POPLayerSetScaleY(CALayer *l, CGFloat f)
60 | {
61 | DECOMPOSE_TRANSFORM(l);
62 | _d.scaleY = f;
63 | RECOMPOSE_TRANSFORM(l);
64 | }
65 |
66 | CGFloat POPLayerGetScaleZ(CALayer *l)
67 | {
68 | DECOMPOSE_TRANSFORM(l);
69 | return _d.scaleZ;
70 | }
71 |
72 | void POPLayerSetScaleZ(CALayer *l, CGFloat f)
73 | {
74 | DECOMPOSE_TRANSFORM(l);
75 | _d.scaleZ = f;
76 | RECOMPOSE_TRANSFORM(l);
77 | }
78 |
79 | CGPoint POPLayerGetScaleXY(CALayer *l)
80 | {
81 | DECOMPOSE_TRANSFORM(l);
82 | return CGPointMake(_d.scaleX, _d.scaleY);
83 | }
84 |
85 | void POPLayerSetScaleXY(CALayer *l, CGPoint p)
86 | {
87 | DECOMPOSE_TRANSFORM(l);
88 | _d.scaleX = p.x;
89 | _d.scaleY = p.y;
90 | RECOMPOSE_TRANSFORM(l);
91 | }
92 |
93 | #pragma mark - Translation
94 |
95 | CGFloat POPLayerGetTranslationX(CALayer *l)
96 | {
97 | DECOMPOSE_TRANSFORM(l);
98 | return _d.translateX;
99 | }
100 |
101 | void POPLayerSetTranslationX(CALayer *l, CGFloat f)
102 | {
103 | DECOMPOSE_TRANSFORM(l);
104 | _d.translateX = f;
105 | RECOMPOSE_TRANSFORM(l);
106 | }
107 |
108 | CGFloat POPLayerGetTranslationY(CALayer *l)
109 | {
110 | DECOMPOSE_TRANSFORM(l);
111 | return _d.translateY;
112 | }
113 |
114 | void POPLayerSetTranslationY(CALayer *l, CGFloat f)
115 | {
116 | DECOMPOSE_TRANSFORM(l);
117 | _d.translateY = f;
118 | RECOMPOSE_TRANSFORM(l);
119 | }
120 |
121 | CGFloat POPLayerGetTranslationZ(CALayer *l)
122 | {
123 | DECOMPOSE_TRANSFORM(l);
124 | return _d.translateZ;
125 | }
126 |
127 | void POPLayerSetTranslationZ(CALayer *l, CGFloat f)
128 | {
129 | DECOMPOSE_TRANSFORM(l);
130 | _d.translateZ = f;
131 | RECOMPOSE_TRANSFORM(l);
132 | }
133 |
134 | CGPoint POPLayerGetTranslationXY(CALayer *l)
135 | {
136 | DECOMPOSE_TRANSFORM(l);
137 | return CGPointMake(_d.translateX, _d.translateY);
138 | }
139 |
140 | void POPLayerSetTranslationXY(CALayer *l, CGPoint p)
141 | {
142 | DECOMPOSE_TRANSFORM(l);
143 | _d.translateX = p.x;
144 | _d.translateY = p.y;
145 | RECOMPOSE_TRANSFORM(l);
146 | }
147 |
148 | #pragma mark - Rotation
149 |
150 | CGFloat POPLayerGetRotationX(CALayer *l)
151 | {
152 | DECOMPOSE_TRANSFORM(l);
153 | return _d.rotateX;
154 | }
155 |
156 | void POPLayerSetRotationX(CALayer *l, CGFloat f)
157 | {
158 | DECOMPOSE_TRANSFORM(l);
159 | _d.rotateX = f;
160 | RECOMPOSE_ROT_TRANSFORM(l);
161 | }
162 |
163 | CGFloat POPLayerGetRotationY(CALayer *l)
164 | {
165 | DECOMPOSE_TRANSFORM(l);
166 | return _d.rotateY;
167 | }
168 |
169 | void POPLayerSetRotationY(CALayer *l, CGFloat f)
170 | {
171 | DECOMPOSE_TRANSFORM(l);
172 | _d.rotateY = f;
173 | RECOMPOSE_ROT_TRANSFORM(l);
174 | }
175 |
176 | CGFloat POPLayerGetRotationZ(CALayer *l)
177 | {
178 | DECOMPOSE_TRANSFORM(l);
179 | return _d.rotateZ;
180 | }
181 |
182 | void POPLayerSetRotationZ(CALayer *l, CGFloat f)
183 | {
184 | DECOMPOSE_TRANSFORM(l);
185 | _d.rotateZ = f;
186 | RECOMPOSE_ROT_TRANSFORM(l);
187 | }
188 |
189 | CGFloat POPLayerGetRotation(CALayer *l)
190 | {
191 | return POPLayerGetRotationZ(l);
192 | }
193 |
194 | void POPLayerSetRotation(CALayer *l, CGFloat f)
195 | {
196 | POPLayerSetRotationZ(l, f);
197 | }
198 |
199 | #pragma mark - Sublayer Scale
200 |
201 | CGPoint POPLayerGetSubScaleXY(CALayer *l)
202 | {
203 | DECOMPOSE_SUBLAYER_TRANSFORM(l);
204 | return CGPointMake(_d.scaleX, _d.scaleY);
205 | }
206 |
207 | void POPLayerSetSubScaleXY(CALayer *l, CGPoint p)
208 | {
209 | DECOMPOSE_SUBLAYER_TRANSFORM(l);
210 | _d.scaleX = p.x;
211 | _d.scaleY = p.y;
212 | RECOMPOSE_SUBLAYER_TRANSFORM(l);
213 | }
214 |
215 | #pragma mark - Sublayer Translation
216 |
217 | extern CGFloat POPLayerGetSubTranslationX(CALayer *l)
218 | {
219 | DECOMPOSE_SUBLAYER_TRANSFORM(l);
220 | return _d.translateX;
221 | }
222 |
223 | extern void POPLayerSetSubTranslationX(CALayer *l, CGFloat f)
224 | {
225 | DECOMPOSE_SUBLAYER_TRANSFORM(l);
226 | _d.translateX = f;
227 | RECOMPOSE_SUBLAYER_TRANSFORM(l);
228 | }
229 |
230 | extern CGFloat POPLayerGetSubTranslationY(CALayer *l)
231 | {
232 | DECOMPOSE_SUBLAYER_TRANSFORM(l);
233 | return _d.translateY;
234 | }
235 |
236 | extern void POPLayerSetSubTranslationY(CALayer *l, CGFloat f)
237 | {
238 | DECOMPOSE_SUBLAYER_TRANSFORM(l);
239 | _d.translateY = f;
240 | RECOMPOSE_SUBLAYER_TRANSFORM(l);
241 | }
242 |
243 | extern CGFloat POPLayerGetSubTranslationZ(CALayer *l)
244 | {
245 | DECOMPOSE_SUBLAYER_TRANSFORM(l);
246 | return _d.translateZ;
247 | }
248 |
249 | extern void POPLayerSetSubTranslationZ(CALayer *l, CGFloat f)
250 | {
251 | DECOMPOSE_SUBLAYER_TRANSFORM(l);
252 | _d.translateZ = f;
253 | RECOMPOSE_SUBLAYER_TRANSFORM(l);
254 | }
255 |
256 | extern CGPoint POPLayerGetSubTranslationXY(CALayer *l)
257 | {
258 | DECOMPOSE_SUBLAYER_TRANSFORM(l);
259 | return CGPointMake(_d.translateX, _d.translateY);
260 | }
261 |
262 | extern void POPLayerSetSubTranslationXY(CALayer *l, CGPoint p)
263 | {
264 | DECOMPOSE_SUBLAYER_TRANSFORM(l);
265 | _d.translateX = p.x;
266 | _d.translateY = p.y;
267 | RECOMPOSE_SUBLAYER_TRANSFORM(l);
268 | }
269 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPMath.h:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 | #import
12 |
13 | #import "POPDefines.h"
14 |
15 | #import "POPVector.h"
16 |
17 | NS_INLINE CGFloat sqrtr(CGFloat f)
18 | {
19 | #if CGFLOAT_IS_DOUBLE
20 | return sqrt(f);
21 | #else
22 | return sqrtf(f);
23 | #endif
24 | }
25 |
26 | // round to nearest sub; pass 2.0 to round to every 0.5 (eg: retina pixels)
27 | NS_INLINE CGFloat POPSubRound(CGFloat f, CGFloat sub)
28 | {
29 | return round(f * sub) / sub;
30 | }
31 |
32 | #define MIX(a, b, f) ((a) + (f) * ((b) - (a)))
33 |
34 | // the longer the duration, the higher the necessary precision
35 | #define SOLVE_EPS(dur) (1. / (1000. * (dur)))
36 |
37 | #define _EQLF_(x, y, epsilon) (fabsf ((x) - (y)) < epsilon)
38 |
39 | extern void interpolate_vector(NSUInteger count, CGFloat *dst, const CGFloat *from, const CGFloat *to, double f);
40 |
41 | extern double timing_function_solve(const double vec[4], double t, double eps);
42 |
43 | // quadratic mapping of t [0, 1] to [start, end]
44 | extern double quadratic_out_interpolation(double t, double start, double end);
45 |
46 | // normalize value to [0, 1] based on its range [startValue, endValue]
47 | extern double normalize(double value, double startValue, double endValue);
48 |
49 | // project a normalized value [0, 1] to a given range [start, end]
50 | extern double project_normal(double n, double start, double end);
51 |
52 | // solve a quadratic equation of the form a * x^2 + b * x + c = 0
53 | extern void quadratic_solve(CGFloat a, CGFloat b, CGFloat c, CGFloat &x1, CGFloat &x2);
54 |
55 | // for a given tension return the bouncy 3 friction that produces no bounce
56 | extern double b3_nobounce(double tension);
57 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPMath.mm:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import "POPMath.h"
11 | #import "UnitBezier.h"
12 | #import "POPAnimationPrivate.h"
13 |
14 | void interpolate_vector(NSUInteger count, CGFloat *dst, const CGFloat *from, const CGFloat *to, double f)
15 | {
16 | for (NSUInteger idx = 0; idx < count; idx++) {
17 | dst[idx] = MIX(from[idx], to[idx], f);
18 | }
19 | }
20 |
21 | double timing_function_solve(const double vec[4], double t, double eps)
22 | {
23 | WebCore::UnitBezier bezier(vec[0], vec[1], vec[2], vec[3]);
24 | return bezier.solve(t, eps);
25 | }
26 |
27 | double normalize(double value, double startValue, double endValue)
28 | {
29 | return (value - startValue) / (endValue - startValue);
30 | }
31 |
32 | double project_normal(double n, double start, double end)
33 | {
34 | return start + (n * (end - start));
35 | }
36 |
37 | static double linear_interpolation(double t, double start, double end)
38 | {
39 | return t * end + (1.f - t) * start;
40 | }
41 |
42 | double quadratic_out_interpolation(double t, double start, double end)
43 | {
44 | return linear_interpolation(2*t - t*t, start, end);
45 | }
46 |
47 | static double b3_friction1(double x)
48 | {
49 | return (0.0007 * pow(x, 3)) - (0.031 * pow(x, 2)) + 0.64 * x + 1.28;
50 | }
51 |
52 | static double b3_friction2(double x)
53 | {
54 | return (0.000044 * pow(x, 3)) - (0.006 * pow(x, 2)) + 0.36 * x + 2.;
55 | }
56 |
57 | static double b3_friction3(double x)
58 | {
59 | return (0.00000045 * pow(x, 3)) - (0.000332 * pow(x, 2)) + 0.1078 * x + 5.84;
60 | }
61 |
62 | double b3_nobounce(double tension)
63 | {
64 | double friction = 0;
65 | if (tension <= 18.) {
66 | friction = b3_friction1(tension);
67 | } else if (tension > 18 && tension <= 44) {
68 | friction = b3_friction2(tension);
69 | } else if (tension > 44) {
70 | friction = b3_friction3(tension);
71 | } else {
72 | assert(false);
73 | }
74 | return friction;
75 | }
76 |
77 | void quadratic_solve(CGFloat a, CGFloat b, CGFloat c, CGFloat &x1, CGFloat &x2)
78 | {
79 | CGFloat discriminant = sqrt(b * b - 4 * a * c);
80 | x1 = (-b + discriminant) / (2 * a);
81 | x2 = (-b - discriminant) / (2 * a);
82 | }
83 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPPropertyAnimation.h:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import "POPAnimatableProperty.h"
11 | #import "POPAnimation.h"
12 |
13 | /**
14 | @abstract Flags for clamping animation values.
15 | @discussion Animation values can optionally be clamped to avoid overshoot. kPOPAnimationClampStart ensures values are more than fromValue and kPOPAnimationClampEnd ensures values are less than toValue.
16 | */
17 | typedef NS_OPTIONS(NSUInteger, POPAnimationClampFlags)
18 | {
19 | kPOPAnimationClampNone = 0,
20 | kPOPAnimationClampStart = 1UL << 0,
21 | kPOPAnimationClampEnd = 1UL << 1,
22 | kPOPAnimationClampBoth = kPOPAnimationClampStart | kPOPAnimationClampEnd,
23 | };
24 |
25 | /**
26 | @abstract The semi-concrete property animation subclass.
27 | */
28 | @interface POPPropertyAnimation : POPAnimation
29 |
30 | /**
31 | @abstract The property to animate.
32 | */
33 | @property (strong, nonatomic) POPAnimatableProperty *property;
34 |
35 | /**
36 | @abstract The value to animate from.
37 | @discussion The value type should match the property. If unspecified, the value is initialized to the object's current value on animation start.
38 | */
39 | @property (copy, nonatomic) id fromValue;
40 |
41 | /**
42 | @abstract The value to animate to.
43 | @discussion The value type should match the property. If unspecified, the value is initialized to the object's current value on animation start.
44 | */
45 | @property (copy, nonatomic) id toValue;
46 |
47 | /**
48 | @abstract The rounding factor applied to the current animated value.
49 | @discussion Specify 1.0 to animate between integral values. Defaults to 0 meaning no rounding.
50 | */
51 | @property (assign, nonatomic) CGFloat roundingFactor;
52 |
53 | /**
54 | @abstract The clamp mode applied to the current animated value.
55 | @discussion See {@ref POPAnimationClampFlags} for possible values. Defaults to kPOPAnimationClampNone.
56 | */
57 | @property (assign, nonatomic) NSUInteger clampMode;
58 |
59 | /**
60 | @abstract The flag indicating whether values should be "added" each frame, rather than set.
61 | @discussion Addition may be type dependent. Defaults to NO.
62 | */
63 | @property (assign, nonatomic, getter = isAdditive) BOOL additive;
64 |
65 | @end
66 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPPropertyAnimation.mm:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import "POPPropertyAnimationInternal.h"
11 |
12 | @implementation POPPropertyAnimation
13 |
14 | #pragma mark - Lifecycle
15 |
16 | #undef __state
17 | #define __state ((POPPropertyAnimationState *)_state)
18 |
19 | - (void)_initState
20 | {
21 | _state = new POPPropertyAnimationState(self);
22 | }
23 |
24 | #pragma mark - Properties
25 |
26 | DEFINE_RW_FLAG(POPPropertyAnimationState, additive, isAdditive, setAdditive:);
27 | DEFINE_RW_PROPERTY(POPPropertyAnimationState, roundingFactor, setRoundingFactor:, CGFloat);
28 | DEFINE_RW_PROPERTY(POPPropertyAnimationState, clampMode, setClampMode:, NSUInteger);
29 | DEFINE_RW_PROPERTY_OBJ(POPPropertyAnimationState, property, setProperty:, POPAnimatableProperty*, ((POPPropertyAnimationState*)_state)->updatedDynamicsThreshold(););
30 | DEFINE_RW_PROPERTY_OBJ_COPY(POPPropertyAnimationState, progressMarkers, setProgressMarkers:, NSArray*, ((POPPropertyAnimationState*)_state)->updatedProgressMarkers(););
31 |
32 | - (id)fromValue
33 | {
34 | return POPBox(__state->fromVec, __state->valueType);
35 | }
36 |
37 | - (void)setFromValue:(id)aValue
38 | {
39 | POPPropertyAnimationState *s = __state;
40 | VectorRef vec = POPUnbox(aValue, s->valueType, s->valueCount, YES);
41 | if (!vec_equal(vec, s->fromVec)) {
42 | s->fromVec = vec;
43 |
44 | if (s->tracing) {
45 | [s->tracer updateFromValue:aValue];
46 | }
47 | }
48 | }
49 |
50 | - (id)toValue
51 | {
52 | return POPBox(__state->toVec, __state->valueType);
53 | }
54 |
55 | - (void)setToValue:(id)aValue
56 | {
57 | POPPropertyAnimationState *s = (POPPropertyAnimationState *)POPAnimationGetState(self);
58 | VectorRef vec = POPUnbox(aValue, s->valueType, s->valueCount, YES);
59 |
60 | if (!vec_equal(vec, s->toVec)) {
61 | s->toVec = vec;
62 |
63 | // invalidate to dependent state
64 | s->didReachToValue = false;
65 | s->distanceVec = NULL;
66 |
67 | if (s->tracing) {
68 | [s->tracer updateToValue:aValue];
69 | }
70 |
71 | // automatically unpause active animations
72 | if (s->active && s->paused) {
73 | s->setPaused(false);
74 | }
75 | }
76 | }
77 |
78 | - (id)currentValue
79 | {
80 | return POPBox(__state->currentValue(), __state->valueType);
81 | }
82 |
83 | #pragma mark - Utility
84 |
85 | - (void)_appendDescription:(NSMutableString *)s debug:(BOOL)debug
86 | {
87 | [s appendFormat:@"; from = %@; to = %@", describe(__state->fromVec), describe(__state->toVec)];
88 |
89 | if (_state->active)
90 | [s appendFormat:@"; currentValue = %@", describe(__state->currentValue())];
91 |
92 | if (__state->velocityVec && 0 != __state->velocityVec->norm())
93 | [s appendFormat:@"; velocity = %@", describe(__state->velocityVec)];
94 |
95 | if (!self.removedOnCompletion)
96 | [s appendFormat:@"; removedOnCompletion = %@", POPStringFromBOOL(self.removedOnCompletion)];
97 |
98 | if (__state->progressMarkers)
99 | [s appendFormat:@"; progressMarkers = [%@]", [__state->progressMarkers componentsJoinedByString:@", "]];
100 |
101 | if (_state->active)
102 | [s appendFormat:@"; progress = %f", __state->progress];
103 | }
104 |
105 | @end
106 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPPropertyAnimationInternal.h:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import "POPAnimationInternal.h"
11 | #import "POPPropertyAnimation.h"
12 |
13 | static void clampValue(CGFloat &value, CGFloat fromValue, CGFloat toValue, NSUInteger clamp)
14 | {
15 | BOOL increasing = (toValue > fromValue);
16 |
17 | // Clamp start of animation.
18 | if ((kPOPAnimationClampStart & clamp) &&
19 | ((increasing && (value < fromValue)) || (!increasing && (value > fromValue)))) {
20 | value = fromValue;
21 | }
22 |
23 | // Clamp end of animation.
24 | if ((kPOPAnimationClampEnd & clamp) &&
25 | ((increasing && (value > toValue)) || (!increasing && (value < toValue)))) {
26 | value = toValue;
27 | }
28 | }
29 |
30 | struct _POPPropertyAnimationState : _POPAnimationState
31 | {
32 | POPAnimatableProperty *property;
33 | POPValueType valueType;
34 | NSUInteger valueCount;
35 | VectorRef fromVec;
36 | VectorRef toVec;
37 | VectorRef currentVec;
38 | VectorRef previousVec;
39 | VectorRef previous2Vec;
40 | VectorRef velocityVec;
41 | VectorRef distanceVec;
42 | CGFloat roundingFactor;
43 | NSUInteger clampMode;
44 | NSArray *progressMarkers;
45 | POPProgressMarker *progressMarkerState;
46 | NSUInteger progressMarkerCount;
47 | NSUInteger nextProgressMarkerIdx;
48 | CGFloat dynamicsThreshold;
49 |
50 | _POPPropertyAnimationState(id __unsafe_unretained anim) : _POPAnimationState(anim),
51 | property(nil),
52 | valueType((POPValueType)0),
53 | valueCount(nil),
54 | fromVec(nullptr),
55 | toVec(nullptr),
56 | currentVec(nullptr),
57 | previousVec(nullptr),
58 | previous2Vec(nullptr),
59 | velocityVec(nullptr),
60 | distanceVec(nullptr),
61 | roundingFactor(0),
62 | clampMode(0),
63 | progressMarkers(nil),
64 | progressMarkerState(nil),
65 | progressMarkerCount(0),
66 | nextProgressMarkerIdx(0),
67 | dynamicsThreshold(0)
68 | {
69 | type = kPOPAnimationBasic;
70 | }
71 |
72 | ~_POPPropertyAnimationState()
73 | {
74 | if (progressMarkerState) {
75 | free(progressMarkerState);
76 | progressMarkerState = NULL;
77 | }
78 | }
79 |
80 | bool canProgress() {
81 | return hasValue();
82 | }
83 |
84 | bool shouldRound() {
85 | return 0 != roundingFactor;
86 | }
87 |
88 | bool hasValue() {
89 | return 0 != valueCount;
90 | }
91 |
92 | bool isDone() {
93 | // inherit done
94 | if (_POPAnimationState::isDone()) {
95 | return true;
96 | }
97 |
98 | // consider an animation with no values done
99 | if (!hasValue() && !isCustom()) {
100 | return true;
101 | }
102 |
103 | return false;
104 | }
105 |
106 | // returns a copy of the currentVec, rounding if needed
107 | VectorRef currentValue() {
108 | if (!shouldRound()) {
109 | return VectorRef(Vector::new_vector(currentVec.get()));
110 | } else {
111 | VectorRef vec = VectorRef(Vector::new_vector(currentVec.get()));
112 | vec->subRound(1 / roundingFactor);
113 | return vec;
114 | }
115 | }
116 |
117 | void resetProgressMarkerState()
118 | {
119 | for (NSUInteger idx = 0; idx < progressMarkerCount; idx++)
120 | progressMarkerState[idx].reached = false;
121 |
122 | nextProgressMarkerIdx = 0;
123 | }
124 |
125 | void updatedProgressMarkers()
126 | {
127 | if (progressMarkerState) {
128 | free(progressMarkerState);
129 | progressMarkerState = NULL;
130 | }
131 |
132 | progressMarkerCount = progressMarkers.count;
133 |
134 | if (0 != progressMarkerCount) {
135 | progressMarkerState = (POPProgressMarker *)malloc(progressMarkerCount * sizeof(POPProgressMarker));
136 | [progressMarkers enumerateObjectsUsingBlock:^(NSNumber *progressMarker, NSUInteger idx, BOOL *stop) {
137 | progressMarkerState[idx].reached = false;
138 | progressMarkerState[idx].progress = [progressMarker floatValue];
139 | }];
140 | }
141 |
142 | nextProgressMarkerIdx = 0;
143 | }
144 |
145 | virtual void updatedDynamicsThreshold()
146 | {
147 | dynamicsThreshold = property.threshold;
148 | }
149 |
150 | bool advanceProgress(CGFloat p)
151 | {
152 | bool advanced = progress != p;
153 | if (advanced) {
154 | progress = p;
155 | NSUInteger count = valueCount;
156 | VectorRef outVec(Vector::new_vector(count, NULL));
157 |
158 | if (1.0 == progress) {
159 | if (outVec && toVec) {
160 | *outVec = *toVec;
161 | }
162 | } else {
163 | interpolate_vector(count, vec_data(outVec), vec_data(fromVec), vec_data(toVec), progress);
164 | }
165 |
166 | currentVec = outVec;
167 | clampCurrentValue();
168 | delegateProgress();
169 | }
170 | return advanced;
171 | }
172 |
173 | void computeProgress() {
174 | if (!canProgress()) {
175 | return;
176 | }
177 |
178 | static ComputeProgressFunctor func;
179 | Vector4r v = vector4(currentVec);
180 | Vector4r f = vector4(fromVec);
181 | Vector4r t = vector4(toVec);
182 | progress = func(v, f, t);
183 | }
184 |
185 | void delegateProgress() {
186 | if (!canProgress()) {
187 | return;
188 | }
189 |
190 | if (delegateDidProgress && progressMarkerState) {
191 |
192 | while (nextProgressMarkerIdx < progressMarkerCount) {
193 | if (progress < progressMarkerState[nextProgressMarkerIdx].progress)
194 | break;
195 |
196 | if (!progressMarkerState[nextProgressMarkerIdx].reached) {
197 | ActionEnabler enabler;
198 | [delegate pop_animation:self didReachProgress:progressMarkerState[nextProgressMarkerIdx].progress];
199 | progressMarkerState[nextProgressMarkerIdx].reached = true;
200 | }
201 |
202 | nextProgressMarkerIdx++;
203 | }
204 | }
205 |
206 | if (!didReachToValue) {
207 | bool didReachToValue = false;
208 | if (0 == valueCount) {
209 | didReachToValue = true;
210 | } else {
211 | Vector4r distance = toVec->vector4r();
212 | distance -= currentVec->vector4r();
213 |
214 | if (0 == distance.squaredNorm()) {
215 | didReachToValue = true;
216 | } else {
217 | // components
218 | if (distanceVec) {
219 | didReachToValue = true;
220 | const CGFloat *distanceValues = distanceVec->data();
221 | for (NSUInteger idx = 0; idx < valueCount; idx++) {
222 | didReachToValue &= signbit(distance[idx]) != signbit(distanceValues[idx]);
223 | }
224 | }
225 | }
226 | }
227 |
228 | if (didReachToValue) {
229 | handleDidReachToValue();
230 | }
231 | }
232 | }
233 |
234 | void handleDidReachToValue() {
235 | didReachToValue = true;
236 |
237 | if (delegateDidReachToValue) {
238 | ActionEnabler enabler;
239 | [delegate pop_animationDidReachToValue:self];
240 | }
241 |
242 | if (tracing) {
243 | [tracer didReachToValue:POPBox(currentValue(), valueType, true)];
244 | }
245 | }
246 |
247 | void readObjectValue(VectorRef *ptrVec, id obj)
248 | {
249 | // use current object value as from value
250 | pop_animatable_read_block read = property.readBlock;
251 | if (NULL != read) {
252 |
253 | Vector4r vec = read_values(read, obj, valueCount);
254 | *ptrVec = VectorRef(Vector::new_vector(valueCount, vec));
255 |
256 | if (tracing) {
257 | [tracer readPropertyValue:POPBox(*ptrVec, valueType, true)];
258 | }
259 | }
260 | }
261 |
262 | virtual void willRun(bool started, id obj) {
263 | // ensure from value initialized
264 | if (NULL == fromVec) {
265 | readObjectValue(&fromVec, obj);
266 | }
267 |
268 | // ensure to value initialized
269 | if (NULL == toVec) {
270 | // compute decay to value
271 | if (kPOPAnimationDecay == type) {
272 | [self toValue];
273 | } else {
274 | // read to value
275 | readObjectValue(&toVec, obj);
276 | }
277 | }
278 |
279 | // handle one time value initialization on start
280 | if (started) {
281 |
282 | // initialize current vec
283 | if (!currentVec) {
284 | currentVec = VectorRef(Vector::new_vector(valueCount, NULL));
285 |
286 | // initialize current value with from value
287 | // only do this on initial creation to avoid overwriting current value
288 | // on paused animation continuation
289 | if (currentVec && fromVec) {
290 | *currentVec = *fromVec;
291 | }
292 | }
293 |
294 | // ensure velocity values
295 | if (!velocityVec) {
296 | velocityVec = VectorRef(Vector::new_vector(valueCount, NULL));
297 | }
298 | }
299 |
300 | // ensure distance value initialized
301 | // depends on current value set on one time start
302 | if (NULL == distanceVec) {
303 |
304 | // not yet started animations may not have from value
305 | VectorRef fromVec2 = NULL != currentVec ? currentVec : fromVec;
306 |
307 | if (fromVec2 && toVec) {
308 | Vector4r distance = toVec->vector4r();
309 | distance -= fromVec2->vector4r();
310 |
311 | if (0 != distance.squaredNorm()) {
312 | distanceVec = VectorRef(Vector::new_vector(valueCount, distance));
313 | }
314 | }
315 | }
316 | }
317 |
318 | virtual void reset(bool all) {
319 | _POPAnimationState::reset(all);
320 |
321 | if (all) {
322 | currentVec = NULL;
323 | previousVec = NULL;
324 | previous2Vec = NULL;
325 | }
326 | progress = 0;
327 | resetProgressMarkerState();
328 | didReachToValue = false;
329 | distanceVec = NULL;
330 | }
331 |
332 | void clampCurrentValue(NSUInteger clamp)
333 | {
334 | if (kPOPAnimationClampNone == clamp)
335 | return;
336 |
337 | // Clamp all vector values
338 | CGFloat *currentValues = currentVec->data();
339 | const CGFloat *fromValues = fromVec->data();
340 | const CGFloat *toValues = toVec->data();
341 |
342 | for (NSUInteger idx = 0; idx < valueCount; idx++) {
343 | clampValue(currentValues[idx], fromValues[idx], toValues[idx], clamp);
344 | }
345 | }
346 |
347 | void clampCurrentValue()
348 | {
349 | clampCurrentValue(clampMode);
350 | }
351 | };
352 |
353 | typedef struct _POPPropertyAnimationState POPPropertyAnimationState;
354 |
355 | @interface POPPropertyAnimation ()
356 |
357 | @end
358 |
359 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPSpringAnimation.h:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import "POPPropertyAnimation.h"
11 |
12 | /**
13 | @abstract A concrete spring animation class.
14 | @discussion Animation is achieved through modeling spring dynamics.
15 | */
16 | @interface POPSpringAnimation : POPPropertyAnimation
17 |
18 | /**
19 | @abstract The designated initializer.
20 | @returns An instance of a spring animation.
21 | */
22 | + (instancetype)animation;
23 |
24 | /**
25 | @abstract Convenience initializer that returns an animation with animatable property of name.
26 | @param name The name of the animatable property.
27 | @returns An instance of a spring animation configured with specified animatable property.
28 | */
29 | + (instancetype)animationWithPropertyNamed:(NSString *)name;
30 |
31 | /**
32 | @abstract The current velocity value.
33 | @discussion Set before animation start to account for initial velocity. Expressed in change of value units per second.
34 | */
35 | @property (copy, nonatomic) id velocity;
36 |
37 | /**
38 | @abstract The effective bounciness.
39 | @discussion Use in conjunction with 'springSpeed' to change animation effect. Values are converted into corresponding dynamics constants. Defined as a value in the range [0, 20]. Defaults to 4.
40 | */
41 | @property (assign, nonatomic) CGFloat springBounciness;
42 |
43 | /**
44 | @abstract The effective speed.
45 | @discussion Use in conjunction with 'springBounciness' to change animation effect. Values are converted into corresponding dynamics constants. Defined as a value in the range [0, 20]. Defaults to 12.
46 | */
47 | @property (assign, nonatomic) CGFloat springSpeed;
48 |
49 | /**
50 | @abstract The tension used in the dynamics simulation.
51 | @discussion Can be used over bounciness and speed for finer grain tweaking of animation effect.
52 | */
53 | @property (assign, nonatomic) CGFloat dynamicsTension;
54 |
55 | /**
56 | @abstract The friction used in the dynamics simulation.
57 | @discussion Can be used over bounciness and speed for finer grain tweaking of animation effect.
58 | */
59 | @property (assign, nonatomic) CGFloat dynamicsFriction;
60 |
61 | /**
62 | @abstract The mass used in the dynamics simulation.
63 | @discussion Can be used over bounciness and speed for finer grain tweaking of animation effect.
64 | */
65 | @property (assign, nonatomic) CGFloat dynamicsMass;
66 |
67 | @end
68 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPSpringAnimation.mm:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import "POPSpringAnimationInternal.h"
11 |
12 | @implementation POPSpringAnimation
13 |
14 | #pragma mark - Lifecycle
15 |
16 | #undef __state
17 | #define __state ((POPSpringAnimationState *)_state)
18 |
19 | + (instancetype)animation
20 | {
21 | return [[self alloc] init];
22 | }
23 |
24 | + (instancetype)animationWithPropertyNamed:(NSString *)aName
25 | {
26 | POPSpringAnimation *anim = [self animation];
27 | anim.property = [POPAnimatableProperty propertyWithName:aName];
28 | return anim;
29 | }
30 |
31 | - (void)_initState
32 | {
33 | _state = new POPSpringAnimationState(self);
34 | }
35 |
36 | - (id)init
37 | {
38 | self = [super _init];
39 | if (nil != self) {
40 | __state->solver = new SpringSolver4d(1, 1, 1);
41 | __state->updatedDynamicsThreshold();
42 | __state->updatedBouncinessAndSpeed();
43 | }
44 | return self;
45 | }
46 |
47 | - (void)dealloc
48 | {
49 | if (__state) {
50 | delete __state->solver;
51 | __state->solver = NULL;
52 | }
53 | }
54 |
55 | #pragma mark - Properties
56 |
57 | - (id)velocity
58 | {
59 | return POPBox(__state->velocityVec, __state->valueType);
60 | }
61 |
62 | - (void)setVelocity:(id)aValue
63 | {
64 | POPPropertyAnimationState *s = __state;
65 | VectorRef vec = POPUnbox(aValue, s->valueType, s->valueCount, YES);
66 | if (!vec_equal(vec, s->velocityVec)) {
67 | s->velocityVec = vec;
68 |
69 | if (s->tracing) {
70 | [s->tracer updateVelocity:aValue];
71 | }
72 | }
73 | }
74 |
75 | DEFINE_RW_PROPERTY(POPSpringAnimationState, dynamicsTension, setDynamicsTension:, CGFloat, [self _updatedDynamicsTension];);
76 | DEFINE_RW_PROPERTY(POPSpringAnimationState, dynamicsFriction, setDynamicsFriction:, CGFloat, [self _updatedDynamicsFriction];);
77 | DEFINE_RW_PROPERTY(POPSpringAnimationState, dynamicsMass, setDynamicsMass:, CGFloat, [self _updatedDynamicsMass];);
78 |
79 | FB_PROPERTY_GET(POPSpringAnimationState, springSpeed, CGFloat);
80 | - (void)setSpringSpeed:(CGFloat)aFloat
81 | {
82 | POPSpringAnimationState *s = __state;
83 | if (s->userSpecifiedDynamics || aFloat != s->springSpeed) {
84 | s->springSpeed = aFloat;
85 | s->userSpecifiedDynamics = false;
86 | s->updatedBouncinessAndSpeed();
87 | if (s->tracing) {
88 | [s->tracer updateSpeed:aFloat];
89 | }
90 | }
91 | }
92 |
93 | FB_PROPERTY_GET(POPSpringAnimationState, springBounciness, CGFloat);
94 | - (void)setSpringBounciness:(CGFloat)aFloat
95 | {
96 | POPSpringAnimationState *s = __state;
97 | if (s->userSpecifiedDynamics || aFloat != s->springBounciness) {
98 | s->springBounciness = aFloat;
99 | s->userSpecifiedDynamics = false;
100 | s->updatedBouncinessAndSpeed();
101 | if (s->tracing) {
102 | [s->tracer updateBounciness:aFloat];
103 | }
104 | }
105 | }
106 |
107 | - (SpringSolver4d *)solver
108 | {
109 | return __state->solver;
110 | }
111 |
112 | - (void)setSolver:(SpringSolver4d *)aSolver
113 | {
114 | if (aSolver != __state->solver) {
115 | if (__state->solver) {
116 | delete(__state->solver);
117 | }
118 | __state->solver = aSolver;
119 | }
120 | }
121 |
122 | #pragma mark - Utility
123 |
124 | - (void)_updatedDynamicsTension
125 | {
126 | __state->userSpecifiedDynamics = true;
127 | if(__state->tracing) {
128 | [__state->tracer updateTension:__state->dynamicsTension];
129 | }
130 | __state->updatedDynamics();
131 | }
132 |
133 | - (void)_updatedDynamicsFriction
134 | {
135 | __state->userSpecifiedDynamics = true;
136 | if(__state->tracing) {
137 | [__state->tracer updateFriction:__state->dynamicsFriction];
138 | }
139 | __state->updatedDynamics();
140 | }
141 |
142 | - (void)_updatedDynamicsMass
143 | {
144 | __state->userSpecifiedDynamics = true;
145 | if(__state->tracing) {
146 | [__state->tracer updateMass:__state->dynamicsMass];
147 | }
148 | __state->updatedDynamics();
149 | }
150 |
151 | - (void)_appendDescription:(NSMutableString *)s debug:(BOOL)debug
152 | {
153 | [super _appendDescription:s debug:debug];
154 |
155 | if (debug) {
156 | if (_state->userSpecifiedDynamics) {
157 | [s appendFormat:@"; dynamics = (tension:%f, friction:%f, mass:%f)", __state->dynamicsTension, __state->dynamicsFriction, __state->dynamicsMass];
158 | } else {
159 | [s appendFormat:@"; bounciness = %f; speed = %f", __state->springBounciness, __state->springSpeed];
160 | }
161 | }
162 | }
163 |
164 | @end
165 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPSpringAnimationInternal.h:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import "POPAnimationExtras.h"
11 | #import "POPPropertyAnimationInternal.h"
12 | #import "POPSpringAnimation.h"
13 |
14 | struct _POPSpringAnimationState : _POPPropertyAnimationState
15 | {
16 | SpringSolver4d *solver;
17 | CGFloat springSpeed;
18 | CGFloat springBounciness; // normalized springiness
19 | CGFloat dynamicsTension; // tension
20 | CGFloat dynamicsFriction; // friction
21 | CGFloat dynamicsMass; // mass
22 |
23 | _POPSpringAnimationState(id __unsafe_unretained anim) : _POPPropertyAnimationState(anim),
24 | solver(nullptr),
25 | springSpeed(12.),
26 | springBounciness(4.),
27 | dynamicsTension(0),
28 | dynamicsFriction(0),
29 | dynamicsMass(0)
30 | {
31 | type = kPOPAnimationSpring;
32 | }
33 |
34 | bool hasConverged()
35 | {
36 | NSUInteger count = valueCount;
37 | if (shouldRound()) {
38 | return vec_equal(previous2Vec, previousVec) && vec_equal(previousVec, toVec);
39 | } else {
40 | if (!previousVec || !previous2Vec)
41 | return false;
42 |
43 | CGFloat t = dynamicsThreshold / 5;
44 |
45 | const CGFloat *toValues = toVec->data();
46 | const CGFloat *previousValues = previousVec->data();
47 | const CGFloat *previous2Values = previous2Vec->data();
48 |
49 | for (NSUInteger idx = 0; idx < count; idx++) {
50 | if ((fabsf(toValues[idx] - previousValues[idx]) >= t) || (fabsf(previous2Values[idx] - previousValues[idx]) >= t)) {
51 | return false;
52 | }
53 | }
54 | return true;
55 | }
56 | }
57 |
58 | bool isDone() {
59 | if (_POPPropertyAnimationState::isDone()) {
60 | return true;
61 | }
62 | return solver->started() && (hasConverged() || solver->hasConverged());
63 | }
64 |
65 | void updatedDynamics()
66 | {
67 | if (NULL != solver) {
68 | solver->setConstants(dynamicsTension, dynamicsFriction, dynamicsMass);
69 | }
70 | }
71 |
72 | void updatedDynamicsThreshold()
73 | {
74 | _POPPropertyAnimationState::updatedDynamicsThreshold();
75 | if (NULL != solver) {
76 | solver->setThreshold(dynamicsThreshold);
77 | }
78 | }
79 |
80 | void updatedBouncinessAndSpeed() {
81 | [POPSpringAnimation convertBounciness:springBounciness speed:springSpeed toTension:&dynamicsTension friction:&dynamicsFriction mass:&dynamicsMass];
82 | updatedDynamics();
83 | }
84 |
85 | bool advance(CFTimeInterval time, CFTimeInterval dt, id obj) {
86 | // advance past not yet initialized animations
87 | if (NULL == currentVec) {
88 | return false;
89 | }
90 |
91 | CFTimeInterval localTime = time - startTime;
92 |
93 | Vector4d value = vector4d(currentVec);
94 | Vector4d toValue = vector4d(toVec);
95 | Vector4d velocity = vector4d(velocityVec);
96 |
97 | SSState4d state;
98 | state.p = toValue - value;
99 |
100 | // the solver assumes a spring of size zero
101 | // flip the velocity from user perspective to solver perspective
102 | state.v = velocity * -1;
103 |
104 | solver->advance(state, localTime, dt);
105 | value = toValue - state.p;
106 |
107 | // flip velocity back to user perspective
108 | velocity = state.v * -1;
109 |
110 | *currentVec = value;
111 |
112 | if (velocityVec) {
113 | *velocityVec = velocity;
114 | }
115 |
116 | clampCurrentValue();
117 |
118 | return true;
119 | }
120 |
121 | virtual void reset(bool all) {
122 | _POPPropertyAnimationState::reset(all);
123 |
124 | if (solver) {
125 | solver->setConstants(dynamicsTension, dynamicsFriction, dynamicsMass);
126 | solver->reset();
127 | }
128 | }
129 | };
130 |
131 | typedef struct _POPSpringAnimationState POPSpringAnimationState;
132 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPSpringSolver.h:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 |
12 | #import "POPVector.h"
13 |
14 | namespace POP {
15 |
16 | template
17 | struct SSState
18 | {
19 | T p;
20 | T v;
21 | };
22 |
23 | template
24 | struct SSDerivative
25 | {
26 | T dp;
27 | T dv;
28 | };
29 |
30 | typedef SSState SSState4d;
31 | typedef SSDerivative SSDerivative4d;
32 |
33 | const CFTimeInterval solverDt = 0.001f;
34 | const CFTimeInterval maxSolverDt = 30.0f;
35 |
36 | /**
37 | Templated spring solver class.
38 | */
39 | template
40 | class SpringSolver
41 | {
42 | double _k; // stiffness
43 | double _b; // dampening
44 | double _m; // mass
45 |
46 | double _tp; // threshold
47 | double _tv; // threshold velocity
48 | double _ta; // threshold acceleration
49 |
50 | CFTimeInterval _accumulatedTime;
51 | SSState _lastState;
52 | T _lastDv;
53 | bool _started;
54 |
55 | public:
56 | SpringSolver(double k, double b, double m = 1) : _k(k), _b(b), _m(m), _started(false)
57 | {
58 | _accumulatedTime = 0;
59 | _lastState.p = T::Zero();
60 | _lastState.v = T::Zero();
61 | _lastDv = T::Zero();
62 | setThreshold(1.);
63 | }
64 |
65 | ~SpringSolver()
66 | {
67 | }
68 |
69 | bool started()
70 | {
71 | return _started;
72 | }
73 |
74 | void setConstants(double k, double b, double m)
75 | {
76 | _k = k;
77 | _b = b;
78 | _m = m;
79 | }
80 |
81 | void setThreshold(double t)
82 | {
83 | _tp = t / 2; // half a unit
84 | _tv = 25.0 * t; // 5 units per second, squared for comparison
85 | _ta = 625.0 * t * t; // 5 units per second squared, squared for comparison
86 | }
87 |
88 | T acceleration(const SSState &state, double t)
89 | {
90 | return state.p*(-_k/_m) - state.v*(_b/_m);
91 | }
92 |
93 | SSDerivative evaluate(const SSState &initial, double t)
94 | {
95 | SSDerivative output;
96 | output.dp = initial.v;
97 | output.dv = acceleration(initial, t);
98 | return output;
99 | }
100 |
101 | SSDerivative evaluate(const SSState &initial, double t, double dt, const SSDerivative &d)
102 | {
103 | SSState state;
104 | state.p = initial.p + d.dp*dt;
105 | state.v = initial.v + d.dv*dt;
106 | SSDerivative output;
107 | output.dp = state.v;
108 | output.dv = acceleration(state, t+dt);
109 | return output;
110 | }
111 |
112 | void integrate(SSState &state, double t, double dt)
113 | {
114 | SSDerivative a = evaluate(state, t);
115 | SSDerivative b = evaluate(state, t, dt*0.5, a);
116 | SSDerivative c = evaluate(state, t, dt*0.5, b);
117 | SSDerivative d = evaluate(state, t, dt, c);
118 |
119 | T dpdt = (a.dp + (b.dp + c.dp)*2.0 + d.dp) * (1.0/6.0);
120 | T dvdt = (a.dv + (b.dv + c.dv)*2.0 + d.dv) * (1.0/6.0);
121 |
122 | state.p = state.p + dpdt*dt;
123 | state.v = state.v + dvdt*dt;
124 |
125 | _lastDv = dvdt;
126 | }
127 |
128 | SSState interpolate(const SSState &previous, const SSState ¤t, double alpha)
129 | {
130 | SSState state;
131 | state.p = current.p*alpha + previous.p*(1-alpha);
132 | state.v = current.v*alpha + previous.v*(1-alpha);
133 | return state;
134 | }
135 |
136 | void advance(SSState &state, double t, double dt)
137 | {
138 | _started = true;
139 |
140 | if (dt > maxSolverDt) {
141 | // excessive time step, force shut down
142 | _lastDv = _lastState.v = _lastState.p = T::Zero();
143 | } else {
144 | _accumulatedTime += dt;
145 |
146 | SSState previousState = state, currentState = state;
147 | while (_accumulatedTime >= solverDt) {
148 | previousState = currentState;
149 | this->integrate(currentState, t, solverDt);
150 | t += solverDt;
151 | _accumulatedTime -= solverDt;
152 | }
153 | CFTimeInterval alpha = _accumulatedTime / solverDt;
154 | _lastState = state = this->interpolate(previousState, currentState, alpha);
155 | }
156 | }
157 |
158 | bool hasConverged()
159 | {
160 | if (!_started) {
161 | return false;
162 | }
163 |
164 | for (int idx = 0; idx < _lastState.p.size(); idx++) {
165 | if (fabs(_lastState.p(idx)) >= _tp) {
166 | return false;
167 | }
168 | }
169 |
170 | return (_lastState.v.squaredNorm() < _tv) && (_lastDv.squaredNorm() < _ta);
171 | }
172 |
173 | void reset()
174 | {
175 | _accumulatedTime = 0;
176 | _lastState.p = T::Zero();
177 | _lastState.v = T::Zero();
178 | _lastDv = T::Zero();
179 | _started = false;
180 | }
181 | };
182 |
183 | /**
184 | Convenience spring solver type definitions.
185 | */
186 | typedef SpringSolver SpringSolver2d;
187 | typedef SpringSolver SpringSolver3d;
188 | typedef SpringSolver SpringSolver4d;
189 | }
190 |
191 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPVector.h:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #ifndef __POP__FBVector__
11 | #define __POP__FBVector__
12 |
13 | #include
14 | #include
15 |
16 | #import
17 | #import
18 | #import "POPMath.h"
19 |
20 | namespace POP {
21 |
22 | /** Fixed two-size vector class */
23 | template
24 | struct Vector2
25 | {
26 | private:
27 | typedef T Vector2::* const _data[2];
28 | static const _data _v;
29 |
30 | public:
31 | T x;
32 | T y;
33 |
34 | // Zero vector
35 | static const Vector2 Zero() { return Vector2(0); }
36 |
37 | // Constructors
38 | Vector2() {}
39 | explicit Vector2(T v) { x = v; y = v; };
40 | explicit Vector2(T x0, T y0) : x(x0), y(y0) {};
41 | explicit Vector2(const CGPoint &p) : x(p.x), y (p.y) {}
42 | explicit Vector2(const CGSize &s) : x(s.width), y (s.height) {}
43 |
44 | // Copy constructor
45 | template explicit Vector2(const Vector2 &v) : x(v.x), y(v.y) {}
46 |
47 | // Index operators
48 | const T& operator[](size_t i) const { return this->*_v[i]; }
49 | T& operator[](size_t i) { return this->*_v[i]; }
50 | const T& operator()(size_t i) const { return this->*_v[i]; }
51 | T& operator()(size_t i) { return this->*_v[i]; }
52 |
53 | // Backing data
54 | T * data() { return &(this->*_v[0]); }
55 | const T * data() const { return &(this->*_v[0]); }
56 |
57 | // Size
58 | inline size_t size() const { return 2; }
59 |
60 | // Assignment
61 | Vector2 &operator= (T v) { x = v; y = v; return *this;}
62 | template Vector2 &operator= (const Vector2 &v) { x = v.x; y = v.y; return *this;}
63 |
64 | // Negation
65 | Vector2 operator- (void) const { return Vector2(-x, -y); }
66 |
67 | // Equality
68 | bool operator== (T v) const { return (x == v && y == v); }
69 | bool operator== (const Vector2 &v) const { return (x == v.x && y == v.y); }
70 |
71 | // Inequality
72 | bool operator!= (T v) const {return (x != v || y != v); }
73 | bool operator!= (const Vector2 &v) const { return (x != v.x || y != v.y); }
74 |
75 | // Scalar Math
76 | Vector2 operator+ (T v) const { return Vector2(x + v, y + v); }
77 | Vector2 operator- (T v) const { return Vector2(x - v, y - v); }
78 | Vector2 operator* (T v) const { return Vector2(x * v, y * v); }
79 | Vector2 operator/ (T v) const { return Vector2(x / v, y / v); }
80 | Vector2 &operator+= (T v) { x += v; y += v; return *this; };
81 | Vector2 &operator-= (T v) { x -= v; y -= v; return *this; };
82 | Vector2 &operator*= (T v) { x *= v; y *= v; return *this; };
83 | Vector2 &operator/= (T v) { x /= v; y /= v; return *this; };
84 |
85 | // Vector Math
86 | Vector2 operator+ (const Vector2 &v) const { return Vector2(x + v.x, y + v.y); }
87 | Vector2 operator- (const Vector2 &v) const { return Vector2(x - v.x, y - v.y); }
88 | Vector2 &operator+= (const Vector2 &v) { x += v.x; y += v.y; return *this; };
89 | Vector2 &operator-= (const Vector2 &v) { x -= v.x; y -= v.y; return *this; };
90 |
91 | // Norms
92 | CGFloat norm() const { return sqrtr(squaredNorm()); }
93 | CGFloat squaredNorm() const { return x * x + y * y; }
94 |
95 | // Cast
96 | template Vector2 cast() const { return Vector2(x, y); }
97 | CGPoint cg_point() const { return CGPointMake(x, y); };
98 | };
99 |
100 | template
101 | const typename Vector2::_data Vector2::_v = { &Vector2::x, &Vector2::y };
102 |
103 | /** Fixed three-size vector class */
104 | template
105 | struct Vector3
106 | {
107 | private:
108 | typedef T Vector3::* const _data[3];
109 | static const _data _v;
110 |
111 | public:
112 | T x;
113 | T y;
114 | T z;
115 |
116 | // Zero vector
117 | static const Vector3 Zero() { return Vector3(0); };
118 |
119 | // Constructors
120 | Vector3() {}
121 | explicit Vector3(T v) : x(v), y(v), z(v) {};
122 | explicit Vector3(T x0, T y0, T z0) : x(x0), y(y0), z(z0) {};
123 |
124 | // Copy constructor
125 | template explicit Vector3(const Vector3 &v) : x(v.x), y(v.y), z(v.z) {}
126 |
127 | // Index operators
128 | const T& operator[](size_t i) const { return this->*_v[i]; }
129 | T& operator[](size_t i) { return this->*_v[i]; }
130 | const T& operator()(size_t i) const { return this->*_v[i]; }
131 | T& operator()(size_t i) { return this->*_v[i]; }
132 |
133 | // Backing data
134 | T * data() { return &(this->*_v[0]); }
135 | const T * data() const { return &(this->*_v[0]); }
136 |
137 | // Size
138 | inline size_t size() const { return 3; }
139 |
140 | // Assignment
141 | Vector3 &operator= (T v) { x = v; y = v; z = v; return *this;}
142 | template Vector3 &operator= (const Vector3 &v) { x = v.x; y = v.y; z = v.z; return *this;}
143 |
144 | // Negation
145 | Vector3 operator- (void) const { return Vector3(-x, -y, -z); }
146 |
147 | // Equality
148 | bool operator== (T v) const { return (x == v && y == v && z = v); }
149 | bool operator== (const Vector3 &v) const { return (x == v.x && y == v.y && z == v.z); }
150 |
151 | // Inequality
152 | bool operator!= (T v) const {return (x != v || y != v || z != v); }
153 | bool operator!= (const Vector3 &v) const { return (x != v.x || y != v.y || z != v.z); }
154 |
155 | // Scalar Math
156 | Vector3 operator+ (T v) const { return Vector3(x + v, y + v, z + v); }
157 | Vector3 operator- (T v) const { return Vector3(x - v, y - v, z - v); }
158 | Vector3 operator* (T v) const { return Vector3(x * v, y * v, z * v); }
159 | Vector3 operator/ (T v) const { return Vector3(x / v, y / v, z / v); }
160 | Vector3 &operator+= (T v) { x += v; y += v; z += v; return *this; };
161 | Vector3 &operator-= (T v) { x -= v; y -= v; z -= v; return *this; };
162 | Vector3 &operator*= (T v) { x *= v; y *= v; z *= v; return *this; };
163 | Vector3 &operator/= (T v) { x /= v; y /= v; z /= v; return *this; };
164 |
165 | // Vector Math
166 | Vector3 operator+ (const Vector3 &v) const { return Vector3(x + v.x, y + v.y, z + v.z); }
167 | Vector3 operator- (const Vector3 &v) const { return Vector3(x - v.x, y - v.y, z - v.z); }
168 | Vector3 &operator+= (const Vector3 &v) { x += v.x; y += v.y; z += v.z; return *this; };
169 | Vector3 &operator-= (const Vector3 &v) { x -= v.x; y -= v.y; z -= v.z; return *this; };
170 |
171 | // Norms
172 | CGFloat norm() const { return sqrtr(squaredNorm()); }
173 | CGFloat squaredNorm() const { return x * x + y * y + z * z; }
174 |
175 | // Cast
176 | template Vector3 cast() const { return Vector3(x, y, z); }
177 | };
178 |
179 | template
180 | const typename Vector3::_data Vector3::_v = { &Vector3::x, &Vector3::y, &Vector3::z };
181 |
182 | /** Fixed four-size vector class */
183 | template
184 | struct Vector4
185 | {
186 | private:
187 | typedef T Vector4::* const _data[4];
188 | static const _data _v;
189 |
190 | public:
191 | T x;
192 | T y;
193 | T z;
194 | T w;
195 |
196 | // Zero vector
197 | static const Vector4 Zero() { return Vector4(0); };
198 |
199 | // Constructors
200 | Vector4() {}
201 | explicit Vector4(T v) : x(v), y(v), z(v), w(v) {};
202 | explicit Vector4(T x0, T y0, T z0, T w0) : x(x0), y(y0), z(z0), w(w0) {};
203 |
204 | // Copy constructor
205 | template explicit Vector4(const Vector4 &v) : x(v.x), y(v.y), z(v.z), w(v.w) {}
206 |
207 | // Index operators
208 | const T& operator[](size_t i) const { return this->*_v[i]; }
209 | T& operator[](size_t i) { return this->*_v[i]; }
210 | const T& operator()(size_t i) const { return this->*_v[i]; }
211 | T& operator()(size_t i) { return this->*_v[i]; }
212 |
213 | // Backing data
214 | T * data() { return &(this->*_v[0]); }
215 | const T * data() const { return &(this->*_v[0]); }
216 |
217 | // Size
218 | inline size_t size() const { return 4; }
219 |
220 | // Assignment
221 | Vector4 &operator= (T v) { x = v; y = v; z = v; w = v; return *this;}
222 | template Vector4 &operator= (const Vector4 &v) { x = v.x; y = v.y; z = v.z; w = v.w; return *this;}
223 |
224 | // Negation
225 | Vector4 operator- (void) const { return Vector4(-x, -y, -z, -w); }
226 |
227 | // Equality
228 | bool operator== (T v) const { return (x == v && y == v && z = v, w = v); }
229 | bool operator== (const Vector4 &v) const { return (x == v.x && y == v.y && z == v.z && w = v.w); }
230 |
231 | // Inequality
232 | bool operator!= (T v) const {return (x != v || y != v || z != v || w != v); }
233 | bool operator!= (const Vector4 &v) const { return (x != v.x || y != v.y || z != v.z || w != v.w); }
234 |
235 | // Scalar Math
236 | Vector4 operator+ (T v) const { return Vector4(x + v, y + v, z + v, w + v); }
237 | Vector4 operator- (T v) const { return Vector4(x - v, y - v, z - v, w - v); }
238 | Vector4 operator* (T v) const { return Vector4(x * v, y * v, z * v, w * v); }
239 | Vector4 operator/ (T v) const { return Vector4(x / v, y / v, z / v, w / v); }
240 | Vector4 &operator+= (T v) { x += v; y += v; z += v; w += v; return *this; };
241 | Vector4 &operator-= (T v) { x -= v; y -= v; z -= v; w -= v; return *this; };
242 | Vector4 &operator*= (T v) { x *= v; y *= v; z *= v; w *= v; return *this; };
243 | Vector4 &operator/= (T v) { x /= v; y /= v; z /= v; w /= v; return *this; };
244 |
245 | // Vector Math
246 | Vector4 operator+ (const Vector4 &v) const { return Vector4(x + v.x, y + v.y, z + v.z, w + v.w); }
247 | Vector4 operator- (const Vector4 &v) const { return Vector4(x - v.x, y - v.y, z - v.z, w - v.w); }
248 | Vector4 &operator+= (const Vector4 &v) { x += v.x; y += v.y; z += v.z; w += v.w; return *this; };
249 | Vector4 &operator-= (const Vector4 &v) { x -= v.x; y -= v.y; z -= v.z; w -= v.w; return *this; };
250 |
251 | // Norms
252 | CGFloat norm() const { return sqrtr(squaredNorm()); }
253 | CGFloat squaredNorm() const { return x * x + y * y + z * z + w * w; }
254 |
255 | // Cast
256 | template Vector4 cast() const { return Vector4(x, y, z, w); }
257 | };
258 |
259 | template
260 | const typename Vector4::_data Vector4::_v = { &Vector4::x, &Vector4::y, &Vector4::z, &Vector4::w };
261 |
262 | /** Convenience typedefs */
263 | typedef Vector2 Vector2f;
264 | typedef Vector2 Vector2d;
265 | typedef Vector2 Vector2r;
266 | typedef Vector3 Vector3f;
267 | typedef Vector3 Vector3d;
268 | typedef Vector3 Vector3r;
269 | typedef Vector4 Vector4f;
270 | typedef Vector4 Vector4d;
271 | typedef Vector4 Vector4r;
272 |
273 | /** Variable-sized vector class */
274 | class Vector
275 | {
276 | size_t _count;
277 | CGFloat *_values;
278 |
279 | private:
280 | Vector(size_t);
281 | Vector(const Vector& other);
282 |
283 | public:
284 | ~Vector();
285 |
286 | // Creates a new vector instance of count with values. Initializing a vector of size 0 returns NULL.
287 | static Vector *new_vector(NSUInteger count, const CGFloat *values);
288 |
289 | // Creates a new vector given a pointer to another. Can return NULL.
290 | static Vector *new_vector(const Vector * const other);
291 |
292 | // Creates a variable size vector given a static vector and count.
293 | static Vector *new_vector(NSUInteger count, Vector4r vec);
294 |
295 | // Size of vector
296 | NSUInteger size() const { return _count; }
297 |
298 | // Returns array of values
299 | CGFloat *data () { return _values; }
300 | const CGFloat *data () const { return _values; };
301 |
302 | // Vector2r support
303 | Vector2r vector2r() const;
304 |
305 | // Vector4r support
306 | Vector4r vector4r() const;
307 |
308 | // CGFloat support
309 | static Vector *new_cg_float(CGFloat f);
310 |
311 | // CGPoint support
312 | CGPoint cg_point() const;
313 | static Vector *new_cg_point(const CGPoint &p);
314 |
315 | // CGSize support
316 | CGSize cg_size() const;
317 | static Vector *new_cg_size(const CGSize &s);
318 |
319 | // CGRect support
320 | CGRect cg_rect() const;
321 | static Vector *new_cg_rect(const CGRect &r);
322 |
323 | // CGAffineTransform support
324 | CGAffineTransform cg_affine_transform() const;
325 | static Vector *new_cg_affine_transform(const CGAffineTransform &t);
326 |
327 | // CGColorRef support
328 | CGColorRef cg_color() const CF_RETURNS_RETAINED;
329 | static Vector *new_cg_color(CGColorRef color);
330 |
331 | // operator overloads
332 | CGFloat &operator[](size_t i) const {
333 | NSCAssert(size() > i, @"unexpected vector size:%lu", (unsigned long)size());
334 | return _values[i];
335 | }
336 |
337 | // Returns the mathematical length
338 | CGFloat norm() const;
339 | CGFloat squaredNorm() const;
340 |
341 | // Round to nearest sub
342 | void subRound(CGFloat sub);
343 |
344 | // Returns string description
345 | NSString * const toString() const;
346 |
347 | // Operator overloads
348 | template Vector& operator= (const Vector4& other) {
349 | size_t count = MIN(_count, other.size());
350 | for (size_t i = 0; i < count; i++) {
351 | _values[i] = other[i];
352 | }
353 | return *this;
354 | }
355 | Vector& operator= (const Vector& other);
356 | void swap(Vector &first, Vector &second);
357 | bool operator==(const Vector &other) const;
358 | bool operator!=(const Vector &other) const;
359 | };
360 |
361 | /** Convenience typedefs */
362 | typedef std::shared_ptr VectorRef;
363 | typedef std::shared_ptr VectorConstRef;
364 |
365 | }
366 | #endif /* defined(__POP__FBVector__) */
367 |
--------------------------------------------------------------------------------
/LTStackView/pop/POPVector.mm:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright (c) 2014-present, Facebook, Inc.
3 | All rights reserved.
4 |
5 | This source code is licensed under the BSD-style license found in the
6 | LICENSE file in the root directory of this source tree. An additional grant
7 | of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import "POPVector.h"
11 | #import "POPAnimationRuntime.h"
12 | #import "POPCGUtils.h"
13 |
14 | namespace POP
15 | {
16 |
17 | Vector::Vector(const size_t count)
18 | {
19 | _count = count;
20 | _values = 0 != count ? (CGFloat *)calloc(count, sizeof(CGFloat)) : NULL;
21 | }
22 |
23 | Vector::Vector(const Vector& other)
24 | {
25 | _count = other.size();
26 | _values = 0 != _count ? (CGFloat *)calloc(_count, sizeof(CGFloat)) : NULL;
27 | if (0 != _count) {
28 | memcpy(_values, other.data(), _count * sizeof(CGFloat));
29 | }
30 | }
31 |
32 | Vector::~Vector()
33 | {
34 | if (NULL != _values) {
35 | free(_values);
36 | _values = NULL;
37 | }
38 | _count = 0;
39 | }
40 |
41 | void Vector::swap(Vector &first, Vector &second)
42 | {
43 | using std::swap;
44 | swap(first._count, second._count);
45 | swap(first._values, second._values);
46 | }
47 |
48 | Vector& Vector::operator=(const Vector& other)
49 | {
50 | Vector temp(other);
51 | swap(*this, temp);
52 | return *this;
53 | }
54 |
55 | bool Vector::operator==(const Vector &other) const {
56 | if (_count != other.size()) {
57 | return false;
58 | }
59 |
60 | const CGFloat * const values = other.data();
61 |
62 | for (NSUInteger idx = 0; idx < _count; idx++) {
63 | if (_values[idx] != values[idx]) {
64 | return false;
65 | }
66 | }
67 |
68 | return true;
69 | }
70 |
71 | bool Vector::operator!=(const Vector &other) const {
72 | if (_count == other.size()) {
73 | return false;
74 | }
75 |
76 | const CGFloat * const values = other.data();
77 |
78 | for (NSUInteger idx = 0; idx < _count; idx++) {
79 | if (_values[idx] != values[idx]) {
80 | return false;
81 | }
82 | }
83 |
84 | return true;
85 | }
86 |
87 | Vector *Vector::new_vector(NSUInteger count, const CGFloat *values)
88 | {
89 | if (0 == count) {
90 | return NULL;
91 | }
92 |
93 | Vector *v = new Vector(count);
94 | if (NULL != values) {
95 | memcpy(v->_values, values, count * sizeof(CGFloat));
96 | }
97 | return v;
98 | }
99 |
100 | Vector *Vector::new_vector(const Vector * const other)
101 | {
102 | if (NULL == other) {
103 | return NULL;
104 | }
105 |
106 | return Vector::new_vector(other->size(), other->data());
107 | }
108 |
109 | Vector *Vector::new_vector(NSUInteger count, Vector4r vec)
110 | {
111 | if (0 == count) {
112 | return NULL;
113 | }
114 |
115 | Vector *v = new Vector(count);
116 |
117 | NSCAssert(count <= 4, @"unexpected count %lu", (unsigned long)count);
118 | for (NSUInteger i = 0; i < MIN(count, 4); i++) {
119 | v->_values[i] = vec[i];
120 | }
121 |
122 | return v;
123 | }
124 |
125 | Vector4r Vector::vector4r() const
126 | {
127 | Vector4r v = Vector4r::Zero();
128 | for (int i = 0; i < _count; i++) {
129 | v(i) = _values[i];
130 | }
131 | return v;
132 | }
133 |
134 | Vector2r Vector::vector2r() const
135 | {
136 | Vector2r v = Vector2r::Zero();
137 | if (_count > 0) v(0) = _values[0];
138 | if (_count > 1) v(1) = _values[1];
139 | return v;
140 | }
141 |
142 | Vector *Vector::new_cg_float(CGFloat f)
143 | {
144 | Vector *v = new Vector(1);
145 | v->_values[0] = f;
146 | return v;
147 | }
148 |
149 | CGPoint Vector::cg_point () const
150 | {
151 | Vector2r v = vector2r();
152 | return CGPointMake(v(0), v(1));
153 | }
154 |
155 | Vector *Vector::new_cg_point(const CGPoint &p)
156 | {
157 | Vector *v = new Vector(2);
158 | v->_values[0] = p.x;
159 | v->_values[1] = p.y;
160 | return v;
161 | }
162 |
163 | CGSize Vector::cg_size () const
164 | {
165 | Vector2r v = vector2r();
166 | return CGSizeMake(v(0), v(1));
167 | }
168 |
169 | Vector *Vector::new_cg_size(const CGSize &s)
170 | {
171 | Vector *v = new Vector(2);
172 | v->_values[0] = s.width;
173 | v->_values[1] = s.height;
174 | return v;
175 | }
176 |
177 | CGRect Vector::cg_rect() const
178 | {
179 | return _count < 4 ? CGRectZero : CGRectMake(_values[0], _values[1], _values[2], _values[3]);
180 | }
181 |
182 | Vector *Vector::new_cg_rect(const CGRect &r)
183 | {
184 | Vector *v = new Vector(4);
185 | v->_values[0] = r.origin.x;
186 | v->_values[1] = r.origin.y;
187 | v->_values[2] = r.size.width;
188 | v->_values[3] = r.size.height;
189 | return v;
190 | }
191 |
192 | CGAffineTransform Vector::cg_affine_transform() const
193 | {
194 | if (_count < 6) {
195 | return CGAffineTransformIdentity;
196 | }
197 |
198 | NSCAssert(size() >= 6, @"unexpected vector size:%lu", (unsigned long)size());
199 | CGAffineTransform t;
200 | t.a = _values[0];
201 | t.b = _values[1];
202 | t.c = _values[2];
203 | t.d = _values[3];
204 | t.tx = _values[4];
205 | t.ty = _values[5];
206 | return t;
207 | }
208 |
209 | Vector *Vector::new_cg_affine_transform(const CGAffineTransform &t)
210 | {
211 | Vector *v = new Vector(4);
212 | v->_values[0] = t.a;
213 | v->_values[1] = t.b;
214 | v->_values[2] = t.c;
215 | v->_values[3] = t.d;
216 | v->_values[4] = t.tx;
217 | v->_values[5] = t.ty;
218 | return v;
219 | }
220 |
221 | CGColorRef Vector::cg_color() const
222 | {
223 | if (_count < 4) {
224 | return NULL;
225 | }
226 | return POPCGColorRGBACreate(_values);
227 | }
228 |
229 | Vector *Vector::new_cg_color(CGColorRef color)
230 | {
231 | CGFloat rgba[4];
232 | POPCGColorGetRGBAComponents(color, rgba);
233 | return new_vector(4, rgba);
234 | }
235 |
236 | void Vector::subRound(CGFloat sub)
237 | {
238 | for (NSUInteger idx = 0; idx < _count; idx++) {
239 | _values[idx] = POPSubRound(_values[idx], sub);
240 | }
241 | }
242 |
243 | CGFloat Vector::norm() const
244 | {
245 | return sqrtr(squaredNorm());
246 | }
247 |
248 | CGFloat Vector::squaredNorm() const
249 | {
250 | CGFloat d = 0;
251 | for (NSUInteger idx = 0; idx < _count; idx++) {
252 | d += (_values[idx] * _values[idx]);
253 | }
254 | return d;
255 | }
256 |
257 | NSString * const Vector::toString() const
258 | {
259 | if (0 == _count)
260 | return @"()";
261 |
262 | if (1 == _count)
263 | return [NSString stringWithFormat:@"%f", _values[0]];
264 |
265 | if (2 == _count)
266 | return [NSString stringWithFormat:@"(%.3f, %.3f)", _values[0], _values[1]];
267 |
268 | NSMutableString *s = [NSMutableString stringWithCapacity:10];
269 |
270 | for (NSUInteger idx = 0; idx < _count; idx++) {
271 | if (0 == idx) {
272 | [s appendFormat:@"[%.3f", _values[idx]];
273 | } else if (idx == _count - 1) {
274 | [s appendFormat:@", %.3f]", _values[idx]];
275 | } else {
276 | [s appendFormat:@", %.3f", _values[idx]];
277 | }
278 | }
279 |
280 | return s;
281 |
282 | }
283 | }
284 |
--------------------------------------------------------------------------------
/LTStackView/pop/WebCore/FloatConversion.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2007 Apple Inc. All rights reserved.
3 | *
4 | * Redistribution and use in source and binary forms, with or without
5 | * modification, are permitted provided that the following conditions
6 | * are met:
7 | *
8 | * 1. Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | * 2. Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 | * its contributors may be used to endorse or promote products derived
15 | * from this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 | * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 | */
28 |
29 | #ifndef FloatConversion_h
30 | #define FloatConversion_h
31 |
32 | #include
33 |
34 | namespace WebCore {
35 |
36 | template
37 | float narrowPrecisionToFloat(T);
38 |
39 | template<>
40 | inline float narrowPrecisionToFloat(double number)
41 | {
42 | return static_cast(number);
43 | }
44 |
45 | template
46 | CGFloat narrowPrecisionToCGFloat(T);
47 |
48 | template<>
49 | inline CGFloat narrowPrecisionToCGFloat(double number)
50 | {
51 | return static_cast(number);
52 | }
53 |
54 | } // namespace WebCore
55 |
56 | #endif // FloatConversion_h
57 |
--------------------------------------------------------------------------------
/LTStackView/pop/WebCore/TransformationMatrix.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
3 | *
4 | * Redistribution and use in source and binary forms, with or without
5 | * modification, are permitted provided that the following conditions
6 | * are met:
7 | * 1. Redistributions of source code must retain the above copyright
8 | * notice, this list of conditions and the following disclaimer.
9 | * 2. Redistributions in binary form must reproduce the above copyright
10 | * notice, this list of conditions and the following disclaimer in the
11 | * documentation and/or other materials provided with the distribution.
12 | *
13 | * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 | */
25 |
26 | #ifndef TransformationMatrix_h
27 | #define TransformationMatrix_h
28 |
29 | #include //for memcpy
30 | #include
31 | #include
32 |
33 | namespace WebCore {
34 |
35 | class TransformationMatrix {
36 | public:
37 |
38 | typedef double Matrix4[4][4];
39 |
40 | TransformationMatrix() { makeIdentity(); }
41 | TransformationMatrix(const TransformationMatrix& t) { *this = t; }
42 | TransformationMatrix(double a, double b, double c, double d, double e, double f) { setMatrix(a, b, c, d, e, f); }
43 | TransformationMatrix(double m11, double m12, double m13, double m14,
44 | double m21, double m22, double m23, double m24,
45 | double m31, double m32, double m33, double m34,
46 | double m41, double m42, double m43, double m44)
47 | {
48 | setMatrix(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44);
49 | }
50 |
51 | void setMatrix(double a, double b, double c, double d, double e, double f)
52 | {
53 | m_matrix[0][0] = a; m_matrix[0][1] = b; m_matrix[0][2] = 0; m_matrix[0][3] = 0;
54 | m_matrix[1][0] = c; m_matrix[1][1] = d; m_matrix[1][2] = 0; m_matrix[1][3] = 0;
55 | m_matrix[2][0] = 0; m_matrix[2][1] = 0; m_matrix[2][2] = 1; m_matrix[2][3] = 0;
56 | m_matrix[3][0] = e; m_matrix[3][1] = f; m_matrix[3][2] = 0; m_matrix[3][3] = 1;
57 | }
58 |
59 | void setMatrix(double m11, double m12, double m13, double m14,
60 | double m21, double m22, double m23, double m24,
61 | double m31, double m32, double m33, double m34,
62 | double m41, double m42, double m43, double m44)
63 | {
64 | m_matrix[0][0] = m11; m_matrix[0][1] = m12; m_matrix[0][2] = m13; m_matrix[0][3] = m14;
65 | m_matrix[1][0] = m21; m_matrix[1][1] = m22; m_matrix[1][2] = m23; m_matrix[1][3] = m24;
66 | m_matrix[2][0] = m31; m_matrix[2][1] = m32; m_matrix[2][2] = m33; m_matrix[2][3] = m34;
67 | m_matrix[3][0] = m41; m_matrix[3][1] = m42; m_matrix[3][2] = m43; m_matrix[3][3] = m44;
68 | }
69 |
70 | TransformationMatrix& operator =(const TransformationMatrix &t)
71 | {
72 | setMatrix(t.m_matrix);
73 | return *this;
74 | }
75 |
76 | TransformationMatrix& makeIdentity()
77 | {
78 | setMatrix(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
79 | return *this;
80 | }
81 |
82 | bool isIdentity() const
83 | {
84 | return m_matrix[0][0] == 1 && m_matrix[0][1] == 0 && m_matrix[0][2] == 0 && m_matrix[0][3] == 0 &&
85 | m_matrix[1][0] == 0 && m_matrix[1][1] == 1 && m_matrix[1][2] == 0 && m_matrix[1][3] == 0 &&
86 | m_matrix[2][0] == 0 && m_matrix[2][1] == 0 && m_matrix[2][2] == 1 && m_matrix[2][3] == 0 &&
87 | m_matrix[3][0] == 0 && m_matrix[3][1] == 0 && m_matrix[3][2] == 0 && m_matrix[3][3] == 1;
88 | }
89 |
90 | // This form preserves the double math from input to output
91 | void map(double x, double y, double& x2, double& y2) const { multVecMatrix(x, y, x2, y2); }
92 |
93 | double m11() const { return m_matrix[0][0]; }
94 | void setM11(double f) { m_matrix[0][0] = f; }
95 | double m12() const { return m_matrix[0][1]; }
96 | void setM12(double f) { m_matrix[0][1] = f; }
97 | double m13() const { return m_matrix[0][2]; }
98 | void setM13(double f) { m_matrix[0][2] = f; }
99 | double m14() const { return m_matrix[0][3]; }
100 | void setM14(double f) { m_matrix[0][3] = f; }
101 | double m21() const { return m_matrix[1][0]; }
102 | void setM21(double f) { m_matrix[1][0] = f; }
103 | double m22() const { return m_matrix[1][1]; }
104 | void setM22(double f) { m_matrix[1][1] = f; }
105 | double m23() const { return m_matrix[1][2]; }
106 | void setM23(double f) { m_matrix[1][2] = f; }
107 | double m24() const { return m_matrix[1][3]; }
108 | void setM24(double f) { m_matrix[1][3] = f; }
109 | double m31() const { return m_matrix[2][0]; }
110 | void setM31(double f) { m_matrix[2][0] = f; }
111 | double m32() const { return m_matrix[2][1]; }
112 | void setM32(double f) { m_matrix[2][1] = f; }
113 | double m33() const { return m_matrix[2][2]; }
114 | void setM33(double f) { m_matrix[2][2] = f; }
115 | double m34() const { return m_matrix[2][3]; }
116 | void setM34(double f) { m_matrix[2][3] = f; }
117 | double m41() const { return m_matrix[3][0]; }
118 | void setM41(double f) { m_matrix[3][0] = f; }
119 | double m42() const { return m_matrix[3][1]; }
120 | void setM42(double f) { m_matrix[3][1] = f; }
121 | double m43() const { return m_matrix[3][2]; }
122 | void setM43(double f) { m_matrix[3][2] = f; }
123 | double m44() const { return m_matrix[3][3]; }
124 | void setM44(double f) { m_matrix[3][3] = f; }
125 |
126 | double a() const { return m_matrix[0][0]; }
127 | void setA(double a) { m_matrix[0][0] = a; }
128 |
129 | double b() const { return m_matrix[0][1]; }
130 | void setB(double b) { m_matrix[0][1] = b; }
131 |
132 | double c() const { return m_matrix[1][0]; }
133 | void setC(double c) { m_matrix[1][0] = c; }
134 |
135 | double d() const { return m_matrix[1][1]; }
136 | void setD(double d) { m_matrix[1][1] = d; }
137 |
138 | double e() const { return m_matrix[3][0]; }
139 | void setE(double e) { m_matrix[3][0] = e; }
140 |
141 | double f() const { return m_matrix[3][1]; }
142 | void setF(double f) { m_matrix[3][1] = f; }
143 |
144 | // this = this * mat
145 | TransformationMatrix& multiply(const TransformationMatrix&);
146 |
147 | TransformationMatrix& scale(double);
148 | TransformationMatrix& scaleNonUniform(double sx, double sy);
149 | TransformationMatrix& scale3d(double sx, double sy, double sz);
150 |
151 | TransformationMatrix& rotate(double d) { return rotate3d(0, 0, d); }
152 | TransformationMatrix& rotateFromVector(double x, double y);
153 | TransformationMatrix& rotate3d(double rx, double ry, double rz);
154 |
155 | // The vector (x,y,z) is normalized if it's not already. A vector of
156 | // (0,0,0) uses a vector of (0,0,1).
157 | TransformationMatrix& rotate3d(double x, double y, double z, double angle);
158 |
159 | TransformationMatrix& translate(double tx, double ty);
160 | TransformationMatrix& translate3d(double tx, double ty, double tz);
161 |
162 | // translation added with a post-multiply
163 | TransformationMatrix& translateRight(double tx, double ty);
164 | TransformationMatrix& translateRight3d(double tx, double ty, double tz);
165 |
166 | TransformationMatrix& flipX();
167 | TransformationMatrix& flipY();
168 | TransformationMatrix& skew(double angleX, double angleY);
169 | TransformationMatrix& skewX(double angle) { return skew(angle, 0); }
170 | TransformationMatrix& skewY(double angle) { return skew(0, angle); }
171 |
172 | TransformationMatrix& applyPerspective(double p);
173 | bool hasPerspective() const { return m_matrix[2][3] != 0.0f; }
174 |
175 | bool isInvertible() const;
176 |
177 | // This method returns the identity matrix if it is not invertible.
178 | // Use isInvertible() before calling this if you need to know.
179 | TransformationMatrix inverse() const;
180 |
181 | // decompose the matrix into its component parts
182 | typedef struct {
183 | double scaleX, scaleY, scaleZ;
184 | double skewXY, skewXZ, skewYZ;
185 | double rotateX, rotateY, rotateZ;
186 | double quaternionX, quaternionY, quaternionZ, quaternionW;
187 | double translateX, translateY, translateZ;
188 | double perspectiveX, perspectiveY, perspectiveZ, perspectiveW;
189 | } DecomposedType;
190 |
191 | bool decompose(DecomposedType& decomp) const;
192 | void recompose(const DecomposedType& decomp, bool useEulerAngle = false);
193 |
194 | void blend(const TransformationMatrix& from, double progress);
195 |
196 | bool isAffine() const
197 | {
198 | return (m13() == 0 && m14() == 0 && m23() == 0 && m24() == 0 &&
199 | m31() == 0 && m32() == 0 && m33() == 1 && m34() == 0 && m43() == 0 && m44() == 1);
200 | }
201 |
202 | // Throw away the non-affine parts of the matrix (lossy!)
203 | void makeAffine();
204 |
205 | bool operator==(const TransformationMatrix& m2) const
206 | {
207 | return (m_matrix[0][0] == m2.m_matrix[0][0] &&
208 | m_matrix[0][1] == m2.m_matrix[0][1] &&
209 | m_matrix[0][2] == m2.m_matrix[0][2] &&
210 | m_matrix[0][3] == m2.m_matrix[0][3] &&
211 | m_matrix[1][0] == m2.m_matrix[1][0] &&
212 | m_matrix[1][1] == m2.m_matrix[1][1] &&
213 | m_matrix[1][2] == m2.m_matrix[1][2] &&
214 | m_matrix[1][3] == m2.m_matrix[1][3] &&
215 | m_matrix[2][0] == m2.m_matrix[2][0] &&
216 | m_matrix[2][1] == m2.m_matrix[2][1] &&
217 | m_matrix[2][2] == m2.m_matrix[2][2] &&
218 | m_matrix[2][3] == m2.m_matrix[2][3] &&
219 | m_matrix[3][0] == m2.m_matrix[3][0] &&
220 | m_matrix[3][1] == m2.m_matrix[3][1] &&
221 | m_matrix[3][2] == m2.m_matrix[3][2] &&
222 | m_matrix[3][3] == m2.m_matrix[3][3]);
223 | }
224 |
225 | bool operator!=(const TransformationMatrix& other) const { return !(*this == other); }
226 |
227 | // *this = *this * t (i.e., a multRight)
228 | TransformationMatrix& operator*=(const TransformationMatrix& t)
229 | {
230 | return multiply(t);
231 | }
232 |
233 | // result = *this * t (i.e., a multRight)
234 | TransformationMatrix operator*(const TransformationMatrix& t)
235 | {
236 | TransformationMatrix result = *this;
237 | result.multiply(t);
238 | return result;
239 | }
240 |
241 | CATransform3D transform3d () const;
242 | CGAffineTransform affineTransform () const;
243 |
244 | TransformationMatrix(const CATransform3D&);
245 | operator CATransform3D() const;
246 |
247 | TransformationMatrix(const CGAffineTransform&);
248 | operator CGAffineTransform() const;
249 |
250 | private:
251 |
252 | // multiply passed 2D point by matrix (assume z=0)
253 | void multVecMatrix(double x, double y, double& dstX, double& dstY) const;
254 |
255 | // multiply passed 3D point by matrix
256 | void multVecMatrix(double x, double y, double z, double& dstX, double& dstY, double& dstZ) const;
257 |
258 | void setMatrix(const Matrix4 m)
259 | {
260 | if (m && m != m_matrix)
261 | memcpy(m_matrix, m, sizeof(Matrix4));
262 | }
263 |
264 | bool isIdentityOrTranslation() const
265 | {
266 | return m_matrix[0][0] == 1 && m_matrix[0][1] == 0 && m_matrix[0][2] == 0 && m_matrix[0][3] == 0 &&
267 | m_matrix[1][0] == 0 && m_matrix[1][1] == 1 && m_matrix[1][2] == 0 && m_matrix[1][3] == 0 &&
268 | m_matrix[2][0] == 0 && m_matrix[2][1] == 0 && m_matrix[2][2] == 1 && m_matrix[2][3] == 0 &&
269 | m_matrix[3][3] == 1;
270 | }
271 |
272 | Matrix4 m_matrix;
273 | };
274 |
275 | } // namespace WebCore
276 |
277 | #endif // TransformationMatrix_h
278 |
--------------------------------------------------------------------------------
/LTStackView/pop/WebCore/UnitBezier.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2008 Apple Inc. All Rights Reserved.
3 | *
4 | * Redistribution and use in source and binary forms, with or without
5 | * modification, are permitted provided that the following conditions
6 | * are met:
7 | * 1. Redistributions of source code must retain the above copyright
8 | * notice, this list of conditions and the following disclaimer.
9 | * 2. Redistributions in binary form must reproduce the above copyright
10 | * notice, this list of conditions and the following disclaimer in the
11 | * documentation and/or other materials provided with the distribution.
12 | *
13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 | */
25 |
26 | #ifndef UnitBezier_h
27 | #define UnitBezier_h
28 |
29 | #include
30 |
31 | namespace WebCore {
32 |
33 | struct UnitBezier {
34 | UnitBezier(double p1x, double p1y, double p2x, double p2y)
35 | {
36 | // Calculate the polynomial coefficients, implicit first and last control points are (0,0) and (1,1).
37 | cx = 3.0 * p1x;
38 | bx = 3.0 * (p2x - p1x) - cx;
39 | ax = 1.0 - cx -bx;
40 |
41 | cy = 3.0 * p1y;
42 | by = 3.0 * (p2y - p1y) - cy;
43 | ay = 1.0 - cy - by;
44 | }
45 |
46 | double sampleCurveX(double t)
47 | {
48 | // `ax t^3 + bx t^2 + cx t' expanded using Horner's rule.
49 | return ((ax * t + bx) * t + cx) * t;
50 | }
51 |
52 | double sampleCurveY(double t)
53 | {
54 | return ((ay * t + by) * t + cy) * t;
55 | }
56 |
57 | double sampleCurveDerivativeX(double t)
58 | {
59 | return (3.0 * ax * t + 2.0 * bx) * t + cx;
60 | }
61 |
62 | // Given an x value, find a parametric value it came from.
63 | double solveCurveX(double x, double epsilon)
64 | {
65 | double t0;
66 | double t1;
67 | double t2;
68 | double x2;
69 | double d2;
70 | int i;
71 |
72 | // First try a few iterations of Newton's method -- normally very fast.
73 | for (t2 = x, i = 0; i < 8; i++) {
74 | x2 = sampleCurveX(t2) - x;
75 | if (fabs (x2) < epsilon)
76 | return t2;
77 | d2 = sampleCurveDerivativeX(t2);
78 | if (fabs(d2) < 1e-6)
79 | break;
80 | t2 = t2 - x2 / d2;
81 | }
82 |
83 | // Fall back to the bisection method for reliability.
84 | t0 = 0.0;
85 | t1 = 1.0;
86 | t2 = x;
87 |
88 | if (t2 < t0)
89 | return t0;
90 | if (t2 > t1)
91 | return t1;
92 |
93 | while (t0 < t1) {
94 | x2 = sampleCurveX(t2);
95 | if (fabs(x2 - x) < epsilon)
96 | return t2;
97 | if (x > x2)
98 | t0 = t2;
99 | else
100 | t1 = t2;
101 | t2 = (t1 - t0) * .5 + t0;
102 | }
103 |
104 | // Failure.
105 | return t2;
106 | }
107 |
108 | double solve(double x, double epsilon)
109 | {
110 | return sampleCurveY(solveCurveX(x, epsilon));
111 | }
112 |
113 | private:
114 | double ax;
115 | double bx;
116 | double cx;
117 |
118 | double ay;
119 | double by;
120 | double cy;
121 | };
122 | }
123 | #endif
124 |
--------------------------------------------------------------------------------
/LTStackView/pop/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/LTStackView/pop/pop-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | English
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIconFile
10 |
11 | CFBundleIdentifier
12 | com.facebook.${PRODUCT_NAME:rfc1034identifier}
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | ${PRODUCT_NAME}
17 | CFBundlePackageType
18 | FMWK
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1
25 | NSHumanReadableCopyright
26 | Copyright © 2014 Facebook. All rights reserved.
27 | NSPrincipalClass
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/LTStackView/pop/pop-Prefix.pch:
--------------------------------------------------------------------------------
1 | //
2 | // Prefix header for all source files of the 'POPAnimation' target in the 'POPAnimation' project
3 | //
4 |
5 | #ifdef __OBJC__
6 | #import
7 | #endif
8 |
--------------------------------------------------------------------------------
/LTStackViewTests/LTStackViewTests-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | org.ltebean.${PRODUCT_NAME:rfc1034identifier}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundlePackageType
14 | BNDL
15 | CFBundleShortVersionString
16 | 1.0
17 | CFBundleSignature
18 | ????
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/LTStackViewTests/LTStackViewTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // LTStackViewTests.m
3 | // LTStackViewTests
4 | //
5 | // Created by ltebean on 14-8-26.
6 | // Copyright (c) 2014年 ltebean. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface LTStackViewTests : XCTestCase
12 |
13 | @end
14 |
15 | @implementation LTStackViewTests
16 |
17 | - (void)setUp
18 | {
19 | [super setUp];
20 | // Put setup code here. This method is called before the invocation of each test method in the class.
21 | }
22 |
23 | - (void)tearDown
24 | {
25 | // Put teardown code here. This method is called after the invocation of each test method in the class.
26 | [super tearDown];
27 | }
28 |
29 | - (void)testExample
30 | {
31 | XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__);
32 | }
33 |
34 | @end
35 |
--------------------------------------------------------------------------------
/LTStackViewTests/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # 
3 |
4 | ## Usage
5 |
6 | Initialize a stack view by:
7 |
8 | ```objective-c
9 | LTStackView *stackView = [[LTStackView alloc]initWithFrame:CGRectMake(0, 0, 320, 480)];
10 | stackView.dataSource = self;
11 | ```
12 |
13 | Then implement `LTStackViewDataSource` protocol:
14 |
15 | ```objective-c
16 | -(UIView*) nextView
17 | {
18 | UIView *view=[[UIView alloc]initWithFrame:CGRectMake(0, 0, 200, 200)];
19 | view.backgroundColor=[UIColor blueColor];
20 | return view;
21 | }
22 | ```
23 |
24 | Finaly call:
25 | ```objective-c
26 | [stackView next];
27 | ```
--------------------------------------------------------------------------------
/image/demostration.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ltebean/LTStackView/eb37c2b12421b72eb237d0178f76a33ab21413f9/image/demostration.gif
--------------------------------------------------------------------------------