I want to stop ActivityIndicator after some time. I guess this can be achieved if I call a method after some time which stops activity indicator.
It can be achieved using NSTimer, but I don't know how. An example with code snippet will be great.
In .h class,
UIActivityIndicatorView *activity;
And used this code to your implementation class,
- (void)viewDidLoad {
[super viewDidLoad];
//initialise activityIndicator and add it to view
activity = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
activity.frame = CGRectMake(150,200, 20, 20);
[self.view addSubview:activity];
[activity startAnimating];
//call timer to fire after your required time
[NSTimer scheduledTimerWithTimeInterval:1.5 target:self selector:#selector(timerMethod:) userInfo:nil repeats:NO];
}
Timer Action,
-(void) timerMethod : (NSTimer *) theTimer {
// after 1.5 seconds, the activity indicator will be hidden.
[activity stopAnimating];
}
Related
I have a UISlider and I am trying to add subviews dynamically on the track of the UISlider with animation. I need 1 second time delay before adding each subview. How can I achieve this?
This is a basic setup of how you can go about achieving it:
#interface ViewController () {
NSTimer *_timer;
CGRect sliderFrame;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.slider.minimumValue = 0.0f;
self.slider.maximumValue = 100.0f;
sliderFrame = self.slider.frame;
_timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:#selector(addLabel:) userInfo:nil repeats:YES];
[_timer fire];
}
- (void) addLabel:(NSTimer*) timer {
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(sliderFrame.origin.x + self.slider.value/100 * self.slider.frame.size.width, sliderFrame.origin.y - 10, 20, 20)];
label.text = #"1";
[self.view addSubview:label];
}
#end
Assuming you are using an animation block, then, within your block you can use setAnimationDelay. For example;
[UIView animateWithDuration:5.0 animations:
^{
[UIView setAnimationDelay:1.0];
...
} completion:^(BOOL finished){
...
}];
This would do a 5 second animation with a delay of 1 second before it started.
you can hook up the valueChangeEvent with an action method.
You can put an animation block in that method with passing the seconds to wait before starting an animation as delay parameter.
[UIView animateWithDuration:(NSTimeInterval) delay:(NSTimeInterval) options:(UIViewAnimationOptions) animations:^(void)animations completion:^(BOOL finished)completion]
then you can change add the view with whatever animation your require.
I developed an iOS app that has two UIButton however the buttons seem to be lagging sometimes when I press them. Sometimes the lag is really bad (takes 10 seconds sometimes). I am almost positive it has something to do with the NSTimer I am using. I just want to make it so the UIViewControllers are switched as soon as the buttons are pressed, I don't want there to be any delay at all. Here is my code:
RealTimeModeViewController.m
#import "RealTimeModeViewController.h"
#interface RealTimeModeViewController ()
#end
#implementation RealTimeModeViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(UpdateTime:)
userInfo:nil
repeats:YES];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (void)UpdateTime:(id)sender
{
// This is where I do everything in my app
}
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(UpdateTime:)
userInfo:nil
repeats:YES];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (void)UpdateTime:(id)sender
{
// Most of code goes here
}
#end
The two UIButton are connected to each other ViewController via Modal style. Maybe I am supposed to put the buttons in the main thread? I am not very familiar with threads. Thank you.
If I had to guess, you are doing something in the UpdateTime: method that is time consuming. Because it is on the main thread and it is running every 1 second, you are probably slowing down everything else. UIButton events are on the main thread, so it's likely that because you are doing everything on the main thread, it is "clogged".
For a timer implementation that won't be as accurate, but will not hang the main thread, see this answer: https://stackoverflow.com/a/8304825/3708242
If you must have the consistency of the NSTimer implementation, try reducing the amount of stuff that UpdateTime: does.
I've had this problem before. You should use UIActivityIndicatorView
The button delay is probably caused by the UpdateTime method. Use UIActivityIndicatorView in ViewWillAppear of ViewDidLoad then perform the UpdateTime method.
Here is what I mean:
-(void) ViewDidLoad
{
UIActivityIndicatorView *act = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
[act setFrame:CGRectMake(320/2-50, 130, 100, 100)];
act.layer.cornerRadius = 10;
[act.layer setBackgroundColor:[[UIColor colorWithWhite: 0.0 alpha:0.30] CGColor]];
UILabel *lable = [[UILabel alloc] initWithFrame:CGRectMake(0, 80, act.frame.size.width, 20)];
[lable setText:[NSString stringWithFormat:#"%#", string]];
[lable setFont:[UIFont fontWithName:#"Helvetica-Light" size:12.0f]];
[lable setTextAlignment:NSTextAlignmentCenter];
[lable setTextColor:[UIColor whiteColor]];
[act addSubview:lable];
[self.view addSubview: act];
[act startAnimating];
// perform the method here, and set your delay time..
[self performSelector:#selector(UpdateTime:) withObject:nil afterDelay:1.0];
}
Then...
- (void)UpdateTime:(id)sender
{
// Most of your code
}
Comment and tell me if this helps :)
I am having some trouble getting my UIActivityIndicatorView to start animating. Here is my setup:
In my viewDidLoad in my view controller I have:
- (void)viewDidLoad{
schoolList = NO;
_activityIndicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[_activityIndicator startAnimating];
[NSThread detachNewThreadSelector: #selector(getSchoolList) toTarget: self withObject: nil];
[self performSelector:#selector(updateUI) withObject:nil afterDelay:20.0];
[super viewDidLoad];
}
The selector getSchoolList communicates with a server to retrieve a list of schools in a given state. Then, the selector updateUI is called to populate my UIPickerView with the list. In my updateUI selector I have:
-(void)updateUI {
_schools = [_server returnData];
if(!(_schools == nil)) {
NSLog(#"update the UI");
}
else
NSLog(#"Error:Show re-load button");
[_activityIndicator stopAnimating];
}
When I run this code, my UIActivityIndicatorView shows up, but does not animate. Can someone explain the proper way to animate my UIActivityIndicatorView? Any help is much appreciated.
You need to add the UIActivityIndicatorView to your view in viewDidLoad like this:
- (void)viewDidLoad {
schoolList = NO;
_activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[self addSubview:_activityIndicator];
[_activityIndicator startAnimating];
[NSThread detachNewThreadSelector: #selector(getSchoolList) toTarget: self withObject: nil];
[self performSelector:#selector(updateUI) withObject:nil afterDelay:20.0];
[super viewDidLoad];
}
EDIT
If _activityIndicator is a properly connected IBOutlet to a UIActivityIndicatorView, you should only need to check the 'animating' box. There would be no need to alloc/init another UIActivityIndicatorView.
Breakpoint the update function, but I don't see where you add that as a view to the hierarchy. I think you're looking at a different indicator view in the program.
So here's my code :
- (IBAction)run:(id)sender {
animationPointer = 0;
self.animationArray = [[NSMutableArray alloc] init];
UIView *allViews = [[UIView alloc]
initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
for (int i = 0; i < [self.paths count]; i++) {
[allViews addSubview:[self createAnimation:[self.paths objectAtIndex:i]]];
[self.animationArray addObject:allViews];
}
timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:#selector(animateTurn)
userInfo:nil repeats:YES];
}
- (void)animateTurn {
UIView *tempView = [self.animationArray objectAtIndex:animationPointer];
[self.view addSubview:tempView];
for (UIImageView *view in tempView.subviews) {
[[tempView.subviews objectAtIndex:animationPointer] startAnimating];
}
animationPointer++;
if (animationPointer >= [self.animationArray count]) {
[timer invalidate];
}
}
createAnimation returns, as you would expect, a fully animated UIImageView. The plan is to have several on each UIView and then animate them all on a UIView then the next after half a second and it repeats. There's only one on each UIView for now.
However, when calling animateTurn on the NSTimer, the animations don't show up.
If I call the method via the normal [self animateTurn] then they appear but nothing with NSTimer nor the performSelector function.
Any help with this (or even suggestions for a better method)?
EDIT:
I should mention the function is actually being triggered and the code is being run including the startAnimating (checked with BOOL/NSLog). There is simply nothing being shown.
This is Your Solution:-
This is what I used and now the selector is Working. :-)
if (![NSThread isMainThread])
{ [self performSelectorOnMainThread:#selector(selectorToRunInMainThread) withObject:nil waitUntilDone:NO];
}
-(void)selectorToRunInMainThread
{
NSString *str = #"Timer event has fired";
NSTimer *atimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateModel:) userInfo:str repeats:YES];
}
Include this line after your timer:-
[timer fire];
I have an animation that is not animating for some reason.
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationController.navigationBar.hidden = YES;
self.nameLabel.text = [self.name uppercaseString];
self.gradient1.alpha = .9;
self.gradient1.image = [UIImage imageNamed:#"heart.png"];
self.gradient1.animationImages = [[NSArray alloc] initWithObjects:
[UIImage imageNamed:#"gradiant1.png"],
[UIImage imageNamed:#"gradiant2.png"],
...
[UIImage imageNamed:#"gradiant26.png"], nil];
self.gradient1.animationDuration = .5;
self.gradient1.animationRepeatCount = 1;
[self updateStats:nil];
}
-(void)updateStats:(NSTimer*)timer{
Utilities *utility = [[Utilities alloc] init];
[utility getDataWithSSID:self.ssID completion:^(bool *finished, NSArray *objects) {
if (finished){
...
[self.gradient1 startAnimating];
}
self.twoSecTimer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self
selector:#selector(updateStats:)
userInfo:nil
repeats:NO];
}];
}
Sometimes it animates once or twice and then stops even though the timer continues to hit over and over. Other times it just doesn't animate at all. However, I have a couple placeholder buttons that I put on the storyboard that aren't tied to anything and whenever I press one of the buttons it animates the next time the timer hits (Actually whenever I hit the screen even though I don't have any sort of gesture recognizers..). Also, when I add in all the other garbage I want to do in this ViewController it animates every other time it's being called. So I think it's something deeper than me forgetting so set some property.
It might be a better idea to move the animation trigger to a moment when that view is actually visible - hence to viewDidAppear:.
Also your way of creating a recursive timer scheduling makes me shiver. I guess it works fine for you but I would definitely suggest to use the repeats flag set to YES instead.
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationController.navigationBar.hidden = YES;
self.nameLabel.text = [self.name uppercaseString];
self.gradient1.alpha = .9;
self.gradient1.image = [UIImage imageNamed:#"heart.png"];
self.gradient1.animationImages = [[NSArray alloc] initWithObjects:
[UIImage imageNamed:#"gradiant1.png"],
[UIImage imageNamed:#"gradiant2.png"],
...
[UIImage imageNamed:#"gradiant26.png"], nil];
self.gradient1.animationDuration = .5;
self.gradient1.animationRepeatCount = 1;
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
//animate right away...
[self updateStats:nil];
//trigger new animations every two seconds
self.twoSecTimer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self
selector:#selector(updateStats:)
userInfo:nil
repeats:YES];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self stopUpdatingStats];
}
-(void)stopUpdatingStats
{
[self.twoSecTimer invalidate];
}
-(void)updateStats:(NSTimer*)timer
{
NSLog(#"updating");
[self.gradient1 startAnimating];
}