Imagine in my app I have a label representing a virtual time and I want to change this label and update the time but this time is not system time and I want to be able to change it with different speeds (like every one real second is one or two minutes in this virtual time) and I also want to be able to call some functions at specific times.
I use UIKit.
How can I do this?
You will find that UIKit has UILabel. UILabel is a pretty straightforward thing to use. You can create it programmatically and position it, or use Interface Builder to create it as part of your View Controller's layout.
Either way, to update it, simply set the text property.
You can use NSTimer to update the text with a time and scale it using some sort of multiplier. Time calculations get tricky, so you may need to open a different question with more specifics about your time update.
Use the scheduledTimerWithTimeInterval:target:selector:userInfo:repeats: method to have it call a method on your object, then [NSTimer invalidate]; to cancel it.
Related
What is the recommended approach for starting a countdown NSTimer on one view and having it be accessible to stop interactively or to have run out in another?
I know one option is to have the NSTimer never turn off once kicked off and just use a global variable to determine whether to countdown or not but that seems inefficient.
More details of what I'm trying do:
In the main view I have a label that will update with the count down 00:00:00 and a button that I want to open a countdown UIDatePicker.
The second view with the UIDatePicker also has a start and stop button that will kick off or stop the countdown.
This view will close and the label on the original screen will display the countdown based on what the user selected previously.
It seems the timer you needed is independent from any of the views. You can use a singleton instance which will init once then be accessed anywhere. It's kind of like a global variable you mention above but if you have more than two views that need access to the timer singleton might be the most suitable choose
In my current project I've created an app that utilizes the position of the UISlider in relation to a target value displayed to the user. I've got full functionality however I'm now trying to spice it up a bit.
Is it possible to set the UISlider to move from (minimum through maximum) than (maximum through minimum) back and forth on its own when the user enters the app rather than having them drag it?
Thoughts:
Possibly use a looping sequence?
Not looking for someone to code this for me I quite enjoy that part. Just looking for guidance.
Further to the NSTimer answer, I wouldn't suggest using that, but CADisplayLink instead. Similar process, but instead of using NSTimer use CADisplayLink.
CADisplayLink synchronises with the screen refresh rate, so you can adjust the animation and slider value based on current frame, so the animation appears smooth.
http://patzearfoss.com/2011/09/02/more-cadisplaylink/
I think that in this case you would have to setup an NSTimer with a time that you wish per frame, separate out the action code within the slider into a routine that can be called by you, then within the timer action code, call your routine, and then set the slider position manually.
Look here for setting up an NSTimer
How do I use NSTimer?
The NSTimer will essentially allow you to setup any framerate you wish, AND keep it off of the MAIN thread.
UISlider has this method that allows you to programatically change the slider's value:
- (void)setValue:(float)value animated:(BOOL)animated
Be careful about using loops though, you don't want to block your main thread an make your app unresponsive.
Trumpetlick's answer provides good information on using an NSTimer, which should help you with this.
Say I have to update a label 1000 times a minute. Completely change its string value. Am I best off making 1000 setText: calls per minute? Or is there a more efficient way? Perhaps doing away with labels completely?
You basically have two options - update the textproperty of a UILabel or draw an NSString directly onto a UIView (after first erasing the previous value). You'll have to run some tests to see which is more efficient.
You can update some local field/variable and use Timer which read value from variable as frequent as it necessary and update Label. You can also use some throttle strategies.
I'm not an iOS expert so I say what my intuition says to me.
I've used this github library in one of my projects https://github.com/dataxpress/UICountingLabel, which basically subclasses a UILabel and counts down from some initial value to some final value with a custom duration that you can specify, and it is quite efficient and smooth. You can have a look at their code and it might help.
I've seen a lot of helpful tutorials that show one how to:
make an image move according to a predefined path, or
move the image, a few pixels at a time, in response to a UIButton.
What I want to do is have the image "drift" arbitrarily according to an Vxy velocity I define, then have the button(s) change the velocity. (Yes, I'd have it slow down with time if no action made).
In other languages there might have been a way to do Change Pxy position by Vxy (to ad infinitum) unless button pushed. I believe GET was the command. I can think of a way to do that in iOS I suppose but that would involve setting up a series of 1 sec CGMutablePathRef anims. Alternatively, I have seen some talk of NSTimer: would it be a good practice to introduce some sort of delay: draw, delay, draw, delay.
Request: specific classes or terms I can search in the manuals for myself.
Iirc using uiview's animateWithDuration:completion is cheaper than using core animation. frame is an animatable property. So, yeah I think I would use an NSTimer to call your method for default calculation of the end frame of your view and then call animateWithDuration:completion there.
[deleted bad idea]
I ran across a wonderful tutorial for anyone considering such a project;
http://www.youtube.com/watch?v=nH_Rj152DRM
I believe the key "noob" problem I was having was in not realizing I should declare the instance variable for my sprite/ image in the
-(void) viewDidLoad{
then work on other properties of the animation in touches/ other user events. Once I figured that out, I am now capable of doing the heavy lifting for the rest of the project myself.
Currently I am using UIKeyinput but it is only sending a single delteBackward event even when I hold down the delete key for a long time.
How can I make it send me multiple event calls when I hold delete down for a long time?
There is no easy way to have the system keyboard do auto-repeat. These leaves you with two options:
Fake it by using an overlay on the keyboard (see the comment by #pho0)
Implement a custom keyboard, install it as the inputView for your view or view controller and implement a custom protocol that supports auto-repeat.
Solution 1 works well if you only need the delete key to auto-repeat, but if you need all the keys to auto-repeat the overlay code becomes as complex as the custom keyboard option. (The overlay needs a rectangle for each key, so why not just replace the underlaying keyboard).
Solution 2 involves a certain amount of "up-front" work... One way you might do this is define a key cap class (like a physical key) and a keyboard layout class.
I have implemented both solutions in projects I have worked on, but I currently use solution 2 since I can create whatever keyboard I like. In the simple case the use need never know that it is not the system keyboard. For power users they can customize the keyboard as they see fit.
For what it is worth, I found it useful to have the keyboard class be dumb; it just communicates that a key has transitioned to being down or has transitioned to being up. An additional class above that decides what action should be taken.
In some ways, I know this is not the answer you were looking for, but I hope it helps,
IDZ
One thing I've seen people do is put a fake button on top of the keyboard button. When someone is holding down on it, have a timer remove the last letter every time it fires.
Hope this helps.