├── Source
├── demo0.gif
├── demo1.gif
└── demo3.gif
├── DGGooeySlide ObjC
├── DGGooeySlide
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ ├── img.imageset
│ │ │ ├── t0141b2bb3491466951.png
│ │ │ └── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── ViewController.h
│ ├── AppDelegate.h
│ ├── main.m
│ ├── DGGooeySlideMenu.h
│ ├── ViewController.m
│ ├── Info.plist
│ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ ├── AppDelegate.m
│ └── DGGooeySlideMenu.m
└── DGGooeySlide.xcodeproj
│ ├── xcuserdata
│ └── Desgard_Duan.xcuserdatad
│ │ ├── xcdebugger
│ │ └── Breakpoints_v2.xcbkptlist
│ │ └── xcschemes
│ │ ├── xcschememanagement.plist
│ │ └── DGGooeySlide.xcscheme
│ ├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcuserdata
│ │ └── Desgard_Duan.xcuserdatad
│ │ └── UserInterfaceState.xcuserstate
│ └── project.pbxproj
└── README.md
/Source/demo0.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Desgard/DGGooeySlideMenu/HEAD/Source/demo0.gif
--------------------------------------------------------------------------------
/Source/demo1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Desgard/DGGooeySlideMenu/HEAD/Source/demo1.gif
--------------------------------------------------------------------------------
/Source/demo3.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Desgard/DGGooeySlideMenu/HEAD/Source/demo3.gif
--------------------------------------------------------------------------------
/DGGooeySlide ObjC/DGGooeySlide/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/DGGooeySlide ObjC/DGGooeySlide.xcodeproj/xcuserdata/Desgard_Duan.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/DGGooeySlide ObjC/DGGooeySlide/Assets.xcassets/img.imageset/t0141b2bb3491466951.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Desgard/DGGooeySlideMenu/HEAD/DGGooeySlide ObjC/DGGooeySlide/Assets.xcassets/img.imageset/t0141b2bb3491466951.png
--------------------------------------------------------------------------------
/DGGooeySlide ObjC/DGGooeySlide.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/DGGooeySlide ObjC/DGGooeySlide.xcodeproj/project.xcworkspace/xcuserdata/Desgard_Duan.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Desgard/DGGooeySlideMenu/HEAD/DGGooeySlide ObjC/DGGooeySlide.xcodeproj/project.xcworkspace/xcuserdata/Desgard_Duan.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/DGGooeySlide ObjC/DGGooeySlide/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // DGGooeySlide
4 | //
5 | // Created by 段昊宇 on 16/6/4.
6 | // Copyright © 2016年 Desgard_Duan. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ViewController : UIViewController
12 |
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/DGGooeySlide ObjC/DGGooeySlide/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // DGGooeySlide
4 | //
5 | // Created by 段昊宇 on 16/6/4.
6 | // Copyright © 2016年 Desgard_Duan. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AppDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow *window;
14 |
15 |
16 | @end
17 |
18 |
--------------------------------------------------------------------------------
/DGGooeySlide ObjC/DGGooeySlide/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // DGGooeySlide
4 | //
5 | // Created by 段昊宇 on 16/6/4.
6 | // Copyright © 2016年 Desgard_Duan. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "AppDelegate.h"
11 |
12 | int main(int argc, char * argv[]) {
13 | @autoreleasepool {
14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/DGGooeySlide ObjC/DGGooeySlide/Assets.xcassets/img.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "t0141b2bb3491466951.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/DGGooeySlide ObjC/DGGooeySlide/DGGooeySlideMenu.h:
--------------------------------------------------------------------------------
1 | //
2 | // DGGooeySlideMenu.h
3 | // DGGooeySlide
4 | //
5 | // Created by 段昊宇 on 16/6/4.
6 | // Copyright © 2016年 Desgard_Duan. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface DGGooeySlideMenu : UIView
12 |
13 |
14 |
15 | -(id)initWithTitles:(NSArray *)titles;
16 |
17 | -(id)initWithTitles:(NSArray *)titles withButtonHeight:(CGFloat)height withMenuColor:(UIColor *)menuColor withBackBlurStyle:(UIBlurEffectStyle)style;
18 |
19 | -(void)trigger;
20 |
21 |
22 | @end
23 |
--------------------------------------------------------------------------------
/DGGooeySlide ObjC/DGGooeySlide.xcodeproj/xcuserdata/Desgard_Duan.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | DGGooeySlide.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | D53F27D31D0252E900A0704C
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/DGGooeySlide ObjC/DGGooeySlide/ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.m
3 | // DGGooeySlide
4 | //
5 | // Created by 段昊宇 on 16/6/4.
6 | // Copyright © 2016年 Desgard_Duan. All rights reserved.
7 | //
8 |
9 | #import "ViewController.h"
10 | #import "DGGooeySlideMenu.h"
11 |
12 | @interface ViewController ()
13 |
14 | @property (nonatomic, strong) DGGooeySlideMenu *menu;
15 |
16 | @end
17 |
18 | @implementation ViewController
19 |
20 | - (void)viewDidLoad {
21 | [super viewDidLoad];
22 | self.menu = [[DGGooeySlideMenu alloc] initWithTitles:@[@"123", @"123" ]];
23 |
24 | }
25 |
26 | - (IBAction)clickButton:(id)sender {
27 | [self.menu trigger];
28 | }
29 | @end
30 |
--------------------------------------------------------------------------------
/DGGooeySlide ObjC/DGGooeySlide/Assets.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" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | }
33 | ],
34 | "info" : {
35 | "version" : 1,
36 | "author" : "xcode"
37 | }
38 | }
--------------------------------------------------------------------------------
/DGGooeySlide ObjC/DGGooeySlide/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 | UIInterfaceOrientationLandscapeLeft
37 | UIInterfaceOrientationLandscapeRight
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DGGooeySlideMenu
2 |
3 | 
4 |
5 | DGGooeySlideMenu---模仿skype照相按钮弹出菜单弹簧效果
6 |
7 | 制作思路及代码解释可查看博文[Recreating Skype's Action Sheet Animation](http://desgard.com/2016/06/05/DGGooeySlideMenu/)
8 |
9 |
10 |
11 | ## 计算弹性数组序列
12 |
13 | 先要确定我们的目标:**构造一个连续序列,这个序列的末状态是0,过程中先增大,再减小,再增大……重复以上过程,因为阻尼衰减,到最后会停留在0,则序列结束。**这个连续序列就好比缓动函数中的[EaseOutElastic](http://www.xuanfengge.com/easeing/easeing/#easeOutElastic)。
14 |
15 | 在iOS7之后,Apple在[UIView Class Refference](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/#//apple_ref/occ/clm/UIView/animateWithDuration:delay:usingSpringWithDamping:initialSpringVelocity:options:animations:completion:)增加了弹簧动画效果。
16 |
17 | ```Objective-C
18 | + (void)animateWithDuration: (NSTimeInterval)duration
19 | delay: (NSTimeInterval)delay
20 | usingSpringWithDamping: (CGFloat)dampingRatio
21 | initialSpringVelocity: (CGFloat)velocity
22 | options: (UIViewAnimationOptions)options
23 | animations: (void (^)(void))animations
24 | completion: (void (^)(BOOL finished))completion
25 | ```
26 |
27 | 我们的灵感来自于官方的这个函数。这里在构造序列的时候,**通过两个视图在不同的时间内执行弹簧动画**,即可得到我们所需要的序列(文字说的不明白,可以看我录制图)。这种方法在Kitten-Yang的书中第二章也详细的介绍了,被称作**辅助视图(Side Helper View)**法。这里我把效果放慢,大家观察两个不同颜色的Rect在Y轴上的距离变化:
28 |
29 | 
30 |
31 | ## 后续任务
32 |
33 | * 根据弹簧效果的两个rect视图,计算弹簧序列。(`diff`序列) 【已完成】
34 | * 重写`drawRect`函数,增加`runtime`频率刷新贝塞尔曲线视图。【已完成】
35 | * 给出initWithTitles接口,传入多个button的Title
36 | * 完成button的布局
37 |
--------------------------------------------------------------------------------
/DGGooeySlide ObjC/DGGooeySlide/Base.lproj/LaunchScreen.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 |
--------------------------------------------------------------------------------
/DGGooeySlide ObjC/DGGooeySlide/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // DGGooeySlide
4 | //
5 | // Created by 段昊宇 on 16/6/4.
6 | // Copyright © 2016年 Desgard_Duan. All rights reserved.
7 | //
8 |
9 | #import "AppDelegate.h"
10 |
11 | @interface AppDelegate ()
12 |
13 | @end
14 |
15 | @implementation AppDelegate
16 |
17 |
18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
19 | // Override point for customization after application launch.
20 | return YES;
21 | }
22 |
23 | - (void)applicationWillResignActive:(UIApplication *)application {
24 | // 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.
25 | // 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.
26 | }
27 |
28 | - (void)applicationDidEnterBackground:(UIApplication *)application {
29 | // 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.
30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
31 | }
32 |
33 | - (void)applicationWillEnterForeground:(UIApplication *)application {
34 | // 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.
35 | }
36 |
37 | - (void)applicationDidBecomeActive:(UIApplication *)application {
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 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
43 | }
44 |
45 | @end
46 |
--------------------------------------------------------------------------------
/DGGooeySlide ObjC/DGGooeySlide.xcodeproj/xcuserdata/Desgard_Duan.xcuserdatad/xcschemes/DGGooeySlide.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/DGGooeySlide ObjC/DGGooeySlide/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/DGGooeySlide ObjC/DGGooeySlide/DGGooeySlideMenu.m:
--------------------------------------------------------------------------------
1 | //
2 | // DGGooeySlideMenu.m
3 | // DGGooeySlide
4 | //
5 | // Created by 段昊宇 on 16/6/4.
6 | // Copyright © 2016年 Desgard_Duan. All rights reserved.
7 | //
8 |
9 | #import "DGGooeySlideMenu.h"
10 |
11 | #define buttonSpace 30
12 | #define menuBlankWidth 80
13 | #define wid [UIScreen mainScreen].bounds.size.width
14 | #define hei [UIScreen mainScreen].bounds.size.height
15 | #define kwid keyWindow.frame.size.width
16 | #define khei keyWindow.frame.size.height
17 | #define swid self.frame.size.width
18 | #define shei self.frame.size.height
19 |
20 | @interface DGGooeySlideMenu() {
21 | UIVisualEffectView *blurView;
22 | UIView *helperSideView;
23 | UIView *helperCenterView;
24 | UIWindow *keyWindow;
25 | BOOL triggered;
26 | CGFloat diff;
27 | UIColor *_menuColor;
28 | CGFloat menuButtonHeight;
29 | }
30 |
31 | @property (nonatomic,strong) CADisplayLink *displayLink;
32 | @property NSInteger animationCount; // 动画的数量
33 |
34 | @end
35 |
36 | @implementation DGGooeySlideMenu
37 |
38 | #pragma mark - Overite
39 | -(id)initWithTitles:(NSArray *)titles{
40 | return [self initWithTitles:titles withButtonHeight:40.0f withMenuColor: [UIColor colorWithRed:0 green:175 / 255.f blue: 240 / 255.f alpha:1] withBackBlurStyle:UIBlurEffectStyleDark];
41 | }
42 |
43 | -(id)initWithTitles: (NSArray *)titles withButtonHeight: (CGFloat)height withMenuColor: (UIColor *)menuColor withBackBlurStyle: (UIBlurEffectStyle) style {
44 |
45 | self = [super init];
46 | if (self) {
47 | keyWindow = [[UIApplication sharedApplication] keyWindow];
48 |
49 | // 背景设置为模糊效果
50 | // UIVisualEffectView
51 | blurView = [[UIVisualEffectView alloc]initWithEffect:[UIBlurEffect effectWithStyle:style]];
52 | blurView.frame = keyWindow.frame;
53 | blurView.alpha = 0.0f;
54 |
55 | // 左下角辅助视图
56 | helperSideView = [[UIView alloc] initWithFrame: CGRectMake(0, hei + 40, 40, 40)];
57 | helperSideView.backgroundColor = [UIColor redColor];
58 | helperSideView.hidden = YES;
59 | [keyWindow addSubview: helperSideView];
60 |
61 | // 中央辅助视图
62 | helperCenterView = [[UIView alloc] initWithFrame: CGRectMake(wid / 2 - 20, hei + 40, 40, 40)];
63 | helperCenterView.backgroundColor = [UIColor yellowColor];
64 | helperCenterView.hidden = YES;
65 | [keyWindow addSubview: helperCenterView];
66 |
67 | // 创建下边界界外的视图
68 | self.frame = CGRectMake(0, khei + khei / 2 + menuBlankWidth, kwid, khei / 2 + menuBlankWidth);
69 | self.backgroundColor = [UIColor clearColor];
70 | [keyWindow insertSubview: self belowSubview: helperSideView];
71 |
72 | _menuColor = menuColor;
73 | menuButtonHeight = height;
74 |
75 | // 视图辅助观察颜色
76 | // self.backgroundColor = [UIColor redColor];
77 | [self addButton];
78 | }
79 | return self;
80 | }
81 |
82 | - (void) addButton {
83 |
84 | }
85 |
86 | - (void) drawRect:(CGRect)rect {
87 | UIBezierPath *path = [UIBezierPath bezierPath];
88 | [path moveToPoint: CGPointMake(0, shei)];
89 | [path addLineToPoint: CGPointMake(0, shei - khei / 2 )];
90 | [path addQuadCurveToPoint: CGPointMake(wid, shei - khei / 2)
91 | controlPoint: CGPointMake(swid / 2, diff + menuBlankWidth)];
92 | [path addLineToPoint: CGPointMake(wid, shei)];
93 | [path closePath];
94 |
95 | CGContextRef context = UIGraphicsGetCurrentContext();
96 | CGContextAddPath(context, path.CGPath);
97 | [_menuColor set];
98 | CGContextFillPath(context);
99 | }
100 |
101 |
102 | - (void) trigger{
103 | if (!triggered) {
104 | [keyWindow insertSubview: blurView belowSubview:self];
105 | [UIView animateWithDuration: 0.618 animations:^{
106 | self.frame = CGRectMake(0, hei / 2 - menuBlankWidth, wid, hei / 2 + menuBlankWidth);
107 | }];
108 |
109 | [self beforeAnimation];
110 | [UIView animateWithDuration: 1
111 | delay: 0.0f
112 | usingSpringWithDamping: 0.5f
113 | initialSpringVelocity: 0.9f
114 | options: UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionAllowUserInteraction
115 | animations: ^{
116 | helperSideView.center = CGPointMake(20, hei / 2);
117 | }
118 | completion: ^(BOOL finished) {
119 | [self finishAnimation];
120 | }];
121 |
122 | [UIView animateWithDuration: 0.3 animations: ^{
123 | blurView.alpha = 1.0f;
124 | }];
125 |
126 | [self beforeAnimation];
127 | [UIView animateWithDuration: 1
128 | delay: 0.0f
129 | usingSpringWithDamping: 0.8f
130 | initialSpringVelocity: 2.0f
131 | options: UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionAllowUserInteraction
132 | animations: ^{
133 | helperCenterView.center = keyWindow.center;
134 | }
135 | completion: ^(BOOL finished) {
136 | if (finished) {
137 | UITapGestureRecognizer *tapGes = [[UITapGestureRecognizer alloc] initWithTarget:self action: @selector(tapToUntrigger)];
138 | [blurView addGestureRecognizer: tapGes];
139 | [self finishAnimation];
140 | }
141 | }];
142 | [self animateButtons];
143 | triggered = YES;
144 | } else {
145 | [self tapToUntrigger];
146 | }
147 | }
148 |
149 | - (void) animateButtons{
150 | for (NSInteger i = 0; i < self.subviews.count; i++) {
151 |
152 | UIView *menuButton = self.subviews[i];
153 | menuButton.transform = CGAffineTransformMakeTranslation(0, -90);
154 | [UIView animateWithDuration: 0.7
155 | delay: i * (0.3 / self.subviews.count)
156 | usingSpringWithDamping: 0.6f
157 | initialSpringVelocity: 0.0f
158 | options: UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionAllowUserInteraction
159 | animations: ^{
160 | menuButton.transform = CGAffineTransformIdentity;
161 | }
162 | completion: NULL];
163 | }
164 |
165 | }
166 |
167 | - (void) tapToUntrigger{
168 |
169 | [UIView animateWithDuration: 0.618 animations:^{
170 | self.frame = CGRectMake(0, khei + khei / 2 + menuBlankWidth, kwid, khei / 2 + menuBlankWidth);
171 | }];
172 |
173 | [self beforeAnimation];
174 | [UIView animateWithDuration: 1
175 | delay: 0.0f
176 | usingSpringWithDamping: 0.6f
177 | initialSpringVelocity: 0.9f
178 | options: UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionAllowUserInteraction
179 | animations: ^{
180 | helperSideView.center = CGPointMake(20, hei + 20);
181 | }
182 | completion: ^(BOOL finished) {
183 | [self finishAnimation];
184 | }];
185 |
186 | [UIView animateWithDuration:0.3 animations: ^{
187 | blurView.alpha = 0.0f;
188 | }];
189 |
190 | [self beforeAnimation];
191 | [UIView animateWithDuration: 1
192 | delay: 0.0f
193 | usingSpringWithDamping: 0.7f
194 | initialSpringVelocity: 2.0f
195 | options: UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionAllowUserInteraction
196 | animations: ^{
197 | helperCenterView.center = CGPointMake(wid / 2, hei + 20);
198 | }
199 | completion: ^(BOOL finished) {
200 | [self finishAnimation];
201 | }];
202 |
203 | triggered = NO;
204 |
205 | }
206 |
207 | //动画之前调用
208 | - (void) beforeAnimation{
209 | if (self.displayLink == nil) {
210 | self.displayLink = [CADisplayLink displayLinkWithTarget: self selector: @selector(displayLinkAction:)];
211 | [self.displayLink addToRunLoop: [NSRunLoop mainRunLoop] forMode: NSDefaultRunLoopMode];
212 | }
213 | self.animationCount ++;
214 | }
215 |
216 | //动画完成之后调用
217 | - (void) finishAnimation{
218 | self.animationCount --;
219 | if (self.animationCount == 0) {
220 | [self.displayLink invalidate];
221 | self.displayLink = nil;
222 | }
223 | }
224 |
225 | - (void) displayLinkAction: (CADisplayLink *)dis{
226 |
227 | CALayer *sideHelperPresentationLayer = (CALayer *)[helperSideView.layer presentationLayer];
228 | CALayer *centerHelperPresentationLayer = (CALayer *)[helperCenterView.layer presentationLayer];
229 |
230 | CGRect centerRect = [[centerHelperPresentationLayer valueForKeyPath:@"frame"] CGRectValue];
231 | CGRect sideRect = [[sideHelperPresentationLayer valueForKeyPath:@"frame"] CGRectValue];
232 |
233 | diff = sideRect.origin.y - centerRect.origin.y;
234 |
235 |
236 | // 重新布局方法
237 | // 在receiver标上一个需要被重新绘图的标记,在下一个draw周期自动重绘
238 | // 默认runloop周期 60Hz
239 | [self setNeedsDisplay];
240 | }
241 |
242 | @end
243 |
--------------------------------------------------------------------------------
/DGGooeySlide ObjC/DGGooeySlide.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | D53F27D91D0252E900A0704C /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = D53F27D81D0252E900A0704C /* main.m */; };
11 | D53F27DC1D0252E900A0704C /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = D53F27DB1D0252E900A0704C /* AppDelegate.m */; };
12 | D53F27DF1D0252E900A0704C /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D53F27DE1D0252E900A0704C /* ViewController.m */; };
13 | D53F27E21D0252E900A0704C /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D53F27E01D0252E900A0704C /* Main.storyboard */; };
14 | D53F27E41D0252E900A0704C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D53F27E31D0252E900A0704C /* Assets.xcassets */; };
15 | D53F27E71D0252E900A0704C /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D53F27E51D0252E900A0704C /* LaunchScreen.storyboard */; };
16 | D53F27F11D02548A00A0704C /* DGGooeySlideMenu.m in Sources */ = {isa = PBXBuildFile; fileRef = D53F27F01D02548A00A0704C /* DGGooeySlideMenu.m */; };
17 | /* End PBXBuildFile section */
18 |
19 | /* Begin PBXFileReference section */
20 | D53F27D41D0252E900A0704C /* DGGooeySlide.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DGGooeySlide.app; sourceTree = BUILT_PRODUCTS_DIR; };
21 | D53F27D81D0252E900A0704C /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
22 | D53F27DA1D0252E900A0704C /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
23 | D53F27DB1D0252E900A0704C /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
24 | D53F27DD1D0252E900A0704C /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; };
25 | D53F27DE1D0252E900A0704C /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; };
26 | D53F27E11D0252E900A0704C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
27 | D53F27E31D0252E900A0704C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
28 | D53F27E61D0252E900A0704C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
29 | D53F27E81D0252E900A0704C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
30 | D53F27EF1D02548A00A0704C /* DGGooeySlideMenu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DGGooeySlideMenu.h; sourceTree = ""; };
31 | D53F27F01D02548A00A0704C /* DGGooeySlideMenu.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DGGooeySlideMenu.m; sourceTree = ""; };
32 | /* End PBXFileReference section */
33 |
34 | /* Begin PBXFrameworksBuildPhase section */
35 | D53F27D11D0252E900A0704C /* Frameworks */ = {
36 | isa = PBXFrameworksBuildPhase;
37 | buildActionMask = 2147483647;
38 | files = (
39 | );
40 | runOnlyForDeploymentPostprocessing = 0;
41 | };
42 | /* End PBXFrameworksBuildPhase section */
43 |
44 | /* Begin PBXGroup section */
45 | D53F27CB1D0252E900A0704C = {
46 | isa = PBXGroup;
47 | children = (
48 | D53F27D61D0252E900A0704C /* DGGooeySlide */,
49 | D53F27D51D0252E900A0704C /* Products */,
50 | );
51 | sourceTree = "";
52 | };
53 | D53F27D51D0252E900A0704C /* Products */ = {
54 | isa = PBXGroup;
55 | children = (
56 | D53F27D41D0252E900A0704C /* DGGooeySlide.app */,
57 | );
58 | name = Products;
59 | sourceTree = "";
60 | };
61 | D53F27D61D0252E900A0704C /* DGGooeySlide */ = {
62 | isa = PBXGroup;
63 | children = (
64 | D53F27EE1D02539200A0704C /* Classes */,
65 | D53F27DA1D0252E900A0704C /* AppDelegate.h */,
66 | D53F27DB1D0252E900A0704C /* AppDelegate.m */,
67 | D53F27DD1D0252E900A0704C /* ViewController.h */,
68 | D53F27DE1D0252E900A0704C /* ViewController.m */,
69 | D53F27E01D0252E900A0704C /* Main.storyboard */,
70 | D53F27E31D0252E900A0704C /* Assets.xcassets */,
71 | D53F27E51D0252E900A0704C /* LaunchScreen.storyboard */,
72 | D53F27E81D0252E900A0704C /* Info.plist */,
73 | D53F27D71D0252E900A0704C /* Supporting Files */,
74 | );
75 | path = DGGooeySlide;
76 | sourceTree = "";
77 | };
78 | D53F27D71D0252E900A0704C /* Supporting Files */ = {
79 | isa = PBXGroup;
80 | children = (
81 | D53F27D81D0252E900A0704C /* main.m */,
82 | );
83 | name = "Supporting Files";
84 | sourceTree = "";
85 | };
86 | D53F27EE1D02539200A0704C /* Classes */ = {
87 | isa = PBXGroup;
88 | children = (
89 | D53F27EF1D02548A00A0704C /* DGGooeySlideMenu.h */,
90 | D53F27F01D02548A00A0704C /* DGGooeySlideMenu.m */,
91 | );
92 | name = Classes;
93 | sourceTree = "";
94 | };
95 | /* End PBXGroup section */
96 |
97 | /* Begin PBXNativeTarget section */
98 | D53F27D31D0252E900A0704C /* DGGooeySlide */ = {
99 | isa = PBXNativeTarget;
100 | buildConfigurationList = D53F27EB1D0252E900A0704C /* Build configuration list for PBXNativeTarget "DGGooeySlide" */;
101 | buildPhases = (
102 | D53F27D01D0252E900A0704C /* Sources */,
103 | D53F27D11D0252E900A0704C /* Frameworks */,
104 | D53F27D21D0252E900A0704C /* Resources */,
105 | );
106 | buildRules = (
107 | );
108 | dependencies = (
109 | );
110 | name = DGGooeySlide;
111 | productName = DGGooeySlide;
112 | productReference = D53F27D41D0252E900A0704C /* DGGooeySlide.app */;
113 | productType = "com.apple.product-type.application";
114 | };
115 | /* End PBXNativeTarget section */
116 |
117 | /* Begin PBXProject section */
118 | D53F27CC1D0252E900A0704C /* Project object */ = {
119 | isa = PBXProject;
120 | attributes = {
121 | CLASSPREFIX = DG;
122 | LastUpgradeCheck = 0730;
123 | ORGANIZATIONNAME = Desgard_Duan;
124 | TargetAttributes = {
125 | D53F27D31D0252E900A0704C = {
126 | CreatedOnToolsVersion = 7.3;
127 | DevelopmentTeam = C3JGTFM664;
128 | };
129 | };
130 | };
131 | buildConfigurationList = D53F27CF1D0252E900A0704C /* Build configuration list for PBXProject "DGGooeySlide" */;
132 | compatibilityVersion = "Xcode 3.2";
133 | developmentRegion = English;
134 | hasScannedForEncodings = 0;
135 | knownRegions = (
136 | en,
137 | Base,
138 | );
139 | mainGroup = D53F27CB1D0252E900A0704C;
140 | productRefGroup = D53F27D51D0252E900A0704C /* Products */;
141 | projectDirPath = "";
142 | projectRoot = "";
143 | targets = (
144 | D53F27D31D0252E900A0704C /* DGGooeySlide */,
145 | );
146 | };
147 | /* End PBXProject section */
148 |
149 | /* Begin PBXResourcesBuildPhase section */
150 | D53F27D21D0252E900A0704C /* Resources */ = {
151 | isa = PBXResourcesBuildPhase;
152 | buildActionMask = 2147483647;
153 | files = (
154 | D53F27E71D0252E900A0704C /* LaunchScreen.storyboard in Resources */,
155 | D53F27E41D0252E900A0704C /* Assets.xcassets in Resources */,
156 | D53F27E21D0252E900A0704C /* Main.storyboard in Resources */,
157 | );
158 | runOnlyForDeploymentPostprocessing = 0;
159 | };
160 | /* End PBXResourcesBuildPhase section */
161 |
162 | /* Begin PBXSourcesBuildPhase section */
163 | D53F27D01D0252E900A0704C /* Sources */ = {
164 | isa = PBXSourcesBuildPhase;
165 | buildActionMask = 2147483647;
166 | files = (
167 | D53F27DF1D0252E900A0704C /* ViewController.m in Sources */,
168 | D53F27F11D02548A00A0704C /* DGGooeySlideMenu.m in Sources */,
169 | D53F27DC1D0252E900A0704C /* AppDelegate.m in Sources */,
170 | D53F27D91D0252E900A0704C /* main.m in Sources */,
171 | );
172 | runOnlyForDeploymentPostprocessing = 0;
173 | };
174 | /* End PBXSourcesBuildPhase section */
175 |
176 | /* Begin PBXVariantGroup section */
177 | D53F27E01D0252E900A0704C /* Main.storyboard */ = {
178 | isa = PBXVariantGroup;
179 | children = (
180 | D53F27E11D0252E900A0704C /* Base */,
181 | );
182 | name = Main.storyboard;
183 | sourceTree = "";
184 | };
185 | D53F27E51D0252E900A0704C /* LaunchScreen.storyboard */ = {
186 | isa = PBXVariantGroup;
187 | children = (
188 | D53F27E61D0252E900A0704C /* Base */,
189 | );
190 | name = LaunchScreen.storyboard;
191 | sourceTree = "";
192 | };
193 | /* End PBXVariantGroup section */
194 |
195 | /* Begin XCBuildConfiguration section */
196 | D53F27E91D0252E900A0704C /* Debug */ = {
197 | isa = XCBuildConfiguration;
198 | buildSettings = {
199 | ALWAYS_SEARCH_USER_PATHS = NO;
200 | CLANG_ANALYZER_NONNULL = YES;
201 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
202 | CLANG_CXX_LIBRARY = "libc++";
203 | CLANG_ENABLE_MODULES = YES;
204 | CLANG_ENABLE_OBJC_ARC = YES;
205 | CLANG_WARN_BOOL_CONVERSION = YES;
206 | CLANG_WARN_CONSTANT_CONVERSION = YES;
207 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
208 | CLANG_WARN_EMPTY_BODY = YES;
209 | CLANG_WARN_ENUM_CONVERSION = YES;
210 | CLANG_WARN_INT_CONVERSION = YES;
211 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
212 | CLANG_WARN_UNREACHABLE_CODE = YES;
213 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
214 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
215 | COPY_PHASE_STRIP = NO;
216 | DEBUG_INFORMATION_FORMAT = dwarf;
217 | ENABLE_STRICT_OBJC_MSGSEND = YES;
218 | ENABLE_TESTABILITY = YES;
219 | GCC_C_LANGUAGE_STANDARD = gnu99;
220 | GCC_DYNAMIC_NO_PIC = NO;
221 | GCC_NO_COMMON_BLOCKS = YES;
222 | GCC_OPTIMIZATION_LEVEL = 0;
223 | GCC_PREPROCESSOR_DEFINITIONS = (
224 | "DEBUG=1",
225 | "$(inherited)",
226 | );
227 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
228 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
229 | GCC_WARN_UNDECLARED_SELECTOR = YES;
230 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
231 | GCC_WARN_UNUSED_FUNCTION = YES;
232 | GCC_WARN_UNUSED_VARIABLE = YES;
233 | IPHONEOS_DEPLOYMENT_TARGET = 9.3;
234 | MTL_ENABLE_DEBUG_INFO = YES;
235 | ONLY_ACTIVE_ARCH = YES;
236 | SDKROOT = iphoneos;
237 | };
238 | name = Debug;
239 | };
240 | D53F27EA1D0252E900A0704C /* Release */ = {
241 | isa = XCBuildConfiguration;
242 | buildSettings = {
243 | ALWAYS_SEARCH_USER_PATHS = NO;
244 | CLANG_ANALYZER_NONNULL = YES;
245 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
246 | CLANG_CXX_LIBRARY = "libc++";
247 | CLANG_ENABLE_MODULES = YES;
248 | CLANG_ENABLE_OBJC_ARC = YES;
249 | CLANG_WARN_BOOL_CONVERSION = YES;
250 | CLANG_WARN_CONSTANT_CONVERSION = YES;
251 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
252 | CLANG_WARN_EMPTY_BODY = YES;
253 | CLANG_WARN_ENUM_CONVERSION = YES;
254 | CLANG_WARN_INT_CONVERSION = YES;
255 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
256 | CLANG_WARN_UNREACHABLE_CODE = YES;
257 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
258 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
259 | COPY_PHASE_STRIP = NO;
260 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
261 | ENABLE_NS_ASSERTIONS = NO;
262 | ENABLE_STRICT_OBJC_MSGSEND = YES;
263 | GCC_C_LANGUAGE_STANDARD = gnu99;
264 | GCC_NO_COMMON_BLOCKS = YES;
265 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
266 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
267 | GCC_WARN_UNDECLARED_SELECTOR = YES;
268 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
269 | GCC_WARN_UNUSED_FUNCTION = YES;
270 | GCC_WARN_UNUSED_VARIABLE = YES;
271 | IPHONEOS_DEPLOYMENT_TARGET = 9.3;
272 | MTL_ENABLE_DEBUG_INFO = NO;
273 | SDKROOT = iphoneos;
274 | VALIDATE_PRODUCT = YES;
275 | };
276 | name = Release;
277 | };
278 | D53F27EC1D0252E900A0704C /* Debug */ = {
279 | isa = XCBuildConfiguration;
280 | buildSettings = {
281 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
282 | CODE_SIGN_IDENTITY = "iPhone Developer";
283 | INFOPLIST_FILE = DGGooeySlide/Info.plist;
284 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
285 | PRODUCT_BUNDLE_IDENTIFIER = desgard.express.DGGooeySlide;
286 | PRODUCT_NAME = "$(TARGET_NAME)";
287 | };
288 | name = Debug;
289 | };
290 | D53F27ED1D0252E900A0704C /* Release */ = {
291 | isa = XCBuildConfiguration;
292 | buildSettings = {
293 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
294 | CODE_SIGN_IDENTITY = "iPhone Developer";
295 | INFOPLIST_FILE = DGGooeySlide/Info.plist;
296 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
297 | PRODUCT_BUNDLE_IDENTIFIER = desgard.express.DGGooeySlide;
298 | PRODUCT_NAME = "$(TARGET_NAME)";
299 | };
300 | name = Release;
301 | };
302 | /* End XCBuildConfiguration section */
303 |
304 | /* Begin XCConfigurationList section */
305 | D53F27CF1D0252E900A0704C /* Build configuration list for PBXProject "DGGooeySlide" */ = {
306 | isa = XCConfigurationList;
307 | buildConfigurations = (
308 | D53F27E91D0252E900A0704C /* Debug */,
309 | D53F27EA1D0252E900A0704C /* Release */,
310 | );
311 | defaultConfigurationIsVisible = 0;
312 | defaultConfigurationName = Release;
313 | };
314 | D53F27EB1D0252E900A0704C /* Build configuration list for PBXNativeTarget "DGGooeySlide" */ = {
315 | isa = XCConfigurationList;
316 | buildConfigurations = (
317 | D53F27EC1D0252E900A0704C /* Debug */,
318 | D53F27ED1D0252E900A0704C /* Release */,
319 | );
320 | defaultConfigurationIsVisible = 0;
321 | };
322 | /* End XCConfigurationList section */
323 | };
324 | rootObject = D53F27CC1D0252E900A0704C /* Project object */;
325 | }
326 |
--------------------------------------------------------------------------------