Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -20,47 +20,28 @@ @implementation MONViewController

- (void)viewDidLoad {
[super viewDidLoad];

MONActivityIndicatorView *indicatorView = [[MONActivityIndicatorView alloc] init];
indicatorView.delegate = self;
indicatorView.numberOfCircles = 3;
indicatorView.radius = 20;
indicatorView.internalSpacing = 3;
// indicatorView.delegate = self;
[indicatorView startAnimating];

indicatorView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:indicatorView];
[self placeAtTheCenterWithView:indicatorView];

NSDictionary *views = @{ @"indicatorView" : indicatorView,
@"superview" : self.view };
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[superview]-(<=1)-[indicatorView]" options:NSLayoutFormatAlignAllCenterX metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[superview]-(<=1)-[indicatorView]" options:NSLayoutFormatAlignAllCenterY metrics:nil views:views]];

[NSTimer scheduledTimerWithTimeInterval:7 target:indicatorView selector:@selector(stopAnimating) userInfo:nil repeats:NO];
[NSTimer scheduledTimerWithTimeInterval:9 target:indicatorView selector:@selector(startAnimating) userInfo:nil repeats:NO];
}

#pragma mark -
#pragma mark - Centering Indicator View

- (void)placeAtTheCenterWithView:(UIView *)view {
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterX
multiplier:1.0f
constant:0.0f]];

[self.view addConstraint:[NSLayoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterY
multiplier:1.0f
constant:0.0f]];
}

#pragma mark -
#pragma mark - MONActivityIndicatorViewDelegate Methods

- (UIColor *)activityIndicatorView:(MONActivityIndicatorView *)activityIndicatorView
circleBackgroundColorAtIndex:(NSUInteger)index {
- (UIColor *)activityIndicatorView:(MONActivityIndicatorView *)activityIndicatorView dotColorAtIndex:(NSUInteger)index {
CGFloat red = (arc4random() % 256)/255.0;
CGFloat green = (arc4random() % 256)/255.0;
CGFloat blue = (arc4random() % 256)/255.0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,25 @@

@protocol MONActivityIndicatorViewDelegate;

@interface MONActivityIndicatorView : UIView
@interface MONActivityIndicatorView : UIView <UIAppearanceContainer>

/** The number of circle indicators. */
@property (readwrite, nonatomic) NSUInteger numberOfCircles;
@property (nonatomic) IBInspectable NSUInteger numberOfCircles; //UI_APPEARANCE_SELECTOR

/** The spacing between circles. */
@property (readwrite, nonatomic) CGFloat internalSpacing;
@property (nonatomic) IBInspectable CGFloat internalSpacing; //UI_APPEARANCE_SELECTOR

/** The radius of each circle. */
@property (readwrite, nonatomic) CGFloat radius;
@property (nonatomic) IBInspectable CGFloat radius; //UI_APPEARANCE_SELECTOR

/** The base animation delay of each circle. */
@property (readwrite, nonatomic) CGFloat delay;
@property (nonatomic) IBInspectable CGFloat delay; //UI_APPEARANCE_SELECTOR

/** The base animation duration of each circle*/
@property (readwrite, nonatomic) CGFloat duration;
@property (nonatomic) IBInspectable CGFloat duration; //UI_APPEARANCE_SELECTOR

/** The assigned delegate */
@property (weak, nonatomic) id<MONActivityIndicatorViewDelegate> delegate;
@property (nonatomic, weak) id<MONActivityIndicatorViewDelegate> delegate;


/**
Expand All @@ -51,7 +51,6 @@
@param index The index of a particular circle.
@return The background color of a particular circle.
*/
- (UIColor *)activityIndicatorView:(MONActivityIndicatorView *)activityIndicatorView
circleBackgroundColorAtIndex:(NSUInteger)index;
- (UIColor *)activityIndicatorView:(MONActivityIndicatorView *)activityIndicatorView dotColorAtIndex:(NSUInteger)index;

@end
Original file line number Diff line number Diff line change
Expand Up @@ -7,78 +7,33 @@
#import <QuartzCore/QuartzCore.h>
#import "MONActivityIndicatorView.h"

@interface MONActivityIndicatorView ()

/** The default color of each circle. */
@property (strong, nonatomic) UIColor *defaultColor;

/** An indicator whether the activity indicator view is animating. */
@property (readwrite, nonatomic) BOOL isAnimating;
@interface MONActivityIndicatorView ()

/**
Sets up default values
*/
- (void)setupDefaults;

/**
Adds circles.
*/
- (void)addCircles;

/**
Removes circles.
*/
- (void)removeCircles;
/** An indicator whether the activity indicator view is animating. */
@property (nonatomic) BOOL isAnimating;

/**
Creates the circle view.
@param radius The radius of the circle.
@param color The background color of the circle.
@param positionX The x-position of the circle in the contentView.
@return The circle view.
*/
- (UIView *)createCircleWithRadius:(CGFloat)radius color:(UIColor *)color positionX:(CGFloat)x;

/**
Creates the animation of the circle.
@param duration The duration of the animation.
@param delay The delay of the animation
@return The animation of the circle.
*/
- (CABasicAnimation *)createAnimationWithDuration:(CGFloat)duration delay:(CGFloat)delay;

@end



@implementation MONActivityIndicatorView

#pragma mark -
#pragma mark - Initializations

- (id)init {
self = [super initWithFrame:CGRectZero];
if (self) {
[self setupDefaults];
}
return self;
}

- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self setupDefaults];
}
return self;
}
@synthesize numberOfCircles = _numberOfCircles;
@synthesize internalSpacing = _internalSpacing;
@synthesize radius = _radius;
@synthesize delay = _delay;
@synthesize duration = _duration;


- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
[self setupDefaults];
}
return self;
}

#pragma mark -
#pragma mark - Intrinsic Content Size

- (CGSize)intrinsicContentSize {
Expand All @@ -87,29 +42,46 @@ - (CGSize)intrinsicContentSize {
return CGSizeMake(width, height);
}

#pragma mark -


#pragma mark - Private Methods

- (void)setupDefaults {
self.translatesAutoresizingMaskIntoConstraints = NO;
self.numberOfCircles = 5;
self.internalSpacing = 5;
self.radius = 10;
self.delay = 0.2;
self.duration = 0.8;
self.defaultColor = [UIColor lightGrayColor];


- (void)refresh
{
if (self.isAnimating)
{
[self removeCircles];
[self addCircles];
}
[self invalidateIntrinsicContentSize];
}

- (UIView *)createCircleWithRadius:(CGFloat)radius
color:(UIColor *)color
positionX:(CGFloat)x {


/**
Creates the circle view.
@param radius The radius of the circle.
@param color The background color of the circle.
@param positionX The x-position of the circle in the contentView.
@return The circle view.
*/
- (UIView *)createCircleWithRadius:(CGFloat)radius color:(UIColor *)color positionX:(CGFloat)x
{
UIView *circle = [[UIView alloc] initWithFrame:CGRectMake(x, 0, radius * 2, radius * 2)];
circle.backgroundColor = color;
circle.layer.cornerRadius = radius;
circle.translatesAutoresizingMaskIntoConstraints = NO;
return circle;
}

/**
Creates the animation of the circle.
@param duration The duration of the animation.
@param delay The delay of the animation
@return The animation of the circle.
*/
- (CABasicAnimation *)createAnimationWithDuration:(CGFloat)duration delay:(CGFloat)delay {
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
anim.delegate = self;
Expand All @@ -126,13 +98,11 @@ - (CABasicAnimation *)createAnimationWithDuration:(CGFloat)duration delay:(CGFlo

- (void)addCircles {
for (NSUInteger i = 0; i < self.numberOfCircles; i++) {
UIColor *color = nil;
if (self.delegate && [self.delegate respondsToSelector:@selector(activityIndicatorView:circleBackgroundColorAtIndex:)]) {
color = [self.delegate activityIndicatorView:self circleBackgroundColorAtIndex:i];
UIColor *color = self.tintColor;
if (self.delegate && [self.delegate respondsToSelector:@selector(activityIndicatorView:dotColorAtIndex:)]) {
color = [self.delegate activityIndicatorView:self dotColorAtIndex:i];
}
UIView *circle = [self createCircleWithRadius:self.radius
color:(color == nil) ? self.defaultColor : color
positionX:(i * ((2 * self.radius) + self.internalSpacing))];
UIView *circle = [self createCircleWithRadius:self.radius color:color positionX:(i * ((2 * self.radius) + self.internalSpacing))];
[circle setTransform:CGAffineTransformMakeScale(0, 0)];
[circle.layer addAnimation:[self createAnimationWithDuration:self.duration delay:(i * self.delay)] forKey:@"scale"];
[self addSubview:circle];
Expand All @@ -145,7 +115,8 @@ - (void)removeCircles {
}];
}

#pragma mark -


#pragma mark - Public Methods

- (void)startAnimating {
Expand All @@ -164,22 +135,100 @@ - (void)stopAnimating {
}
}

#pragma mark -
#pragma mark - Custom Setters and Getters


#pragma mark - *** Custom Setters and Getters ***

#pragma mark - Number of Circles

- (NSUInteger)numberOfCircles
{
if (!_numberOfCircles) return 5;
return _numberOfCircles;
}



- (void)setNumberOfCircles:(NSUInteger)numberOfCircles {
_numberOfCircles = numberOfCircles;
[self invalidateIntrinsicContentSize];
[self refresh];
}



#pragma mark - Radius

- (CGFloat)radius
{
if (!_radius) return 10.f;
return _radius;
}

- (void)setRadius:(CGFloat)radius {
_radius = radius;
[self invalidateIntrinsicContentSize];
[self refresh];
}



#pragma mark - Delay

- (CGFloat)delay
{
if (!_delay) return 0.2f;
return _delay;
}



- (void)setDelay:(CGFloat)delay
{
_delay = delay;
[self refresh];
}



#pragma mark - Duration

- (CGFloat)duration
{
if (!_duration) return 0.8f;
return _duration;
}



- (void)setDuration:(CGFloat)duration
{
_duration = duration;
[self refresh];
}


#pragma mark - Internal Spacing

- (CGFloat)internalSpacing
{
if (!_internalSpacing) return 5;
return _internalSpacing;
}

- (void)setInternalSpacing:(CGFloat)internalSpacing {
_internalSpacing = internalSpacing;
[self invalidateIntrinsicContentSize];
[self refresh];
}



#pragma mark - Tint Color

- (void)setTintColor:(UIColor *)tintColor
{
[super setTintColor:tintColor];
[self refresh];
}



@end
Loading