XCode Custom Activity Indicator - Hide after UIWebView Loads (webViewDidFinishLoad) - objective-c

I'm using the code found here http://blog.blackwhale.at/?p=336 to create a custom activityIndicator in the current version of xCode. This code uses a series of .png images in an array and then displays them at the set interval to create an animated loading image that you can then place on the screen (and assuming you can somehow remove it) whenever you want.
In my main ViewController.m file I have the following code in my viewDidLoad section :
/* --- START CUSTOM ACTIVITY INDICATOR */
//Create the first status image and the indicator view
UIImage *statusImage = [UIImage imageNamed:#"activity1.png"];
UIImageView *activityImageView = [[UIImageView alloc]
initWithImage:statusImage];
//Add more images which will be used for the animation
activityImageView.animationImages = [NSArray arrayWithObjects:
[UIImage imageNamed:#"activity1.png"],
[UIImage imageNamed:#"activity2.png"],
[UIImage imageNamed:#"activity3.png"],
[UIImage imageNamed:#"activity4.png"],
[UIImage imageNamed:#"activity5.png"],
[UIImage imageNamed:#"activity6.png"],
[UIImage imageNamed:#"activity7.png"],
[UIImage imageNamed:#"activity8.png"],
[UIImage imageNamed:#"activity9.png"],
[UIImage imageNamed:#"activity10.png"],
[UIImage imageNamed:#"activity11.png"],
[UIImage imageNamed:#"activity12.png"],
nil];
//Set the duration of the animation (play with it
//until it looks nice for you)
activityImageView.animationDuration = 0.6;
//Position the activity image view somewhere in
//the middle of your current view
activityImageView.frame = CGRectMake(
self.view.frame.size.width/2
-statusImage.size.width/2,
self.view.frame.size.height/1.2
-statusImage.size.height/1.2,
statusImage.size.width,
statusImage.size.height);
//Start the animation
[activityImageView startAnimating];
//Add your custom activity indicator to your current view
[self.view addSubview:activityImageView];
/* --- END CUSTOM ACTIVITY INDICATOR */
I would like to CLEAR/DELETE/HIDE the activityImageView element, as I only want it to show when the app first launches until the UIWebView finishes loading.
I would like to call this and have the gif appear while webViewDidStartLoad and then clear when webViewDidFinishLoad. Someone help??

You should go like this:
- (void)viewDidLoad {
[super viewDidLoad];
//Create the first status image and the indicator view
UIImage *statusImage = [UIImage imageNamed:#"activity1.png"];
UIImageView *activityImageView = [[UIImageView alloc]
initWithImage:statusImage];
//Add more images which will be used for the animation
activityImageView.animationImages = [NSArray arrayWithObjects:
[UIImage imageNamed:#"activity1.png"],
[UIImage imageNamed:#"activity2.png"],
[UIImage imageNamed:#"activity3.png"],
[UIImage imageNamed:#"activity4.png"],
[UIImage imageNamed:#"activity5.png"],
[UIImage imageNamed:#"activity6.png"],
[UIImage imageNamed:#"activity7.png"],
[UIImage imageNamed:#"activity8.png"],
[UIImage imageNamed:#"activity9.png"],
[UIImage imageNamed:#"activity10.png"],
[UIImage imageNamed:#"activity11.png"],
[UIImage imageNamed:#"activity12.png"],
nil];
//Set the duration of the animation (play with it
//until it looks nice for you)
activityImageView.animationDuration = 0.6;
//Position the activity image view somewhere in
//the middle of your current view
activityImageView.frame = CGRectMake(
self.view.frame.size.width/2
-statusImage.size.width/2,
self.view.frame.size.height/1.2
-statusImage.size.height/1.2,
statusImage.size.width,
statusImage.size.height);
//Start the animation
[activityImageView startAnimating];
//Add your custom activity indicator to your current view
[self.view addSubview:activityImageView];
self.timer = [NSTimer scheduledTimerWithTimeInterval:(1.0/2.0)
target:self
selector:#selector(loading)
userInfo:nil
repeats:YES];
}
- (void)loading {
if (!self.webView.loading) {
[activityImageView stopAnimating];
activityImageView.hidden = 1;
} else {
[activityImageView startAnimating];
}
}

Okay, so the reason that you cannot access activityImageView is because its declared in your viewDidLoad function. Add it as a property to your ViewController class and you should be able to do what you want. Make sure that you remove the declaration of activityImageView from viewDidLoad, and just initialize it there.
Also, where is your webview that you want to show the activity indicator? Does it have a separate view controller or is it included in your main view controller? It sounds like your scope for activityImageView is incorrect, though without knowing how you have everything set up its a little hard for me to tell you where to put it.
After you use your activity indicator in these two places, do you plan on using it again during the applications run time, or will it only ever be visible if you reload the application? Depending on the answer to that you will either want to just hide it, or remove it from you main view.
UIImageView.hidden is what controls visibility.
EDIT, Code as requested:
ViewController.h
#interface ViewController : UIViewController
{
UIWebView *_webView;
}
#property(nonatomic, strong) UIWebView *webView;
#property(nonatomic, strong) UIImageView *activityImageView;
ViewController.m
#implementation ViewController
#synthesize activityImageView;
#synthesize webView = _webView;
-(void)viewDidLoad {
//all your previous stuff with the change that you just alloc activityImageView instead of declare it
activityImageView = [[UIImageView alloc] initWithImage:statusImage];
//The above is the initialization, below is where your old code should go
}

Declare your activityImageView as a property in your header file and configure it in your viewDidLoad: method
You should add your activityImageView in UIWebViewDelegate method
- (void)webViewDidStartLoad:(UIWebView *)webView
And then stopAnimating and removeFromSuperview in the UIWebViewDelegate methods
- (void)webViewDidFinishLoad:(UIWebView *)webView
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
You should read UIImageView documentation and the UIWebViewDelegate protocol reference
UPDATE
In your header:
#property(nonatomic, retain) UIImageView *activityImageView;
In your implementation
#synthesize activityImageView;
-(void)viewDidLoad{
activityImageView = [[UIImageView alloc]
initWithImage:statusImage];
//Add more images which will be used for the animation
activityImageView.animationImages = [NSArray arrayWithObjects:
[UIImage imageNamed:#"activity1.png"],
[UIImage imageNamed:#"activity2.png"],
[UIImage imageNamed:#"activity3.png"],
[UIImage imageNamed:#"activity4.png"],
[UIImage imageNamed:#"activity5.png"],
[UIImage imageNamed:#"activity6.png"],
[UIImage imageNamed:#"activity7.png"],
[UIImage imageNamed:#"activity8.png"],
[UIImage imageNamed:#"activity9.png"],
[UIImage imageNamed:#"activity10.png"],
[UIImage imageNamed:#"activity11.png"],
[UIImage imageNamed:#"activity12.png"],
nil];
//Set the duration of the animation (play with it
//until it looks nice for you)
activityImageView.animationDuration = 0.6;
//Position the activity image view somewhere in
//the middle of your current view
activityImageView.frame = CGRectMake(
self.view.frame.size.width/2
-statusImage.size.width/2,
self.view.frame.size.height/1.2
-statusImage.size.height/1.2,
statusImage.size.width,
statusImage.size.height);
}
- (void)webViewDidStartLoad:(UIWebView *)webView{
[self.activityImageView startAnimating];
[self.view addSubview:activityImageView];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView{
[activityImageView stopAnimating];
[activityImageView removeFromSuperview];
}
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error{
[activityImageView stopAnimating];
[activityImageView removeFromSuperview];
}

Related

Compare image background

The background image is already set in the Xcode project, but when the button gets clicked it changes, so I want to check whether or not the background image 80red.png is the same as the button's background just clicked.
-(IBAction)buttonChange:(id)sender {
redImage = [UIImage imageNamed:#"80red.png”];
UIImage *ButtonColour = [sender backgroundImageForState:UIControlStateNormal];
NSData *ButtonColourData = UIImagePNGRepresentation(ButtonColour);
NSData *redImageData = UIImagePNGRepresentation(redImage);
if ([ButtonColourData isEqual: redImageData]) {
// if images are the same
NSLog(#"Images are the same");
}
}
I don't understand why my code is not working.
Your code doesn't work because you have mistakes in syntax of code.
redImage isn't link to object UIImage class - You had to write UIImage *redImage = [UIImage imageNamed:#"80red.png"];
Next:
When you do a comparison dates of images, you comparing size the images, but different images may be the same size. Better compare the images on their content.
I pretended to your situation and that's what I got:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 2, 2)];
[button setBackgroundImage:[UIImage imageNamed:#"80red.png"] forState:UIControlStateNormal];
[self buttonChange:button];
return YES;
}
-(IBAction)buttonChange:(id)sender {
UIImage *redImage = [UIImage imageNamed:#"80red.png"];
UIImage *ButtonColour = [sender backgroundImageForState:UIControlStateNormal];
//NSData *ButtonColourData = UIImagePNGRepresentation(ButtonColour);
//NSData *redImageData = UIImagePNGRepresentation(redImage);
if ([redImage isEqual: ButtonColour]) {
// if images are the same
NSLog(#"Images are the same");
}
}
I hope my advice will help you.
P.S. Sorry for my english =)

How To Speed Up Image Blur?

I have the following code in my viewWillAppear in a modal uiviewcontroller.
I am including UIImage+ImageEffects.h to do the blurring of the background image in this example.
-(void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:NO];
// grab an image of our parent view
UIView *parentView = self.presentingViewController.view;
UIImage *parentViewImage = [self takeSnapshotOfView:parentView];
UIImage *blurredImage = nil;
//BLUR THE IMAGE
blurredImage = [self blurWithImageEffects:parentViewImage];
// insert an image view with a picture of the parent view at the back of our view's subview stack...
UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.view.bounds];
imageView.image = blurredImage;
[self.view insertSubview:imageView atIndex:0];
}
[EDIT] Adding Blur Methods
- (UIImage *)takeSnapshotOfView:(UIView *)view
{
CGFloat reductionFactor = 1.5;
UIGraphicsBeginImageContext(CGSizeMake(view.frame.size.width/reductionFactor, view.frame.size.height/reductionFactor));
[view drawViewHierarchyInRect:CGRectMake(0, 0, view.frame.size.width/reductionFactor, view.frame.size.height/reductionFactor) afterScreenUpdates:YES];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
- (UIImage *)blurWithImageEffects:(UIImage *)image
{
return [image applyBlurWithRadius:10 tintColor:[UIColor colorWithWhite:1 alpha:0.2] saturationDeltaFactor:1.5 maskImage:nil];
}
The code works fine and the background shows up blurry but it is really noticeably slow on iPad 3 with iOS 8. When the button to display this viewcontroller is tapped there is a pause before the viewcontroller slides up from the bottom. If I remove the blur the view controller slides up faster.
I tried putting the code in the viewDidAppear but then there is a noticeable white background displayed for a few seconds before the blur appears. But when in viewDidAppear the viewcontroller slides up immediately.
If I reduce the applyWithBlurRadius value this does not seem to reduce the time it takes to apply the blur.
Is there any way I can make it run faster?
GPUImage might solve your issue, Its fast and it doesn't put too much load on processing.
Link To Framework : https://github.com/BradLarson/GPUImage
Link to use GPUImage Blur
http://blog.bubbly.net/tag/gpu-image/
http://www.raywenderlich.com/60968/ios-7-blur-effects-gpuimage
However a reference is shown below which will give you the basic idea:
First prepare your view which is to blurred:
- (NSData *)PhotoForBlurring:(UIView *)view{
UIGraphicsBeginImageContextWithOptions(view.bounds.size, NO, 1.0);
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData * data = UIImagePNGRepresentation(image);
[data writeToFile:#"aName.png" atomically:YES];
return data; }
-(void)sharingScrapPage{
GPUImageiOSBlurFilter *blur = [[GPUImageiOSBlurFilter alloc]init];
blur.blurRadiusInPixels=2.0;
blur.downsampling=6.0;
[blurview removeFromSuperview];
blurview = [[UIImageView alloc]initWithFrame:getRectDisplay(0, 0, 480, 320)]; // Landscape Iphone 4S
UIImage *imageForBlurring=[UIImage imageWithData:[self PhotoForBlurring:self.view]];
NSData* pngdataForBlurring = UIImagePNGRepresentation (imageForBlurring);
UIImage* blurImage = [UIImage imageWithData:pngdataForBlurring];
blurImage=[blur imageByFilteringImage:blurImage];
blurview.image=blurImage;
[self.view addSubview:blurview];
[progressHUD removeFromSuperview];
progressHUD = [[ProgressHUD alloc]initWithFrame:getRectDisplay(190, 110, 100, 90)];
[blurview addSubview:progressHUD]; }

Stretched background image in subview

Aroundabouts the internet, I've come across the following code for stretching an image to fill a UIView:
UIGraphicsBeginImageContext(self.view.frame.size);
[[UIImage imageNamed:#"image.png"] drawInRect:self.view.bounds];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.view.backgroundColor = [UIColor colorWithPatternImage:image];
This is all well and good. But I thought I'd repurpose the code to work for a custom UIView class being used as a subview, and put the following code in initWithCoder: (since the views are being added in storyboard) as follows:
- (id)initWithCoder:(NSCoder *)coder
{
self = [super initWithCoder:coder];
if (self) {
UIGraphicsBeginImageContext(self.frame.size);
[[UIImage imageNamed:#"image.png"] drawInRect:self.bounds];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.backgroundColor = [UIColor colorWithPatternImage:image];
}
return self;
}
Note that I've changed "self.view" to simply "self" to reflect that this code is being called by the view itself and not by a view controller. The first code sample works great, and fills the view grandly. The second doesn't (even if I put it in the view controller ala self.subView.frame.size), and I have a feeling it's because I don't properly understand frame and bounds. Can somebody give me a quick crash course, or (if I'm way off base) point out what's actually wrong?
EDIT: Now I'm really confused. Using NSLog, I've gleaned the following information:
self.view.bounds.size.width: 768
self.subView.bounds.size.width: 0
...Huh?? The same is true of frame. But... it's on there, it's got dimensions...
I think there might be an easier way to accomplish what you are wanting to do. If I understand you correctly, you're looking to have image.png be a background image for your custom view. If so, all you'll need to do is add a UIImageView when you initialize your custom view.
- (id) initWithCoder: (NSCoder *) coder
{
self = [super initWithCoder: coder];
if (self) {
UIImageView *imageView = [[UIImageView alloc] initWithFrame: self.bounds];
[imageView setAutoresizingMask: (UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth)];
[imageView setImage: [UIImage imageNamed: #"image.png"]];
[self addSubview: imageView];
}
return self;
}

Does it make sense to add ATMHud to tabBarController.view

When i try to add ATMHud to uitableviewcontroller subview it does work but it doesn't disable the scrolling and if the tableview is not on top i can't see the hud view. What i did was added to teh tabBarController.view that works but i want find out if this is a good idea or later on i might have issues with it.
Another question is tabBarController.view frame is that the whole screen or just the bottom part. How come atmhud shows in the middle of the screen?
Thanks in advance!
Yan
============
Found a blog post that shows how to reset self.view and add tableview separately in uitableviewcontroller
UITableViewController and fixed sub views
- (void)viewDidLoad {
[super viewDidLoad];
if (!tableView &&
[self.view isKindOfClass:[UITableView class]]) {
tableView = (UITableView *)self.view;
}
self.view = [[[UIView alloc] initWithFrame:
[UIScreen mainScreen].applicationFrame] autorelease];
self.tableView.frame = self.view.bounds;
self.tableView.contentInset = UIEdgeInsetsMake(44.0, 0.0, 0.0, 0.0);
[self.view addSubview:self.tableView];
UIView *fixedBar = [[UIView alloc] initWithFrame:
CGRectMake(0.0, 0.0, self.view.bounds.size.width, 44.0)];
fixedBar.backgroundColor = [UIColor colorWithRed:
0.0 green:1.0 blue:0.0 alpha:0.7];
[self.view addSubview:fixedBar];
[fixedBar release];
}
After this when add hud to self.view you will be able to disable the tableview on the bottom.
Let me know if this a good way to setup the tableview
The problem with using the tab bar is that the hud is now modal, and the user cannot change the tab.
It sounds like the tableview is not your primary viewm, as it can get "covered up". If its not the primary view, then add the ATMHud to self.view. If the tableView is the same as self.view, then add a new transparent view to it, then add the HUD to that view.
The tabBarController.view is the view that hosts the tabbed views - if you want to see its size (or frame) log it using NSStringFromCGRect(self.tabBarController.frame);
EDIT: I just did a test, the ATMHud DOES block the UI. All I can think of is that you have not inserted it where you need to (at the top of current view's subviews.) I have a demo project where I do this:
hud = [[ATMHud alloc] initWithDelegate:self];
[self.view addSubview:hud.view];
[hud setCaption:#"Howdie"];
[hud setActivity:YES];
[hud show];
[hud hideAfter:5];
A button under the hud is not active - in fact nothing in the view is active (probably the Nav Bar would be live though)
If you want an ARCified and field tested version, you can grab it here
EDIT2: The solution to your problem is below. Note that ATMHud blocks clicks from getting to the table, and the code below stops the scrolling:
- (void)hudWillAppear:(ATMHud *)_hud
{
self.tableView.scrollEnabled = NO;
}
- (void)hudDidDisappear:(ATMHud *)_hud
{
self.tableView.scrollEnabled = YES;
}
Dump the views:
#import <QuartzCore/QuartzCore.h>
#import "UIView+Utilities.h"
#interface UIView (Utilities_Private)
+ (void)appendView:(UIView *)v toStr:(NSMutableString *)str;
#end
#implementation UIView (Utilities_Private)
+ (void)appendView:(UIView *)a toStr:(NSMutableString *)str
{
[str appendFormat:#" %#: frame=%# bounds=%# layerFrame=%# tag=%d userInteraction=%d alpha=%f hidden=%d\n",
NSStringFromClass([a class]),
NSStringFromCGRect(a.frame),
NSStringFromCGRect(a.bounds),
NSStringFromCGRect(a.layer.frame),
a.tag,
a.userInteractionEnabled,
a.alpha,
a.isHidden
];
}
#end
#implementation UIView (Utilities)
+ (void)dumpSuperviews:(UIView *)v msg:(NSString *)msg
{
NSMutableString *str = [NSMutableString stringWithCapacity:256];
while(v) {
[self appendView:v toStr:str];
v = v.superview;
}
[str appendString:#"\n"];
NSLog(#"%#:\n%#", msg, str);
}
+ (void)dumpSubviews:(UIView *)v msg:(NSString *)msg
{
NSMutableString *str = [NSMutableString stringWithCapacity:256];
if(v) [self appendView:v toStr:str];
for(UIView *a in v.subviews) {
[self appendView:a toStr:str];
}
[str appendString:#"\n"];
NSLog(#"%#:\n%#", msg, str);
}
#end

UIImageView setImage doesn't work

I'm making an animation calling repeatedly this function so I can make an animation:
The method where I have the issue, is a method of a UIImageView's subclass Class
#interface MyCustomImageView : UIImageView {
& it is the following:
- (void) animationShowFrame: (NSInteger) frame {
NSLog(#"frame: %d", frame);
if ((frame >= animationNumFrames) || (frame < 0))
return;
NSData *data = [animationData objectAtIndex:frame];
UIImage *img = [UIImage imageWithData:data];
NSLog(#"%#",img);
NSLog(#"data: %d", [data length]);
[self setImage:img];
}
The problem is that, it seems like the first image is perfectly set, but the rest of them are ignored...
NSLogging them I can see that the images are there & the data is different every time, so, they are loaded ok, even I tried to addSubview to self (the class is UIImageView's child), through a UIImageView & they are showing, but this is not the way cause in that case I'm using too much memory...
Asking for the description in the console, I can see how self.image = nil after setting it...
I don't know what else I can do with this, it's driving me crazy.
Try to subclass to a UIView instead to a UIImageView, and create the UIImageView as a property inside.
#interface CustomView : UIView {
UIImageView *imageView;
Then, in animationShowFrame use that imageView:
- (void) animationShowFrame: (NSInteger) frame {
NSData *data = [animationData objectAtIndex:frame];
UIImage *img = [UIImage imageWithData:data];
[self.imageView setImage:img];
}
Hope it helps!