I've got my UITextView set up for scrolling like this,
-(void)startAutoScroll
{
NSLog(#"AutoScroll Started");
if (scrollingTimer == nil) {
scrollingTimer = [NSTimer scheduledTimerWithTimeInterval:(60.0/1000.0)
target:self
selector:#selector(autoscrollTimerFired:)
userInfo:nil
repeats:YES];
}
}
- (void) autoscrollTimerFired:(NSTimer *)timer
{
scrollPoint = self.completeText.contentOffset;
scrollPoint = CGPointMake(scrollPoint.x, scrollPoint.y + velocityFactor);
[self.completeText setContentOffset:scrollPoint animated:NO];
}
How to enable smooth scrolling? thanks
You can make the trick scrolling pixel by pixel with animated NO since it doesn't stop like the animated YES property after its done scrolling. The only thing you gotta set is the velocityFactor as the time your NSTimer should be called, not the scroll should move. And after the scroll is done with the contentSize, invalidate the timer and the scroll should stop.
- (void) autoscrollTimerFired:(NSTimer *)timer {
[self.completeText setContentOffset:CGPointMake(0, self.completeText.contentOffset.y + 1.0) animated:NO];
if (self.completeText.contentOffset.y != self.completeText.contentSize.height - self.completeText.frame.size.height) {
scrollingTimer = [NSTimer scheduledTimerWithTimeInterval:velocityFactor target:self selector:#selector(autoscrollTimerFired:) userInfo:nil repeats:NO];
} else {
[scrollingTimer invalidate];
}
}
Related
** I show count down timer on cell when i long press on cell.but the problem is that when i click on row timer started but suddenly when i click on second cell timer stop of previous cell and start timer new cell which i click ,but the main functionality which i need is that i have to show running previous timer and current timer . please any one give me right way for that.**
-(void)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer
{ AppDelegate *app=(AppDelegate *)[UIApplication sharedApplication].delegate;
CGPoint p = [gestureRecognizer locationInView:ChatTable];
NSIndexPath *indexPath = [ChatTable indexPathForRowAtPoint:p];
if ([[[userArray valueForKey:#"sender_id"] objectAtIndex:indexPath.row]isEqualToString: app.userId]) {
}
else{
if (gestureRecognizer.state == UIGestureRecognizerStateBegan)
{
if ([imageCache objectForKey:[NSString stringWithFormat:#"%d",indexPath.row]]==NULL) {
}
else
{
self.picId=[[userArray valueForKey:#"pic_id"] objectAtIndex:indexPath.row];
self.imageName=[[userArray valueForKey:#"imagename"] objectAtIndex:indexPath.row];
ChatTable.userInteractionEnabled=NO;
// self.navigationController.navigationBarHidden=YES;
image=[[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 320, 480)];
self.pickerValue=[[userArray valueForKey:#"seconds"] objectAtIndex:indexPath.row];
image.image=[imageCache objectForKey:[NSString stringWithFormat:#"%d",indexPath.row]];
[self.view addSubview:image];
[self showTableTime:indexPath];
}
}
else if (gestureRecognizer.state == UIGestureRecognizerStateEnded) {
UITableViewCell * myCell = [ChatTable cellForRowAtIndexPath:indexpathForTimer];
UILabel * myLabel = (UILabel *)[myCell viewWithTag:101];
myLabel.text=#"";
// self.navigationController.navigationBarHidden=NO;
[image removeFromSuperview];
}
}
}
-(void)showTableTime:(NSIndexPath *)indexPath
{
secondsLeft=[self.pickerValue integerValue];
indexpathForTimer=indexPath;
[self countDownTimer];
}
- (void)countDownTimer {
timer =[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateCounter:) userInfo:nil repeats:YES];
}
- (void)updateCounter:(NSTimer *)theTimer {
UITableViewCell * myCell = [ChatTable cellForRowAtIndexPath:indexpathForTimer];
UILabel * myLabel = (UILabel *)[myCell viewWithTag:101];
if (secondsLeft >0) {
secondsLeft --;
UILabel * myLabel = (UILabel *)[myCell viewWithTag:101];
myLabel.text=[NSString stringWithFormat:#"0%d",secondsLeft];
}
else if(secondsLeft==0)
{
[self.image removeFromSuperview];
[timer invalidate];
ChatTable.userInteractionEnabled=YES;
myLabel.text=#"";
[self SendRequsetToServerOfSeenImage];
}
else
{
}
}
The problem is that you only store one timer/indexpath pair (you only use the variables "timer" and "indexPathForTimer"). As soon as you activate a second cell, the variable indexPathForTimer will be overwritten with the indexPath for the second cell, so you only update the second cell.
I would suggest you convert the variable timer into an NSMutableArray and indexPathForTimer into an NSMapTable and then do
// code to init the map table, perform this where you initialize your variables
// (you may want to use weakToStrong or weakToWeak depending on your memory
// management)
indexPathForTimer = [NSMapTable strongToStrongObjectsMapTable];
// use this code to create your timer instance with reference to the index path
// for which it was instantiated
NSTimer* newTimer = [NSTimer timerWithTimerInterval:1.0 target:self selector:#selector(updateCounter:) userInfo:nil repeats:YES];
[timer addObject:newTimer];
[indexPathForTimer addObject:indexPath forKey:newTimer];
[NSRunLoop mainRunLoop] addTimer:newTimer forModes:NSRunLoopCommonModes];
In your updateCounter: method, you can then get the real index path like so
currentIndexPath = [indexPathForTimer objectForKey:theTimer];
Try this
- (void)countDownTimer
{
timer =[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateCounter:) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop]addTimer:timer forMode:NSRunLoopCommonModes];
}
I think you want to run multiple timer on view or on each cell. but it become complicated to handle multiple timers that running on different cells.
I'm working on a buzzer app for IOS. When you click the buzzer, it buzzes, 30 seconds pops up, and counts down until after 1 and then buzzes and disappears. If, during the course of the 30-second countdown, someone wants to reset the buzzer (so that the timer goes off and disappears), they will just click the buzzer again.
I have three questions:
1. How do you start the app with the UILabel invisible and then shows up upon the first click?
2. How do you reset the buzzer by clicking it during the 30 second countdown?
3. Will reseting the buzzer fix the problem of the timer going down extremely quick when clicked multiple times?
viewcontrol.h
#import <UIKit/UIKit.h>
#import <AudioToolbox/AudioToolbox.h>
#interface ViewController : UIViewController {
IBOutlet UILabel *seconds;
NSTimer *timer;
int MainInt;
SystemSoundID buzzer;
}
- (IBAction)start:(id)sender;
- (void)countdown;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
-(IBAction)start:(id)sender {
seconds.hidden = NO;
MainInt = 30;
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(countdown) userInfo:nil repeats:YES];
AudioServicesPlaySystemSound(buzzer);
}
-(void)countdown {
MainInt -= 1;
seconds.text = [NSString stringWithFormat:#"%i", MainInt];
if (MainInt < 1) {
[timer invalidate];
timer = nil;
seconds.hidden = YES;
AudioServicesPlaySystemSound(buzzer);
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSURL *buttonURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"Buzz" ofType:#"wav"]];
AudioServicesCreateSystemSoundID((__bridge CFURLRef)buttonURL, &buzzer);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
1) hiding the label on startup
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//hide the label initially
[seconds setHidden:YES];
/// other code
then call [seconds setHidden:NO]; in start method
2) reset buzzer
-(IBAction)start:(id)sender {
seconds.hidden = NO;
MainInt = 30;
if(timer != nil)
{
//timer exist..stop previous timer first.
[timer invalidate];
}
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(countdown) userInfo:nil repeats:YES];
AudioServicesPlaySystemSound(buzzer);
}
1) For the label becoming visible on a delay, initialize the label (in code or in IB) with seconds.alpha = 0.0. Then to make it visible...
NSTimeInterval delayUntilLabelIsVisible = 3.0; // 3 seconds
[UIView animateWithDuration:0.3
delay:delayUntilLabelIsVisible
options:UIViewAnimationCurveEaseIn
animations:^{seconds.alpha = 1.0;}
completion:^(BOOL finished) {}];
2,3) Your second and third questions can be solved with a line of code in the start method...
-(IBAction)start:(id)sender {
seconds.hidden = NO;
MainInt = 30;
// cancel the old timer before creating a new one
// (otherwise many timers will run at once, calling the buzzer method too often)
[timer invalidate];
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(countdown) userInfo:nil repeats:YES];
AudioServicesPlaySystemSound(buzzer);
}
I want to make a "downloading" uilabel whose label text will change dynamically when I call the method "updating":
self.checkingArray = [NSArray arrayWithObjects:#"download", #"download.", #"download..", #"download...",
nil];
- (void) updating
{
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:#selector(changeText) userInfo:nil repeats:YES];
}
- (void) changeText
{
checkLabel.text = [self.checkingArray objectAtIndex:curCheckingState];
self.curCheckingState++;
if (self.curCheckingState >= 4) {
self.curCheckingState = 0;
}
But the label text stay with the text "download...", I want to know how to achieve my purpose?
Implement this:
- (void) updating
{
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(changeText) userInfo:nil repeats:YES];
}
- (void) changeText
{
static unsigned char state = 0;
checkLabel.text = [self.checkingArray objectAtIndex:state];
if(state < 3) state++;
else state = 0;
}
Do this:
self.checkingArray = [NSArray arrayWithObjects:#"download", #"download.", #"download..", #"download...",
nil];
self.curCheckingState = 0;
- (void) updating
{
//change timer time interval if needed
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(changeText) userInfo:nil repeats:YES];
}
- (void) changeText
{
checkLabel.text = [self.checkingArray objectAtIndex:self.curCheckingState];
if (self.curCheckingState == 3) //depending on [array count]-1
{
self.curCheckingState = 0;
}
else
{
self.curCheckingState++;
}
}
I have this code in LongTapGestureRecognizer for autoscrolling a view:
-(void) longPressDetectedgesture:
(UILongPressGestureRecognizer*)recognizer
{
_btnautoscrollstop.hidden = NO;
_btnautoscroll.hidden = YES;
// if (autoscrollTimer == nil) {
autoscrollTimer = [NSTimer
scheduledTimerWithTimeInterval:(55.0/1000.0)
target:self
selector:#selector(autoscrollTimerFired:)
userInfo:nil
repeats:YES];
}
- (void)autoscrollTimerFired:(NSTimer*)timer {
CGPoint scrollPoint = self.table.contentOffset;
scrollPoint = CGPointMake(scrollPoint.x, scrollPoint.y + 1);
[self.table setContentOffset:scrollPoint animated:NO];
}
It works perfect for me, but my need is, the autoscrooling must stop when the user taps the screen for Longgesture for the second time and vise versa. How to stop this, when the user taps for a second time.
It looks like you're almost there. You probably want something like this:
if (recogniser.state == UIGestureRecognizerStateBegan) {
if (autoscrollTimer == nil) {
autoscrollTimer = [NSTimer scheduledTimerWithTimeInterval:(55.0/1000.0)
target:self
selector:#selector(autoscrollTimerFired:)
userInfo:nil
repeats:YES];
} else {
[autoscrollTimer invalidate];
autoscrollTimer = nil;
}
}
What i usually do is declare a global BOOL Alter; and initialize it Alter = NO; in viewDidLoad (or any other method) then
-(void) longPressDetectedgesture:(UILongPressGestureRecognizer*)recognizer
{
if(Alter)
{
Alter = NO;
[autoscrollTimer inValidate];
}
else
{
Alter = YES;
_btnautoscrollstop.hidden = NO;
_btnautoscroll.hidden = YES;
// if (autoscrollTimer == nil) {
autoscrollTimer = [NSTimer scheduledTimerWithTimeInterval:(55.0/1000.0)
target:self
selector:#selector(autoscrollTimerFired:)
userInfo:nil
repeats:YES];
}
}
create a BOOL called shouldFireTimer in viewDidLoad or similar and update it's value each time you detect a longpress
-(void) longPressDetectedgesture: (UILongPressGestureRecognizer*)recognizer {
_btnautoscrollstop.hidden = NO;
_btnautoscroll.hidden = YES;
if ( shouldFireTimer ) {
[autoscrollTimer invalidate];
autoscrollTimer = nil;
} else {
autoscrollTimer = [NSTimer
scheduledTimerWithTimeInterval:(55.0/1000.0)
target:self
selector:#selector(autoscrollTimerFired:)
userInfo:nil
repeats:YES];
}
shouldFireTimer = !shouldFireTimer;
}
- (void)autoscrollTimerFired:(NSTimer*)timer {
CGPoint scrollPoint = self.table.contentOffset;
scrollPoint = CGPointMake(scrollPoint.x, scrollPoint.y + 1);
[self.table setContentOffset:scrollPoint animated:NO];
}
or like Matt says above maybe just check nil status instead of using a BOOL. I suggest using a BOOL as you maybe firing autoscrollTimerFired in other circumstances too (from a button for example) i.e. it might not be nil when you want to call it.
Using NSTimer for my application in which I have to show countdown timer with initial timing equal to 100sec. It shows 99,then 98..96..94..92...86 and so on. But I want each sec to show up. Here is my code....
-(void)updateTimerLabel{
if (timeRemaining>0 ) {
timeRemaining=timeRemaining-1.0;
timerLabel.text=[NSString stringWithFormat:#"%.0f", timeRemaining];
countdownTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateTimerLabel) userInfo:nil repeats:YES];
}
}
Try following code
int i =100;
-(void)viewDidLoad
{
[super viewDidLoad];
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(theActionMethod) userInfo:nil repeats:YES];
}
-(void)theActionMethod
{
if(i > 0)
{
NSString *str = [NSString stringWithFormat:#"%d",i];
lbl.text = str;
}
i--;
}
You are actually re-creating the timer every time your method gets called.
You should try leaving that outside and retaining it until you're finished with it.
#interface SomeClass
NSTimer * aTimer;
#end
#implementation
- (void)createTimer {
aTimer = [[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateTimerLabel) userInfo:nil repeats:YES] retain];
}
- (void)updateTimerLabel {
// do timer updates here
// call [aTimer release]
// and [aTimer invalidate]
// aTimer = nil;
// when you're done
}
#end
you have call updateTimerLabel outside the method.
ex:
-(void)viewDidLoad{timeRemaining=100.0;[self updateTimerLabel];countdownTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateTimerLabel) userInfo:nil repeats:YES];}
-(void)updateTimerLabel
{if (timeRemaining>0 )
{timeRemaining=timeRemaining-1.0;NSLog(#"%#",[NSString stringWithFormat:#"%.0f",timeRemaining]);}}