In my app, I try to move the Label when the Yaw changes.
The View is moved perfectly But not smoothly.
I used the Gyroscope & try to implement the Panorama functionality in my app.
My code is as follow:
- (void)viewDidLoad {
[super viewDidLoad];
pre_yaw=0,xpost=11;
_motionManager = [[CMMotionManager alloc] init];
[_motionManager startDeviceMotionUpdates];
[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(doSomething) userInfo:nil repeats:YES];
}
- (void)doSomething
{
_deviceMotion = [_motionManager deviceMotion];
fyaw=_deviceMotion.attitude.yaw * 180 / M_PI;
fpitch=_deviceMotion.attitude.pitch * 180 / M_PI;
froll=_deviceMotion.attitude.roll * 180 / M_PI;
self.lbl_pitch.text=[ NSString stringWithFormat:#"%.0f",fpitch];
self.lbl_yaw.text=[ NSString stringWithFormat:#"%.0f",fyaw];
self.lbl_roll.text=[ NSString stringWithFormat:#"%.0f",froll];
fyaw=fabsf(fyaw);
if (fpitch<90 && fpitch>77) {
lbl_isvalid.textColor=[UIColor blueColor];
lbl_isvalid.text=#"Valid";
if (fyaw>pre_yaw) {
float diff=fyaw-pre_yaw;
xpost=xpost+diff;
lbl_move.frame=CGRectMake(xpost, 82, 42, 21);
}
}
else{
lbl_isvalid.textColor=[UIColor redColor];
lbl_isvalid.text=#"IN-Valid";
}
pre_yaw=fyaw;
}
Help me to solve this.
Thank you,
Try to decrease the time interval of the NSTimer. Decrease it until you get an acceptable level of smoothness, but no less. We don't want to overload the CPU, hence decrease the battery life, do we?
Related
Currently I am developing a game which needs a stop watch say 1 minute,when user taps the play button it enters the game screen,I want the to run the stop watch count down of 1 minute 01:00,00:59,00:58 etc. For that reason I searched and found NSTimer would be the ideal choice to implement a stop watch.Hence I took a label,created an instance of NSTimer,assigned time interval and started decrementing the value in timer label,i.e.:
-(void)viewDidAppear:(BOOL)animated
{
self.stopWatchTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(viewWillAppear:) userInfo:nil repeats:YES];
[super viewDidAppear:YES];
}
-(void)viewWillAppear:(BOOL)animated
{
static int currentTime = 60;
int newTime = currentTime--;
int minutesRemaining = newTime / 60; // integer division, truncates fractional part
int secondsRemaining = newTime % 60; // modulo division
self.timerLabel.text = [NSString stringWithFormat:#"%02d:%02d", minutesRemaining, secondsRemaining];
if ([self.timerLabel.text isEqualToString:#"00:00"])
{
[stopWatchTimer invalidate];
}
[super viewWillAppear:YES];
}
The problem here is the timer starts running 01:00,00:59,00:58 and goes on,say at 53rd second,I navigated to another view and came back,it is running from 00:53,00:52 and so on,but I want it to run from 01:00 and for that I implemented invalidating NSTimer in viewDidDisappear i.e.
-(void)viewDidDisappear:(BOOL)animated
{
if ([stopWatchTimer isValid])
{
[stopWatchTimer invalidate];
self.stopWatchTimer = nil;
}
[super viewDidDisappear:YES];
}
Still the same issue exists!
Done lots of Research on the issue and found no answer useful and working.
Can some one please guide me,any help is appreciated.
Thanks every one in advance :)
You are use the selector viewWillAppear for the timer. viewWillAppear is a method on a viewController that gets called when the view appears on screen, you should not call it yourself. Instead, create your own method that decrements the timer:
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
self.stopWatchTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateTime:) userInfo:nil repeats:YES];
currentTime = 60; // This could be an instance variable
self.timerLabel.text = #"01:00";
}
-(void)updateTime {
int newTime = currentTime--;
int minutesRemaining = newTime / 60; // integer division, truncates fractional part
int secondsRemaining = newTime % 60; // modulo division
self.timerLabel.text = [NSString stringWithFormat:#"%02d:%02d", minutesRemaining, secondsRemaining];
if ([self.timerLabel.text isEqualToString:#"00:00"])
{
[self.stopWatchTimer invalidate];
}
}
-(void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
if ([self.stopWatchTimer isValid])
{
[self.stopWatchTimer invalidate];
self.stopWatchTimer = nil;
}
}
With this technique the timer is responsible for calling every second, but you will probably have timing issues after some seconds. To have a more accurate timing, you should store the time that you started the countdown and then on every updateTime call, compare the current time with the stored started time.
Add to your interface:
#property (nonatomic) NSTimeInterval startTime;
then in the implementation:
-(void)viewDidAppear:(BOOL)animated
{
self.startTime = [NSDate timeIntervalSinceReferenceDate];
self.duration = 60; // How long the countdown should be
self.stopWatchTimer = [NSTimer scheduledTimerWithTimeInterval:0.1
target:self
selector:#selector(updateTime)
userInfo:nil
repeats:YES];
self.timerLabel.text = #"01:00"; // Make sure this represents the countdown time
}
-(void)updateTime {
int newTime = self.duration - (round([NSDate timeIntervalSinceReferenceDate] - self.startTime));
int minutesRemaining = newTime / 60; // integer division, truncates fractional part
int secondsRemaining = newTime % 60; // modulo division
self.timerLabel.text = [NSString stringWithFormat:#"%02d:%02d", minutesRemaining, secondsRemaining];
if (newTime < 1)
{
[self.stopWatchTimer invalidate];
/* Do more stuff here */
}
}
-(void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
if ([self.stopWatchTimer isValid])
{
[self.stopWatchTimer invalidate];
self.stopWatchTimer = nil;
}
}
Some extra (unrelated) comments on the code:
when implementing viewDidDisappear: pass the animated parameter to the call to super:
[super viewDidDisappear:animated];
when implementing viewDidAppear: pass the animated parameter to the call to super, also, make sure you call super first this in the method, before doing anything else
I have a problem getting pitch, roll and yaw angles from CMAttitude class.
First, I did a normal Gyro using 'CMMotionManager' class and atributes x,y,z and worked fine.
Then, I tried to use CMAttitude for "absolute angles", but I doesn't work because It seems that is not updating data. Angles are always 0 (but the isn't errors or warnings)
I have searched a lot in stackoverflow, and used some solutions I find, but I have the same problem.
Here's my code:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
motionManager = [[CMMotionManager alloc] init];
CMDeviceMotion *deviceMotion = motionManager.deviceMotion;
CMAttitude *attitude = deviceMotion.attitude;
referenceAttitude = attitude;
[motionManager startGyroUpdates];
timer = [NSTimer scheduledTimerWithTimeInterval:1/30.0
target:self
selector:#selector(doGyroUpdate)
userInfo:nil
repeats:YES];
}
-(void)doGyroUpdate {
//cambia el frame de referencia
[motionManager.deviceMotion.attitude multiplyByInverseOfAttitude: referenceAttitude];
double rRotation = motionManager.deviceMotion.attitude.roll*180/M_PI;
double pRotation = motionManager.deviceMotion.attitude.pitch*180/M_PI;
double yRotation = motionManager.deviceMotion.attitude.yaw*180/M_PI;
NSString *myString = [NSString stringWithFormat:#"%f",rRotation];
self.angYaw.text = myString;
myString = [NSString stringWithFormat:#"%f",pRotation];
self.angPitch.text = myString;
myString = [NSString stringWithFormat:#"%f",yRotation];
self.angRoll.text = myString;
}
Thanks a lot! :D
motionManager has 4 modes: Accelerometer, Gyroscope, Magnetometer and Device motion.
Depending on which one you need, you need to start appropriate mode: startAccelerometerUpdates, startGyroUpdates, startMagnetometerUpdates or startDeviceMotionUpdates.
You are starting startGyroUpdates but reading deviceMotion property. In your case only gyroData will be available.
do this instead and you will be getting the deviceMotion data:
[motionManager startDeviceMotionUpdates];
I'm trying to move a UIImageView up and down while making it bigger. Now when I do those things separately it works like I thought it would, but when i combine them it looks really glitchy and like I wanted it to look.
Here is my code so you can copy it into Xcode and see what happens for yourself.
Add a UIImageView with whatever image you got in interface builder and add this code to the viewController.h:
IBOutlet UIImageView *bg1;
int steps;
float a;
And this to the viewController.m
#define kA 3
- (void)viewDidLoad {
[super viewDidLoad];
steps = 0;
a = kA;
[NSTimer scheduledTimerWithTimeInterval:.04 target:self selector:#selector(walk)
userInfo:nil repeats:YES];
}
-(void)resetA { // This function makes it possible for the UIImageView to move up and down
if (a > 0) a=-kA;
else a=kA;
steps++;
NSLog(#"%i", steps);
}
-(void)walk { // This function makes the UIImageView bigger and move up and down
if (a > 0) [bg1 setFrame:CGRectMake(0, 0, bg1.bounds.size.width+a,
bg1.bounds.size.height+a)];
else [bg1 setFrame:CGRectMake(0, 0, bg1.bounds.size.width-a,
bg1.bounds.size.height-a)];
[bg1 setCenter:CGPointMake(160, bg1.center.y+a)];
a *= 0.9;
if (a < 0.15 & a > 0 || a > -0.15 & a < 0) [self resetA];
}
I have looked everywhere but I cannot find out how to do so. I need a simple timer that can count up in milliseconds and can be stopped. (XCode 3.1, Objective-C, iPhone OS Development)
Am I just being daft or is "count-up timer" the same as a stopwatch.
If it is, check out this video tutorial
Here is the sample code which i have done one timer with minute, second, and mili seconds.. So, its helpful for you. And also do it release after not use..
-(void)showTime:(NSTimer *)sender
{
miniSeconds++;
if (miniSeconds == 10)
{
miniSeconds = 0;
seconds++;
if (seconds == 60)
{
seconds = 0;
minutes++;
}
}
timeLabel.text = [NSString stringWithFormat:#"%02i:%02i:%02i",minutes,seconds,miniSeconds];
}
-(void)nextLevelTime
{
[labelTimer invalidate];
miniSeconds = 0;
seconds = 0;
minutes = 0;
}
The nextLevel method use for to stop timer and release all thing..
Use it, I have done with this code..
NSTimer should do it:
Class Reference
Timer Programming Topics
#interface ViewController()
{
UILabel *progress;
NSTimer *timer;
int currMinute;
int currSeconds;
int currHours;
}
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
progress=[[UILabel alloc] initWithFrame:CGRectMake(80, 15, 100, 50)];
progress.textColor=[UIColor redColor];
[progress setText:#"Time : 00:00:00"];
progress.backgroundColor=[UIColor clearColor];
[self.view addSubview:progress];
currMinute=00;
currSeconds=00;
currHours=00;
// Do any additional setup after loading the view, typically from a nib.
}
-(void)start
{
timer=[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(timerFired) userInfo:nil repeats:YES];
}
-(void)timerFired
{
currSeconds+=1;
if(currSeconds==60)
{
currSeconds=0;
currMinute+=1;
if(currMinute==60)
{
currMinute=0;
currHours+=1;
}
}
[_progress setText:[NSString stringWithFormat:#"%#%02d%#%02d%#%02d",#"Time : ",currHours,#":",currMinute,#":",currSeconds]];
if(currMinute==2)//stop at 2 minute
{
[timer invalidate];
}
}
I'm using AVPlayer for play my video using slider and Some Buttons.
Here is my methods for moving forward and backward using buttons.
-(IBAction)MoveForward
{
//int value = timeSlider.value*36000 + 10;
//CMTime newTime = CMTimeMakeWithSeconds(value, playspeed);
//CMTime newTime = CMTimeMake(value,(playspeed*timeSlider.maximumValue));
CMTime newTime = CMTimeMakeWithSeconds(timeSlider.value, playspeed);
newTime.value += 60;
[player seekToTime: newTime];
}
-(IBAction)MoveBackward
{
CMTime newTime = CMTimeMakeWithSeconds(timeSlider.value-1, playspeed);
[player seekToTime: newTime];
}
My Problem on this is the time to Seek is not working properly. That navigate to next frame based on seconds. I need to move next frame minutely. Help me...
I don't really understand your code, you don't really need separate methods to move forwards and backwards, you can use the same one for both. I've got a working AVPlayer Movie Player, I'll show you how I did the slider part.
-(IBAction)sliding:(id)sender {
CMTime newTime = CMTimeMakeWithSeconds(seeker.value, 1);
[self.player seekToTime:newTime];
}
-(void)setSlider {
sliderTimer = [[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateSlider) userInfo:nil repeats:YES] retain];
self.seeker.maximumValue = [self durationInSeconds];
[seeker addTarget:self action:#selector(sliding:) forControlEvents:UIControlEventValueChanged];
seeker.minimumValue = 0.0;
seeker.continuous = YES;
}
- (void)updateSlider {
self.seeker.maximumValue = [self durationInSeconds];
self.seeker.value = [self currentTimeInSeconds];
}
- (Float64)durationInSeconds {
Float64 dur = CMTimeGetSeconds(duration);
return dur;
}
- (Float64)currentTimeInSeconds {
Float64 dur = CMTimeGetSeconds([self.player currentTime]);
return dur;
}
And that's it, there are two gotchas in this code, first, the duration property returns a CMTime variable, you have to convert it to a float, also, this returns the raw number of seconds, you have to convert it to h:mm:ss if you want to display time labels. Second, the updateSlider method is triggered by a timer every second.
Good Luck.
The following snippet of code worked for me:
CMTime videoLength = self.mPlayer.currentItem.asset.duration; // Gets the video duration
float videoLengthInSeconds = videoLength.value/videoLength.timescale; // Transfers the CMTime duration into seconds
[self.mPlayer seekToTime:CMTimeMakeWithSeconds(videoLengthInSeconds * [slider value], 1)
completionHandler:^(BOOL finished)
{
dispatch_async(dispatch_get_main_queue(), ^{
isSeeking = NO;
// Do some stuff
});
}];