Skip to content

Commit

Permalink
Implemented simple custom activity indicator.
Browse files Browse the repository at this point in the history
- Supports loading from device or remotely (synchronously).
- Supports resizing.
- Fixed memory leak.
  • Loading branch information
wcwynn committed Jul 22, 2012
1 parent 5eb4a0b commit 5ae5549
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 23 deletions.
22 changes: 22 additions & 0 deletions practical_test_01.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@
4FE7A536155120AF0066D32D /* CoreMotion.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4FE7A535155120AF0066D32D /* CoreMotion.framework */; };
4FE7A538155120BC0066D32D /* CoreText.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4FE7A537155120BC0066D32D /* CoreText.framework */; };
54835DF6159315D70022A4D5 /* ExceptionDebugPlugin.mm in Sources */ = {isa = PBXBuildFile; fileRef = 54835DF5159315D70022A4D5 /* ExceptionDebugPlugin.mm */; };
F60DC4C915BBEC87009F99F3 /* ImageIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F60DC4C815BBEC87009F99F3 /* ImageIO.framework */; };
F60DC4CD15BBF2E6009F99F3 /* custom.gif in Resources */ = {isa = PBXBuildFile; fileRef = F60DC4CC15BBF2E6009F99F3 /* custom.gif */; };
F62FB68115BBDAFE00663C0D /* WizActivitySpinnerView.m in Sources */ = {isa = PBXBuildFile; fileRef = F62FB68015BBDAFE00663C0D /* WizActivitySpinnerView.m */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
Expand Down Expand Up @@ -120,13 +123,18 @@
4FE7A537155120BC0066D32D /* CoreText.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreText.framework; path = System/Library/Frameworks/CoreText.framework; sourceTree = SDKROOT; };
54835DF4159315D70022A4D5 /* ExceptionDebugPlugin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExceptionDebugPlugin.h; sourceTree = "<group>"; };
54835DF5159315D70022A4D5 /* ExceptionDebugPlugin.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ExceptionDebugPlugin.mm; sourceTree = "<group>"; };
F60DC4C815BBEC87009F99F3 /* ImageIO.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ImageIO.framework; path = System/Library/Frameworks/ImageIO.framework; sourceTree = SDKROOT; };
F60DC4CC15BBF2E6009F99F3 /* custom.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = custom.gif; sourceTree = "<group>"; };
F62FB67F15BBDAFE00663C0D /* WizActivitySpinnerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WizActivitySpinnerView.h; sourceTree = "<group>"; };
F62FB68015BBDAFE00663C0D /* WizActivitySpinnerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WizActivitySpinnerView.m; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
4FE7A2F91550E5E70066D32D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
F60DC4C915BBEC87009F99F3 /* ImageIO.framework in Frameworks */,
4F763FFC15804CE900770319 /* CoreData.framework in Frameworks */,
4FE7A538155120BC0066D32D /* CoreText.framework in Frameworks */,
4FE7A536155120AF0066D32D /* CoreMotion.framework in Frameworks */,
Expand Down Expand Up @@ -199,6 +207,7 @@
4F1F23551562579100344943 /* Localizable.strings */,
4F1F23591562579100344943 /* icons */,
4F1F235E1562579100344943 /* splash */,
F60DC4CB15BBF2E6009F99F3 /* spinner */,
);
path = Resources;
sourceTree = "<group>";
Expand Down Expand Up @@ -240,6 +249,8 @@
4FA4839E1574FE3700DBA289 /* WizAssetsPluginExtendCDVViewControllerPrivate.h */,
4FA4839F1574FE3700DBA289 /* wizSpinnerPlugin.h */,
4FA483A01574FE3700DBA289 /* wizSpinnerPlugin.m */,
F62FB67F15BBDAFE00663C0D /* WizActivitySpinnerView.h */,
F62FB68015BBDAFE00663C0D /* WizActivitySpinnerView.m */,
);
name = wizSpinnerPlugin;
path = project_files/Plugins/wizSpinnerPlugin;
Expand Down Expand Up @@ -267,6 +278,7 @@
4FE7A3021550E5E70066D32D /* Frameworks */ = {
isa = PBXGroup;
children = (
F60DC4C815BBEC87009F99F3 /* ImageIO.framework */,
4F763FFB15804CE900770319 /* CoreData.framework */,
4F91CAB6155B67CE00BA9750 /* Cordova.framework */,
4FE7A537155120BC0066D32D /* CoreText.framework */,
Expand Down Expand Up @@ -308,6 +320,14 @@
path = project_files/Plugins/ExceptionDebugPlugin;
sourceTree = SOURCE_ROOT;
};
F60DC4CB15BBF2E6009F99F3 /* spinner */ = {
isa = PBXGroup;
children = (
F60DC4CC15BBF2E6009F99F3 /* custom.gif */,
);
path = spinner;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
Expand Down Expand Up @@ -374,6 +394,7 @@
4F1F23731562579100344943 /* Default.png in Resources */,
4F1F23741562579100344943 /* Default@2x.png in Resources */,
4F1F23751562579100344943 /* verify.sh in Resources */,
F60DC4CD15BBF2E6009F99F3 /* custom.gif in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -392,6 +413,7 @@
4FA483B91574FE3800DBA289 /* wizSpinnerPlugin.m in Sources */,
4F763FFA15804A7300770319 /* DBModel.xcdatamodeld in Sources */,
54835DF6159315D70022A4D5 /* ExceptionDebugPlugin.mm in Sources */,
F62FB68115BBDAFE00663C0D /* WizActivitySpinnerView.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
16 changes: 16 additions & 0 deletions project_files/Plugins/wizSpinnerPlugin/WizActivitySpinnerView.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// WizActivitySpinnerView.h
// practical_test_01
//
// Created by Chris Wynn on 7/22/12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface WizActivitySpinnerView : UIImageView

- (id)initWithImageURL:(NSURL *)url;
- (void)setSize:(CGSize)size;

@end
56 changes: 56 additions & 0 deletions project_files/Plugins/wizSpinnerPlugin/WizActivitySpinnerView.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//
// WizActivitySpinnerView.m
// practical_test_01
//
// Created by Chris Wynn on 7/22/12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//

#import "WizActivitySpinnerView.h"
#import <ImageIO/ImageIO.h>

@implementation WizActivitySpinnerView

- (id)initWithImageURL:(NSURL *)url
{
// For remote URLs, the read of data below will make app unresponsive.

// TODO: Consider changing to asynchronous or background loading of URL data

// Read data from the URL
NSData *data = [NSData dataWithContentsOfURL:url];

// Split data into individual frames using ImageIO (iOS4.0 and above).
NSMutableArray *frames = nil;
CGImageSourceRef imgSource = CGImageSourceCreateWithData((CFDataRef)data, NULL);
if ( imgSource ) {
size_t count = CGImageSourceGetCount(imgSource);
frames = [NSMutableArray arrayWithCapacity:count];
for ( size_t i = 0; i < count; i++ ) {
CGImageRef img = CGImageSourceCreateImageAtIndex(imgSource, i, NULL);
if ( img ) {
[frames addObject:[UIImage imageWithCGImage:img]];
CGImageRelease(img);
}
}
CFRelease(imgSource);
}

// Initialize with the frame data. Note that if frames is nil,
// both the image and animationImages will be initialized to nil.
self = [super initWithImage:[frames objectAtIndex:0]];
if (self) {
self.animationImages = frames;
}

return self;
}

- (void)setSize:(CGSize)size
{
CGRect myBounds = self.bounds;
myBounds.size = size;
self.bounds = myBounds;
}

@end
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*/

#import "WizAssetsPluginExtendCDVViewController.h"
#import "WizActivitySpinnerView.h"
#import "WizDebugLog.h"

#define degreesToRadians(x) (M_PI * x / 180.0)
Expand Down Expand Up @@ -77,7 +78,7 @@ -(CDVViewController*)hideCustomLoader:(UIView *)progressView
for(UIView* spinnerHolder in [UIApplication sharedApplication].keyWindow.subviews) {
if(spinnerHolder.tag==44){
// hide spinner
for(UIActivityIndicatorView*spinnerView in spinnerHolder.subviews) {
for(WizActivitySpinnerView*spinnerView in spinnerHolder.subviews) {
if(spinnerView.tag==45){
[spinnerView setHidden:TRUE];
[spinnerView setAlpha:0.0];
Expand Down Expand Up @@ -113,7 +114,7 @@ -(CDVViewController*)removeCustomLoader:(UIView *)progressView
{
NSLog(@"****************************************** remove spinner");
// remove view
for(UIActivityIndicatorView*spinnerView in [UIApplication sharedApplication].keyWindow.subviews) {
for(WizActivitySpinnerView*spinnerView in [UIApplication sharedApplication].keyWindow.subviews) {
if(spinnerView.tag==45){
[spinnerView removeFromSuperview];
}
Expand Down Expand Up @@ -251,8 +252,8 @@ -(CDVViewController*)showCustomLoader:(NSDictionary *)options
textColour = @"white";
}



CGFloat width = [[options objectForKey:@"width"] floatValue];
CGFloat height = [[options objectForKey:@"height"] floatValue];



Expand All @@ -265,15 +266,16 @@ -(CDVViewController*)showCustomLoader:(NSDictionary *)options
CGFloat screenHeight = screenRect.size.height;


// set UIActivityIndicatorView
for(UIActivityIndicatorView*spinnerView in spinnerHolder.subviews) {
// set WizActivitySpinnerView
for(WizActivitySpinnerView *spinnerView in spinnerHolder.subviews) {
if(spinnerView.tag==45){
// TODO: Implement colors
if ([spinnerColour isEqualToString:@"white"]) {
[spinnerView setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleWhiteLarge];
// TODO: white color
} else if ([spinnerColour isEqualToString:@"grey"]) {
[spinnerView setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleGray];
// TODO: grey color
} else {
[spinnerView setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleGray];
// TODO: default color
}

if ([pos isEqualToString:@"low"]) {
Expand All @@ -290,6 +292,11 @@ -(CDVViewController*)showCustomLoader:(NSDictionary *)options
[spinnerView setCenter:CGPointMake(screenWidth/2, screenHeight/2)];

}

if ( width > 0 && height > 0 ) {
[spinnerView setSize:CGSizeMake(width, height)];
}

if (showSpinner == 1) {
[spinnerView setHidden:FALSE];
[spinnerView setAlpha:1.0];
Expand Down Expand Up @@ -345,12 +352,10 @@ -(CDVViewController*)showCustomLoader:(NSDictionary *)options
for(UIView* spinnerHolder in [UIApplication sharedApplication].keyWindow.subviews) {
if(spinnerHolder.tag==44){
// show spinner
for(UIActivityIndicatorView*spinnerView in spinnerHolder.subviews) {
for(WizActivitySpinnerView*spinnerView in spinnerHolder.subviews) {
if(spinnerView.tag==45){
[spinnerView setHidden:FALSE];
[spinnerView setAlpha:1.0];
[spinnerView setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleWhiteLarge];

}
}
// show text label
Expand Down Expand Up @@ -416,6 +421,8 @@ -(CDVViewController*)createCustomLoader:(NSDictionary *)options
NSString *textColour = @"white";
CGFloat opacity = 0.0 ;
NSString *spinnerColour = @"white";
CGFloat width = 0.0;
CGFloat height = 0.0;

if (options)
{
Expand Down Expand Up @@ -454,6 +461,9 @@ -(CDVViewController*)createCustomLoader:(NSDictionary *)options
textColour = @"white";
}

width = [[options objectForKey:@"width"] floatValue];
height = [[options objectForKey:@"height"] floatValue];

}


Expand Down Expand Up @@ -487,7 +497,13 @@ -(CDVViewController*)createCustomLoader:(NSDictionary *)options


// create spinner
UIActivityIndicatorView *activitySpinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
// Some URLs for testing local and remote loading of custom animated .gif
// (Invalid URL or non-existent file will fail silently and not display any image)
// TODO: Add some reasonable error handling and default image
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"custom" ofType:@"gif" inDirectory:nil]];
//NSURL *url = [NSURL URLWithString:@"https://github.com/aogilvie/practical-test-01/raw/master/custom.gif"];
//NSURL *url = [NSURL URLWithString:@"http://images.animationfactory.com/thw/thw14/AF/animations/time/clocks/mr_alarm_dragging_feet/4966736.gif?mr_alarm_dragging_feet_lg_wm"];
WizActivitySpinnerView *activitySpinner = [[WizActivitySpinnerView alloc] initWithImageURL:url];
[activitySpinner setCenter:CGPointMake(screenWidth/2, screenHeight/1.5)];
[activitySpinner setAlpha:1.0];
[activitySpinner setBackgroundColor:[UIColor clearColor]];
Expand All @@ -496,6 +512,9 @@ -(CDVViewController*)createCustomLoader:(NSDictionary *)options
[activitySpinner setClipsToBounds:TRUE];
[activitySpinner setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin];
[activitySpinner setContentMode:UIViewContentModeScaleToFill];
if ( width > 0 && height > 0 ) {
[activitySpinner setSize:CGSizeMake(width, height)];
}


if ([pos isEqualToString:@"low"]) {
Expand All @@ -513,17 +532,17 @@ -(CDVViewController*)createCustomLoader:(NSDictionary *)options

}

// TODO: Implement color handling
if ([spinnerColour isEqualToString:@"white"]) {
[activitySpinner setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleWhiteLarge];
// TODO: white color
} else if ([spinnerColour isEqualToString:@"grey"]) {
[activitySpinner setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleGray];
// TODO: grey color
} else {
[activitySpinner setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleGray];
// TODO: default color
}




// create text..
UITextView *loaderStatus = [[UITextView alloc] initWithFrame:spinnerHolder.bounds];
[loaderStatus setTag:46];
Expand Down Expand Up @@ -560,11 +579,20 @@ -(CDVViewController*)createCustomLoader:(NSDictionary *)options
[spinnerHolder addSubview:backgroundScreen];
[spinnerHolder addSubview:activitySpinner];
[spinnerHolder addSubview:loaderStatus];
[backgroundScreen retain];
[activitySpinner retain];
[loaderStatus retain];



// Leaking memory is bad Ally. Good test though. :)
// After these release messages are sent, the objects remain allocated
// (with a retainCount of 1) for as long as they have a superview.
// The previous code sent retain messages which incremented the retainCounts
// without ever decrementing retainCounts (via release messages). Worse, the
// original code didn't even hang on to the objects as member variables or
// properties -- so it was not even possible to send release messages later.
[backgroundScreen release];
[activitySpinner release];
[loaderStatus release];

// And don't forget to send a release to spinnerHolder. :)
[spinnerHolder release];

return NULL;

Expand Down
File renamed without changes
2 changes: 1 addition & 1 deletion www/test_index.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

function startSpinner() {
console.log("startSpinner");
wizSpinner.show( { timeout : 5, spinnerColour : "grey", textColour : "black", opacity : 0.2 } );
wizSpinner.show( { timeout : 5, spinnerColour : "grey", textColour : "black", opacity : 0.2, width : 200, height : 200 } );
}

function shouldRotateToOrientation (orientation)
Expand Down

0 comments on commit 5ae5549

Please sign in to comment.