I'm new to coding and I'm currently making a guide/reference app (My first app).
I've been using the interface builder to do most of the work. I know I need to use code soon but for now I enjoy learning with IB.
Here's my question: I have a view that has a lot of HD pictures, it takes 4-5 seconds to load until I can scroll the page smoothly. I want to add a progress view bar (between a UITableView and the navigation bar) that show a 5 seconds progress in order to let the user know that its still loading(I know about the activity indicator but the progress view bar looks nicer and seems easier to use).
Can someone guide me through all the steps in order to make a progress view bar act as a 5 seconds timer?
Let's implement as this way for 5 min progressView,
In .h file,
NSTimer * timer;
UIProgressView * progView;
float duration;
In .m file
- (void)viewDidLoad
{
[super viewDidLoad];
progView = [[UIProgressView alloc] initWithFrame:CGRectMake(10.0, 0.0, 300.0, 10.0)];
[self.view addSubview:progView];
timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(updateProgress) userInfo:nil repeats:YES];;
}
-(void)updateProgress
{
duration += 0.1;
progView.progress = (duration/5.0); // here 5.0 indicates your required time duration
if (progView.progress == 1)
{
[timer invalidate];
timer = nil;
}
}
Thanks!
This should get you started:
#property (nonatomic, strong) NSTimer *progressTimer;
#property (nonatomic, assign) CGFloat progress;
#property (nonatomic, strong) UIProgressView *progressView;
- (void)yourMethod
{
if (!self.progressView)
{
self.progressView = [[UIProgressView alloc]initWithFrame:CGRectMake(0, 64, 320, 2)];
self.progressView.progressTintColor = [UIColor greenColor];
[self.navigationController.navigationBar.superview insertSubview:self.progressView belowSubview:self.navigationController.navigationBar];
}
else
{
self.progressView.hidden = NO;
}
self.progressTimer = [NSTimer timerWithTimeInterval:0.1 target:self selector:#selector(updateProgressView) userInfo:nil repeats:YES];
NSTimer *stopProgressTimer = [NSTimer timerWithTimeInterval:5.0 target:self selector:#selector(stopProgressView) userInfo:nil repeats:NO];
[stopProgressTimer fire];
}
- (void)stopProgressView
{
[self.progressTimer invalidate];
self.progress = 0.0f;
self.progressView.hidden = YES;
self.progressView.progress = 0.0f;
}
- (void)updateProgressView
{
self.progress = (self.progress + 0.1f) / 5;
self.progressView.progress = self.progress;
}
Related
I'm using Objective-C to make a stopwatch. I already have a basic stop watch with 3 buttons: Start, Stop and reset. Here is my code for viewcontroller.m:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
-(IBAction)Start:(id)start
{
Timer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:#selector(addingthetime) userInfo:nil repeats:YES];
}
-(IBAction)Stop:(id)sender
{
[Timer invalidate];
}
-(IBAction)Restart:(id)sender
{
[Timer invalidate];
addingtheTime = 0;
Label.text = [NSString stringWithFormat:#"0.00"];
}
-(void)addingthetime
{
addingtheTime = addingtheTime + 0.01;
Label.text = [NSString stringWithFormat:#"%.2f", addingtheTime];
}
#end
And here is my code for viewcontroller.h:
#import <UIKit/UIKit.h>
float addingtheTime;
#interface ViewController : UIViewController
{
IBOutlet UILabel *Label;
NSTimer *Timer;
}
#end
So my question is how do I make the Start button do the following once clicked:
Start the timer
Change the title to stop
(Click the same button again)
Stop the timer
Change the title to start
So the aim is to have only one button which starts and stops the timer but please I want the title to change as well.
Don't worry about the reset button as I want that to remain by itself.
PS. Please explain things clearly because I find it really hard to understand some things and I am a beginner so try and keep it fairly simple thanks, and sorry if the question isn't clear.
You can use button.tag property to achieve this. By Default the button.tag property have 0. So assume that 0 is a state when timer is Not started and 1 is the state when timer is started. You can manipulate .tag property according to your custom logic.
-(IBAction)Start:(id)start
{
UIButton *button = (UIButton *)start;
if (button.tag == 0){
button.tag = 1;
[button setTitle:#"Stop" forControlState:UIControlStateNormal];
Timer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:#selector(addingthetime) userInfo:nil repeats:YES];
}else {
button.tag = 0;
[button setTitle:#"Stop" forControlState:UIControlStateNormal];
//Invoke your method to stop Timer.
}
}
In the ViewController.h:
#import <UIKit/UIKit.h>
float addingtheTime;
#interface ViewController : UIViewController
{
IBOutlet UILabel *Label;
NSTimer *Timer;
}
#end
In the ViewController.m:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
-(void)addingthetime
{
addingtheTime = addingtheTime + 0.01;
Label.text = [NSString stringWithFormat:#"%.2f", addingtheTime];
}
- (IBAction)startOrStopAction:(UIButton *)sender {
// stop
if ([sender.titleLabel.text isEqualToString:#"stop"]) {
[Timer setFireDate:[NSDate distantFuture]];
[sender setTitle:#"start" forState:UIControlStateNormal];
}
// start
else {
if (!Timer) {
Timer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:#selector(addingthetime) userInfo:nil repeats:YES];
}else {
[Timer setFireDate:[NSDate date]];
}
[sender setTitle:#"stop" forState:UIControlStateNormal];
}
}
#end
The result:
In iPhone:
In iPad:
I want this progress view to basically "reset" when its done.
Tried to reset the count to 0 and it does reset but for each reset the timer just becomes faster and faster.
.h
#property (nonatomic, strong) NSTimer *myTimer;
#property (weak, nonatomic) IBOutlet UILabel *progressLabel;
.m
- (void)updateUI:(NSTimer *)timer
{
static int count = 0; count++;
if (count <=100)
{
self.progressView.progress = (float)count/100.0f;
}
else
{
self.myTimer = nil;
[self.myTimer invalidate];
// shoot method for next question
count = 0;
self.progressView = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
self.progressView.center = self.view.center;
[self.view addSubview:self.progressView];
self.myTimer = [NSTimer scheduledTimerWithTimeInterval:3 target:self selector:#selector(updateUI:) userInfo:nil repeats:true];
}
}
You need to invalidate the timer before you set it to nil. As of now, your call to invalidate is a no-op. This means you keep adding more and more active timers.
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 have a UITextView that displays a value (ex. "32039"). Frequently in my app I change the value of that number, but want to animate the increase or decrease in value. The animation I have in mind is something like this. I've seen this question but the only animations possible using the method described in the answers are those like fade in/out, move in from left/right/down/up, and reveal/push. Is there a UIKit or Core Animation implementation of this animation, or even an implementation in a 3rd party library, or should I roll my own?
// Something like this would work
#property (nonatomic, strong) UILabel *testLabel;
#property (nonatomic, strong) NSTimer *timer;
#property (nonatomic, assign) NSUInteger counter;
- (void)viewDidLoad
{
[super viewDidLoad];
self.testLabel = [[UILabel alloc] initWithFrame:CGRectMake(50.0f, 100.0f, 80.0f, 25.0f)];
self.testLabel.text = #"44";
[self.view addSubview:self.testLabel];
self.timer = [NSTimer timerWithTimeInterval:.5 target:self selector:#selector(changeLabelText) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];
[self.timer fire];
}
- (void)changeLabelText {
self.counter++;
if (self.counter == 100000) {
[self.timer invalidate];
}
self.testLabel.text = [NSString stringWithFormat:#"%d", (44 + self.counter)];
}
I made a stopwatch application recently and it had a few glitches.
If I hit the stop button twice in a row, the entire app would crash.
If I hit the start button twice in a row, the timer would run twice as fast and the stop button would stop working.
How do I fix this problem?
Here is the code in my .h file:
IBOutlet UILabel *time;
IBOutlet UILabel *time1;
IBOutlet UILabel *time2;
NSTimer *myTicker;
NSTimer *myTicker2;
NSTimer *myTicker3;
}
- (IBAction)start;
- (IBAction)stop;
- (IBAction)reset;
- (void)showActivity;
- (void)showActivity1;
- (void)showActivity2;
#end
and here is my code in the .m file:
- (IBAction)start {
myTicker = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(showActivity) userInfo:nil repeats:YES];
myTicker2 = [NSTimer scheduledTimerWithTimeInterval:.1 target:self selector:#selector(showActivity1) userInfo:nil repeats:YES];
myTicker3 = [NSTimer scheduledTimerWithTimeInterval:60 target:self selector:#selector(showActivity2) userInfo:nil repeats:YES];
}
- (IBAction)stop {
[myTicker invalidate];
[myTicker2 invalidate];
[myTicker3 invalidate];
}
- (IBAction)reset {
time.text = #"00";
time1.text = #"00";
time2.text = #"00";
}
- (void)showActivity {
int currentTime = [time.text intValue];
int newTime = currentTime + 1;
if (newTime == 60) {
newTime = 0;
}
time.text = [NSString stringWithFormat:#"%d", newTime];
}
- (void)showActivity1 {
int currentTime1 = [time1.text intValue];
int newTime1 = currentTime1 + 1;
if (newTime1 == 10) {
newTime1 = 0;
}
time1.text = [NSString stringWithFormat:#"%d", newTime1];
}
- (void)showActivity2 {
int currentTime2 = [time2.text intValue];
int newTime2 = currentTime2 + 1;
time2.text = [NSString stringWithFormat:#"%d", newTime2];
}
Set the stop button's userInterActionEnabled property to NO and the start button's to YES when the -stop method is fired. Then switch and set the stop button's userInterActionEnabled to YES and the start button's to NO when -start is fired.
You should create a private BOOL variable "isRunning", which is checked when clicked on Stop or Start like:
- (IBAction)stop {
if(!isRunning) return;
[myTicker invalidate];
[myTicker2 invalidate];
[myTicker3 invalidate];
self.isRunning = NO;
}
etc. Also ignoring user interactions is general a good idea (like CodaFi suggested), but only fights the symptoms ;-) You really should do both checks.