Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Mod Med Animation #2

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions SVProgressHUD.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
6A58C8EC1CAE62F400BF604D /* SVProgressAnimatedView.h in Headers */ = {isa = PBXBuildFile; fileRef = 6A58C8EA1CAE62F400BF604D /* SVProgressAnimatedView.h */; };
6A58C8ED1CAE62F400BF604D /* SVProgressAnimatedView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A58C8EB1CAE62F400BF604D /* SVProgressAnimatedView.m */; };
6A58C8EE1CAE62F400BF604D /* SVProgressAnimatedView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A58C8EB1CAE62F400BF604D /* SVProgressAnimatedView.m */; };
A61C76D1211E289F00D43B8A /* MMLogoAnimatedView.m in Sources */ = {isa = PBXBuildFile; fileRef = A61C76CF211E289E00D43B8A /* MMLogoAnimatedView.m */; };
A63CC6AB211E2CD30086E839 /* MMLogoAnimatedView.m in Sources */ = {isa = PBXBuildFile; fileRef = A61C76CF211E289E00D43B8A /* MMLogoAnimatedView.m */; };
/* End PBXBuildFile section */

/* Begin PBXCopyFilesBuildPhase section */
Expand Down Expand Up @@ -52,6 +54,8 @@
65F0220D15C858060030BBEF /* SVProgressHUD.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = SVProgressHUD.bundle; sourceTree = "<group>"; };
6A58C8EA1CAE62F400BF604D /* SVProgressAnimatedView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SVProgressAnimatedView.h; sourceTree = "<group>"; };
6A58C8EB1CAE62F400BF604D /* SVProgressAnimatedView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SVProgressAnimatedView.m; sourceTree = "<group>"; };
A61C76CF211E289E00D43B8A /* MMLogoAnimatedView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MMLogoAnimatedView.m; sourceTree = "<group>"; };
A61C76D0211E289E00D43B8A /* MMLogoAnimatedView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MMLogoAnimatedView.h; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -119,6 +123,8 @@
65F0220115C857EF0030BBEF /* SVProgressHUD */ = {
isa = PBXGroup;
children = (
A61C76D0211E289E00D43B8A /* MMLogoAnimatedView.h */,
A61C76CF211E289E00D43B8A /* MMLogoAnimatedView.m */,
3CB14F9A1AFBCB57003C2641 /* SVRadialGradientLayer.h */,
3CB14F9B1AFBCB57003C2641 /* SVRadialGradientLayer.m */,
65F0220415C857EF0030BBEF /* SVProgressHUD.h */,
Expand Down Expand Up @@ -244,6 +250,7 @@
4A9D7DF11AB345DD0039B273 /* SVProgressHUD.m in Sources */,
3CB14F9E1AFBCB57003C2641 /* SVRadialGradientLayer.m in Sources */,
4A9D7DF21AB345DD0039B273 /* SVIndefiniteAnimatedView.m in Sources */,
A63CC6AB211E2CD30086E839 /* MMLogoAnimatedView.m in Sources */,
6A58C8EE1CAE62F400BF604D /* SVProgressAnimatedView.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand All @@ -255,6 +262,7 @@
65F0220715C857EF0030BBEF /* SVProgressHUD.m in Sources */,
3CB14F9D1AFBCB57003C2641 /* SVRadialGradientLayer.m in Sources */,
4A9D7DD11AB345540039B273 /* SVIndefiniteAnimatedView.m in Sources */,
A61C76D1211E289F00D43B8A /* MMLogoAnimatedView.m in Sources */,
6A58C8ED1CAE62F400BF604D /* SVProgressAnimatedView.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
20 changes: 20 additions & 0 deletions SVProgressHUD/MMLogoAnimatedView.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// MMLogoAnimatedView.h
// SVProgressHUD
//
// Created by Jing Wei Li on 8/9/18.
// Copyright © 2018 Modernizing Medicine. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface MMLogoAnimatedView : UIView

@property (nonatomic, assign) CGFloat diameter;
@property (nonatomic, assign) CFTimeInterval duration;
@property (nonatomic, strong) UIColor *strokeColor;
@property (nonatomic, assign) CGFloat offsetToCenter;

- (void)layoutAnimatedLayer;

@end
127 changes: 127 additions & 0 deletions SVProgressHUD/MMLogoAnimatedView.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
//
// MMLogoAnimatedView.m
// SVProgressHUD
//
// Created by Jing Wei Li on 8/9/18.
// Copyright © 2018 Modernizing Medicine. All rights reserved.
//

#import "MMLogoAnimatedView.h"

static NSString * const ringAnimationKey = @"ringAnimationKey";
static NSString * const heartbeatAnimationKey = @"heartbeatAnimationKey";
static CGFloat const ringStrokeWidth = 2.0;
static CGFloat const heartbeatStrokeWidth = 5.0;

@interface MMLogoAnimatedView()

@property (nonatomic, strong) CAShapeLayer *ringLayer;
@property (nonatomic, strong) CAShapeLayer *heartbeatLayer;

@end

@implementation MMLogoAnimatedView

- (void)willMoveToSuperview:(UIView *)newSuperview {
if (!newSuperview) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should do

if (newSuperview == nil) {
}

[self.ringLayer removeFromSuperlayer];
[self.heartbeatLayer removeFromSuperlayer];
self.ringLayer = nil;
self.heartbeatLayer = nil;
}
}

- (void)layoutAnimatedLayer {
self.ringLayer = [self createRingLayer];
self.heartbeatLayer = [self createHeartbeatLayer];
[self.layer addSublayer:self.ringLayer];
[self.layer addSublayer:self.heartbeatLayer];
}

- (void)setFrame:(CGRect)frame {
if(!CGRectEqualToRect(frame, super.frame)) {
[super setFrame:frame];
if(self.superview) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should do

if (self.superview != nil) {
}

self.offsetToCenter = self.diameter < self.superview.bounds.size.width ? (self.superview.bounds.size.width - self.diameter) / 2 : 0;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can make this more debug friendly by doing:

CGFloat superviewWidth = CGRectGetWidth(self.superview.bounds);
BOOL diameterLessThatSuperviewWidth = self.diameter < superviewWidth;
self.offsetToCenter = diameterLessThatSuperviewWidth ? (superviewWidth - self.diameter) / 2 : 0;

[self layoutAnimatedLayer];
}
}

}

- (CAShapeLayer *)createRingLayer {
if (!self.ringLayer) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

UIBezierPath *path = [[UIBezierPath alloc] init];
CGFloat centerLength = self.offsetToCenter + (self.diameter / 2.0);
[path addArcWithCenter:CGPointMake(centerLength, centerLength)
radius:self.diameter / 2
startAngle:0.09 * M_PI
endAngle:2.09 * M_PI
clockwise:YES];

self.ringLayer = [CAShapeLayer layer];
CAAnimationGroup *animationGroup = [self createReversibleAnimationOnLayer:self.ringLayer
fromBezierPath:path
strokeWidth:ringStrokeWidth];

[self.ringLayer addAnimation:animationGroup forKey:ringAnimationKey];
}

return self.ringLayer;
}

- (CAShapeLayer *)createHeartbeatLayer {
if (!self.heartbeatLayer) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

UIBezierPath *path = [[UIBezierPath alloc] init];
[path moveToPoint:CGPointMake(self.offsetToCenter + self.diameter * 0.06, self.offsetToCenter + self.diameter * 0.69)];
[path addLineToPoint:CGPointMake(self.offsetToCenter + self.diameter * 0.25, self.offsetToCenter + self.diameter * 0.69)];
[path addLineToPoint:CGPointMake(self.offsetToCenter + self.diameter * 0.33, self.offsetToCenter + self.diameter * 0.41)];
[path addLineToPoint:CGPointMake(self.offsetToCenter + self.diameter * 0.46, self.offsetToCenter + self.diameter * 0.76)];
[path addLineToPoint:CGPointMake(self.offsetToCenter + self.diameter * 0.63, self.offsetToCenter + self.diameter * 0.24)];
[path addLineToPoint:CGPointMake(self.offsetToCenter + self.diameter * 0.73, self.offsetToCenter + self.diameter * 0.62)];
[path addLineToPoint:CGPointMake(self.offsetToCenter + self.diameter * 0.95, self.offsetToCenter + self.diameter * 0.62)];

self.heartbeatLayer = [CAShapeLayer layer];
CAAnimationGroup *animationGroup = [self createReversibleAnimationOnLayer:self.heartbeatLayer
fromBezierPath:path
strokeWidth:heartbeatStrokeWidth];
[self.heartbeatLayer addAnimation:animationGroup forKey:heartbeatAnimationKey];
}

return self.heartbeatLayer;
}

- (CAAnimationGroup *)createReversibleAnimationOnLayer:(CAShapeLayer *)shapeLayer
fromBezierPath:(UIBezierPath *)bezierPath
strokeWidth:(CGFloat)strokeWidth {

shapeLayer.path = bezierPath.CGPath;
shapeLayer.fillColor = nil;
shapeLayer.strokeColor = self.strokeColor.CGColor;
shapeLayer.lineWidth = strokeWidth;
shapeLayer.lineCap = kCALineCapRound;
shapeLayer.lineJoin = kCALineJoinRound;

CABasicAnimation *forwardAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
forwardAnimation.fromValue = @1.0;
forwardAnimation.toValue = @0.0;
forwardAnimation.duration = self.duration;
forwardAnimation.beginTime = 0.0;

CABasicAnimation *reverseAnimation = [CABasicAnimation animationWithKeyPath:@"strokeStart"];
reverseAnimation.fromValue = @1.0;
reverseAnimation.toValue = @0.0;
reverseAnimation.duration = self.duration;
reverseAnimation.beginTime = self.duration;

CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
animationGroup.animations = @[forwardAnimation, reverseAnimation];
animationGroup.repeatCount = INFINITY;
animationGroup.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
animationGroup.autoreverses = YES;
animationGroup.duration = self.duration * 2;

return animationGroup;
}

@end
6 changes: 6 additions & 0 deletions SVProgressHUD/SVProgressHUD.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,12 @@ typedef void (^SVProgressHUDDismissCompletion)(void);
+ (void)setMaxSupportedWindowLevel:(UIWindowLevel)windowLevel; // default is UIWindowLevelNormal
+ (void)setHapticsEnabled:(BOOL)hapticsEnabled; // default is NO

// ModMed Logo Animations
+ (void)enableModMedAnimation;
+ (void)setModMedAnimationDuration:(CFTimeInterval)interval; // default is 1 second
+ (void)setModMedAnimationColor:(UIColor *)color; // default is the Mod Med purple
+ (void)setModMedAnimationDiameter:(CGFloat)diameter; // default is 60.0 points

#pragma mark - Show Methods

+ (void)show;
Expand Down
80 changes: 76 additions & 4 deletions SVProgressHUD/SVProgressHUD.m
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#import "SVIndefiniteAnimatedView.h"
#import "SVProgressAnimatedView.h"
#import "SVRadialGradientLayer.h"
#import "MMLogoAnimatedView.h"

#ifndef kCFCoreFoundationVersionNumber_iOS_9_0
#define kCFCoreFoundationVersionNumber_iOS_9_0 1240.1
Expand Down Expand Up @@ -54,6 +55,7 @@ @interface SVProgressHUD ()
@property (nonatomic, strong) UIView *indefiniteAnimatedView;
@property (nonatomic, strong) SVProgressAnimatedView *ringView;
@property (nonatomic, strong) SVProgressAnimatedView *backgroundRingView;
@property (nonatomic, strong) MMLogoAnimatedView *logoView;

@property (nonatomic, readwrite) CGFloat progress;
@property (nonatomic, readwrite) NSUInteger activityCount;
Expand Down Expand Up @@ -97,6 +99,13 @@ - (void)cancelIndefiniteAnimatedViewAnimation;
- (UIColor*)foregroundColorForStyle;
- (UIColor*)backgroundColorForStyle;

// properties for ModMed Animations
@property (assign, nonatomic) BOOL isModMedAnimationEnabled;
@property (assign, nonatomic) CFTimeInterval modMedAnimationDuration;
@property (assign, nonatomic) CGFloat modMedAnimationDiameter;
@property (strong, nonatomic) UIColor *modMedAnimationColor;


@end

@implementation SVProgressHUD {
Expand Down Expand Up @@ -229,6 +238,23 @@ + (void)setHapticsEnabled:(BOOL)hapticsEnabled {
[self sharedView].hapticsEnabled = hapticsEnabled;
}

+ (void)enableModMedAnimation {
[self sharedView].isModMedAnimationEnabled = YES;
}

+ (void)setModMedAnimationColor:(UIColor *)color {
[self sharedView].modMedAnimationColor = color;
}

+ (void)setModMedAnimationDuration:(CFTimeInterval)interval {
[self sharedView].modMedAnimationDuration = interval;
}

+ (void)setModMedAnimationDiameter:(CGFloat)diameter {
[self sharedView].modMedAnimationDiameter = diameter;
}


#pragma mark - Show Methods

+ (void)show {
Expand Down Expand Up @@ -526,6 +552,12 @@ - (void)updateHUDFrame {
self.backgroundRingView.center = self.ringView.center = CGPointMake(CGRectGetMidX(self.hudView.bounds), centerY);
}
self.imageView.center = CGPointMake(CGRectGetMidX(self.hudView.bounds), centerY);

if (self.logoView) {
BOOL isCentering = self.logoView.diameter < self.hudView.bounds.size.width;
self.logoView.offsetToCenter = isCentering ? (self.hudView.bounds.size.width - self.logoView.diameter) / 2 : 0;
[self.logoView layoutAnimatedLayer];
}

// Label
if(imageUsed || progressUsed) {
Expand Down Expand Up @@ -835,13 +867,28 @@ - (void)showProgress:(float)progress status:(NSString*)status {
[strongSelf cancelRingLayerAnimation];

// Add indefiniteAnimatedView to HUD

if (self.isModMedAnimationEnabled) {
[strongSelf cancelModMedAnimation];
// Add mod med logo view to HUD
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
[strongSelf.hudVibrancyView.contentView addSubview:strongSelf.indefiniteAnimatedView];
[strongSelf.hudVibrancyView.contentView addSubview:[strongSelf MMLogoAnimatedView]];
#else
[strongSelf.hudView addSubview:strongSelf.indefiniteAnimatedView];
[strongSelf.hudView addSubview:[strongSelf MMLogoAnimatedView]];
#endif
if([strongSelf.indefiniteAnimatedView respondsToSelector:@selector(startAnimating)]) {
[(id)strongSelf.indefiniteAnimatedView startAnimating];
if([strongSelf.logoView respondsToSelector:@selector(startAnimating)]) {
[(id)strongSelf.logoView startAnimating];
}
} else {
// Add indefiniteAnimatedView to HUD
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
[strongSelf.hudVibrancyView.contentView addSubview:strongSelf.indefiniteAnimatedView];
#else
[strongSelf.hudView addSubview:strongSelf.indefiniteAnimatedView];
#endif
if([strongSelf.indefiniteAnimatedView respondsToSelector:@selector(startAnimating)]) {
[(id)strongSelf.indefiniteAnimatedView startAnimating];
}
}

// Update the activity count
Expand Down Expand Up @@ -1191,6 +1238,16 @@ - (SVProgressAnimatedView*)backgroundRingView {

return _backgroundRingView;
}

- (MMLogoAnimatedView *)MMLogoAnimatedView {
self.logoView = [[MMLogoAnimatedView alloc] initWithFrame:CGRectZero];
self.logoView.duration = self.modMedAnimationDuration ?: 1.0;
self.logoView.strokeColor = self.modMedAnimationColor ?: [UIColor colorWithRed:78/255.0 green:42/255.0 blue:129/255.0 alpha:1];
self.logoView.diameter = self.modMedAnimationDiameter ?: 60.0;

return self.logoView;
}


- (void)cancelRingLayerAnimation {
// Animate value update, stop animation
Expand All @@ -1206,6 +1263,21 @@ - (void)cancelRingLayerAnimation {
[self.ringView removeFromSuperview];
[self.backgroundRingView removeFromSuperview];
}

- (void)cancelModMedAnimation {
[CATransaction begin];
[CATransaction setDisableActions:YES];

[self.hudView.layer removeAllAnimations];

[CATransaction commit];

if (self.logoView) {
[self.logoView removeFromSuperview];
self.logoView = nil;
}
[self.backgroundView removeFromSuperview];
}

- (void)cancelIndefiniteAnimatedViewAnimation {
// Stop animation
Expand Down