Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save erkanyildiz/4976ae3a13419cc1f6d6 to your computer and use it in GitHub Desktop.
Save erkanyildiz/4976ae3a13419cc1f6d6 to your computer and use it in GitHub Desktop.
Infinite Equilateral Triangle Animation as Activity Indicator
// erkanyildiz
// 20150813-1940
//
// EYInfiniteEquilateralTriangleAnimationView.h
#import <UIKit/UIKit.h>
@interface EYInfiniteEquilateralTriangleAnimationView : UIView
- (instancetype) initWithSide:(CGFloat)side andCenter:(CGPoint)center;
- (void) start;
@end
// erkanyildiz
// 20150813-1940
//
// EYInfiniteEquilateralTriangleAnimationView.m
#import "EYInfiniteEquilateralTriangleAnimationView.h"
@interface EYInfiniteEquilateralTriangleAnimationView ()
{
UIView* tUp;
UIView* tLeft;
UIView* tRight;
UIView* tCenter;
NSArray* minors;
CGFloat _side;
#define DURA 4.0
#define SCALE 2.0
#define SHRINK 0.3
#define D2R(angle) ((angle) * M_PI / 180.0)
}
@end
@implementation EYInfiniteEquilateralTriangleAnimationView
-(instancetype) initWithSide:(CGFloat)side andCenter:(CGPoint)center
{
_side = side;
CGFloat containerSide = side * 2 * sqrt(3) / 3.0;
typeof(self) infiniteTriangle = [self initWithFrame:(CGRect){center.x - containerSide * 0.5 , center.y - containerSide * 0.5, containerSide, containerSide}];
CGFloat minorTriangleSide = side * 0.5;
CGPoint cUp = (CGPoint){containerSide * 0.5, minorTriangleSide * 0.5 * 2 * sqrt(3) / 3.0};
CGPoint cLeft = cUp;
cLeft.x -= minorTriangleSide * 0.5;
cLeft.y += minorTriangleSide * 0.5 * sqrt(3);
CGPoint cRight = cLeft;
cRight.x += minorTriangleSide;
CGPoint cCenter = (CGPoint){containerSide * 0.5, containerSide * 0.5};
tUp = [self minorEquilateralTriangleWithCenter:cUp];
tLeft = [self minorEquilateralTriangleWithCenter:cLeft];
tRight = [self minorEquilateralTriangleWithCenter:cRight];
tCenter = [self minorEquilateralTriangleWithCenter:cCenter];
tCenter.transform = CGAffineTransformMakeRotation(D2R(180));
minors = [NSArray arrayWithObjects:tUp,tLeft,tRight,tCenter, nil];
[minors enumerateObjectsUsingBlock:^(UIView* v, NSUInteger idx, BOOL *stop)
{
[self addSubview:v];
}];
return infiniteTriangle;
}
#pragma mark -
-(void)start
{
[self rotate];
[self scale];
[self moveOut];
}
-(void)reset
{
[self.layer removeAllAnimations];
self.transform = CGAffineTransformIdentity;
[minors enumerateObjectsUsingBlock:^(UIView* v, NSUInteger idx, BOOL *stop)
{
if(v != tCenter)
{
[v.layer removeAllAnimations];
v.alpha = 1;
v.transform = CGAffineTransformIdentity;
}
}];
}
#pragma mark -
-(void)rotate
{
[UIView animateWithDuration:DURA * 0.5 delay:0 options:UIViewAnimationOptionCurveLinear animations:^
{
self.transform = CGAffineTransformRotate(self.transform, D2R(150));
}completion:nil];
[UIView animateWithDuration:DURA * 0.5 delay:DURA * 0.5 options:UIViewAnimationOptionCurveLinear animations:^
{
self.transform = CGAffineTransformRotate(self.transform, D2R(150));
}
completion:^(BOOL finished)
{
[self reset];
[self start];
}];
}
-(void)scale
{
[UIView animateWithDuration:DURA delay:0 options:UIViewAnimationOptionCurveLinear animations:^
{
self.transform = CGAffineTransformScale(self.transform, SCALE, SCALE);
}completion:nil];
}
-(void)moveOut
{
float moveOutDistance = _side * 0.2;
[UIView animateWithDuration:DURA / 3.0 delay:DURA * 0.0 / 3.0 options:0 animations:^
{
tUp.transform = CGAffineTransformScale(CGAffineTransformMakeTranslation(0, -moveOutDistance), SHRINK, SHRINK);
tUp.alpha = 0;
}completion:nil];
[UIView animateWithDuration:DURA / 3.0 delay:DURA * 1.0 / 3.0 options:0 animations:^
{
tRight.transform = CGAffineTransformScale(CGAffineTransformMakeTranslation(0.65 * moveOutDistance * sqrt(3), 0.65 * moveOutDistance), SHRINK, SHRINK);
tRight.alpha = 0;
}completion:nil];
[UIView animateWithDuration:DURA / 3.0 delay:DURA * 2.0 / 3.0 options:0 animations:^
{
tLeft.transform = CGAffineTransformScale(CGAffineTransformMakeTranslation(-0.78 * moveOutDistance * sqrt(3), 0.78 * moveOutDistance), SHRINK, SHRINK);
tLeft.alpha = 0;
}completion:nil];
}
#pragma mark -
-(UIView*)minorEquilateralTriangleWithCenter:(CGPoint)center
{
CGFloat minorSide = _side * 0.5;
CGFloat minorContainerSide = _side * 0.5 * (sqrt(3) * 2.0 / 3.0);
UIView* minorTriangleView = [UIView.alloc initWithFrame:(CGRect){center.x - minorContainerSide * 0.5 , center.y - minorContainerSide * 0.5, minorContainerSide, minorContainerSide}];
CGPoint top = (CGPoint){minorContainerSide * 0.5, 0.0};
CGPoint left = (CGPoint){(minorContainerSide - minorSide) * 0.5, minorSide * 0.5 * sqrt(3)};
CGPoint right = left;
right.x += minorSide;
UIBezierPath* trianglePath = [UIBezierPath bezierPath];
[trianglePath moveToPoint:top];
[trianglePath addLineToPoint:left];
[trianglePath addLineToPoint:right];
[trianglePath closePath];
CAShapeLayer* triangleLayer = CAShapeLayer.layer;
triangleLayer.path = trianglePath.CGPath;
triangleLayer.lineWidth = 0.33;
triangleLayer.strokeColor = UIColor.blackColor.CGColor;
triangleLayer.lineCap = @"round";
triangleLayer.fillColor = UIColor.blackColor.CGColor;
[minorTriangleView.layer addSublayer:triangleLayer];
return minorTriangleView;
}
-(void) setBackgroundColor:(UIColor *)backgroundColor
{
[super setBackgroundColor:UIColor.clearColor];
[minors enumerateObjectsUsingBlock:^(UIView* v, NSUInteger idx, BOOL *stop)
{
((CAShapeLayer*)v.layer.sublayers.firstObject).fillColor = backgroundColor.CGColor;
((CAShapeLayer*)v.layer.sublayers.firstObject).strokeColor = backgroundColor.CGColor;
}];
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment