I am using the Snowfall sample code which drops UImages from the top of the screen. I want to detect a Touch on the UIImageview and update a label. If i create a single UIImageView in IBOutlet and connect it to the touch event the label is updated correctly. But when I try to apply it to the falling UIImageView it does not work. Here is what I have so far:
- (void)viewDidLoad {
[super viewDidLoad];
score = 0;
self.view.backgroundColor = [UIColor colorWithRed:0.5 green:0.5 blue:1.0 alpha:1.0];
flakeImage = [UIImage imageNamed:#"flake.png"];
[NSTimer scheduledTimerWithTimeInterval:(0.5) target:self selector:#selector(onTimer) userInfo:nil repeats:YES];
}
- (void)onTimer
{
flakeView = [[UIImageView alloc] initWithImage:flakeImage];
flakeView.opaque = YES;
flakeView.userInteractionEnabled = YES;
flakeView.multipleTouchEnabled = YES;
int startX = round(random() % 320);
int endX = round(random() % 320);
double scale = 1 / round(random() % 100) + 1.0;
double speed = 1 / round(random() % 100) + 1.0;
flakeView.frame = CGRectMake(startX, -100.0, 25.0 * scale, 25.0 * scale);
[self.view addSubview:flakeView];
[self.view bringSubviewToFront:flakeView];
[UIView beginAnimations:nil context:flakeView];
[UIView setAnimationDuration:5 * speed];
flakeView.frame = CGRectMake(endX, 500.0, 25.0 * scale, 25.0 * scale);
[UIView setAnimationDidStopSelector:#selector(onAnimationComplete:finished:context:)];
[UIView setAnimationDelegate:self];
[UIView commitAnimations];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
if ([touch view] == flakeView)
{
NSLog(#"tag %#",touch);
score = score + 1;
lbl1.text = [NSString stringWithFormat:#"%i", score];
}
}
Animations typically disable touch handling so you have to use:
animateWithDuration:delay:options:animations:completion
to set the options to receive touches.
http://developer.apple.com/library/IOs/#documentation/WindowsViews/Conceptual/ViewPG_iPhoneOS/AnimatingViews/AnimatingViews.html#//apple_ref/doc/uid/TP40009503-CH6-SW1
IIRC the option you want is: UIViewAnimationOptionAllowUserInteraction Look for UIViewAnimationOptions in the above doc for the full list.
Related
I don't understand why only the animateDarkAst animation works. The first two timers (the one that operates on processKeys and the one that operates on animateDarkAst) work fine but the other timers don't. It doesn't matter what order I write the timers only those two methods work with their respective timers. For the other 3 animations, nothing appears on the screen because no code is being processed within their methods (animateLightAst, animateSmallAst, animateComet).
// Prepare asteroids.
_asteroiddark = [[NSImageView alloc] init];
[_asteroiddark setImage: [NSImage imageNamed:#"asteroiddark"]];
[_asteroiddark setFrame: theModel.darkAstRect];
_asteroidlight = [[NSImageView alloc] init];
[_asteroidlight setImage: [NSImage imageNamed:#"asteroidwhite"]];
[_asteroidlight setFrame: theModel.lightAstRect];
_asteroidsmall = [[NSImageView alloc] init];
[_asteroidsmall setImage: [NSImage imageNamed:#"asteroidsmall"]];
[_asteroidsmall setFrame: theModel.smallAstRect];
// ... and comets
_comet = [[NSImageView alloc] init];
[_comet setImage:[NSImage imageNamed:#"comet"]];
[_comet setFrame: theModel.cometRect];
// Set up key Processing timer for fluid spaceship movement.
timer1 = [NSTimer scheduledTimerWithTimeInterval:0.03 target:self selector:#selector(processKeys) userInfo:nil repeats:YES];
// Make a random value for first animation timer.
double randomInterval1 = arc4random() % (4 - 1) + 1;
// Set up key Processing timer for animation.
timer2 = [NSTimer scheduledTimerWithTimeInterval:randomInterval1 target:self selector:#selector(animateDarkAst) userInfo:nil repeats:YES];
double randomInterval2 = ((double)arc4random() / 3) * (3 - 1) + 1;
timer3 = [NSTimer scheduledTimerWithTimeInterval:randomInterval2 target:self selector:#selector(animateSmallAst) userInfo:nil repeats:YES];
double randomInterval3 = ((double)arc4random() / 5) * (5 - 1) + 1;
timer4 = [NSTimer scheduledTimerWithTimeInterval:randomInterval3 target:self selector:#selector(animateLightAst) userInfo:nil repeats:YES];
double randomInterval4 = ((double)arc4random() / 6) * (6 - 1) + 1;
timer5 = [NSTimer scheduledTimerWithTimeInterval:randomInterval4 target:self selector:#selector(animateComet) userInfo:nil repeats:YES];
}
return self;
}
-(void) animateDarkAst
{
int randX = arc4random_uniform(self.bounds.size.width);
int randSize = 40 + arc4random() % (120-40+1);
CGPoint startPoint = CGPointMake(randX, self.bounds.size.height);
[_asteroiddark setFrame: NSMakeRect(startPoint.x, startPoint.y, randSize, randSize)];
[self addSubview:_asteroiddark];
// Create animation (down y-axis)
[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
[context setDuration:1.5];
[context setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]];
_asteroiddark.animator.frame = CGRectOffset(_asteroiddark.frame, 0, -self.bounds.size.height - 180);
} completionHandler:nil];
}
-(void) animateSmallAst
{
int randX = arc4random_uniform(self.bounds.size.width);
int randSize = 40 + arc4random() % (120-40+1);
CGPoint startPoint = CGPointMake(randX, self.bounds.size.height);
[_asteroidsmall setFrame: NSMakeRect(startPoint.x, startPoint.y, randSize, randSize)];
[self addSubview:_asteroidsmall];
// Create animation (down y-axis)
[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
[context setDuration:1.5];
[context setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]];
_asteroidsmall.animator.frame = CGRectOffset(_asteroidsmall.frame, 0, -self.bounds.size.height - 180);
} completionHandler:nil];
}
-(void) animateLightAst
{
int randX = arc4random_uniform(self.bounds.size.width);
int randSize = 40 + arc4random() % (120-40+1);
CGPoint startPoint = CGPointMake(randX, self.bounds.size.height);
[_asteroidlight setFrame: NSMakeRect(startPoint.x, startPoint.y, randSize, randSize)];
[self addSubview:_asteroidlight];
// Create animation (down y-axis)
[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
[context setDuration:1.5];
[context setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]];
_asteroidlight.animator.frame = CGRectOffset(_asteroidlight.frame, 0, -self.bounds.size.height - 180);
} completionHandler:nil];
}
-(void) animateComet
{
int randX = arc4random_uniform(self.bounds.size.width);
int randSize = 40 + arc4random() % (120-40+1);
CGPoint startPoint = CGPointMake(randX, self.bounds.size.height);
[_comet setFrame: NSMakeRect(startPoint.x, startPoint.y, randSize, randSize)];
[self addSubview:_comet];
// Create animation (down y-axis)
[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
[context setDuration:1.5];
[context setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]];
_comet.animator.frame = CGRectOffset(_comet.frame, 0, -self.bounds.size.height - 180);
} completionHandler:nil];
}
How should I be handling this? Can I not have 5 timers at once?
The correct Q would be: "Why does at least one timer work?"
As you can see in the documentation the signature of the method has to take one parameter (the instance of NSTimer that send the message to the delegate).
aSelector The message to send to target when the timer fires.
The selector should have the following signature: timerFireMethod:
(including a colon to indicate that the method takes an argument). The
timer passes itself as the argument, thus the method would adopt the
following pattern:
Change the signature of the methods and of the selector when adding the timer.
I would like to include in my application a compass and labels cardinal gravitationally rotate and maintain its position as the compass of iOS application.
I've done some code and separately running, but when they work together goes crazy.
This is part of the code I use:
UIImageView * imgCompass;
UIImageView * north;
- (void)viewDidLoad
{
[super viewDidLoad];
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.headingFilter = 1;
[locationManager requestWhenInUseAuthorization];
[locationManager startUpdatingLocation];
[locationManager startUpdatingHeading];
motionManager = [[CMMotionManager alloc] init];
motionManager.accelerometerUpdateInterval = 0.01;
motionManager.gyroUpdateInterval = 0.01;
[motionManager startAccelerometerUpdatesToQueue:[NSOperationQueue currentQueue]
withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) {
if (!error) {
[self outputAccelertionData:accelerometerData.acceleration];
}
else{
NSLog(#"%#", error);
}
}];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading {
// Convert Degree to Radian and move the needle
newRad = -newHeading.trueHeading * M_PI / 180.0f;
[UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
self.viewCompass.transform = CGAffineTransformMakeRotation(newRad);
} completion:nil];
}
- (void)outputAccelertionData:(CMAcceleration)acceleration{
//UIInterfaceOrientation orientationNew;
// Get the current device angle
float xx = -acceleration.x;
float yy = acceleration.y;
float angle = atan2(yy, xx);
[UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
// Add 1.5 to the angle to keep the image constantly horizontal to the viewer.
[self.north setTransform:CGAffineTransformMakeRotation(angle - 1.5)];
} completion:nil];
}
Any ideas? Thank You. I'm desperate...
I solved. Simply subtract the radius of the compass and add the result to the object you want. in my case north, east, west and south are UIImageView.
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading {
self.lblGrados.text = [NSString stringWithFormat:#"%.0f°", newHeading.magneticHeading];
// Convert Degree to Radian and move the needle
newRad = -newHeading.trueHeading * M_PI / 180.0f;
[UIView animateWithDuration:0.6 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
compassView.transform = CGAffineTransformMakeRotation(newRad);
} completion:nil];
[UIView animateWithDuration:0.6 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
[self.north setTransform:CGAffineTransformMakeRotation(-newRad)];
[self.south setTransform:CGAffineTransformMakeRotation(-newRad)];
[self.east setTransform:CGAffineTransformMakeRotation(-newRad)];
[self.west setTransform:CGAffineTransformMakeRotation(-newRad)];
} completion:nil];
}
I am trying to set a delay for my animation, so once it appears and then disappears, I want to wait a certain amount of seconds for it to reappear. I have tried placing it in multiple spots throughout my code, but it was all the same result.
- (void) startRedDot {
redDotTimer = [NSTimer scheduledTimerWithTimeInterval:1.5
target:self
selector:#selector(moveButtonWithAnimation)
userInfo:nil
repeats:YES];
[redDotTimer fire];
}
-(void) moveButtonRandomly {
CGSize limits;
CGPoint newPosition;
// Get limits
limits.width = gameView.frame.size.width - redButton.frame.size.width;
limits.height = gameView.frame.size.height - redButton.frame.size.height;
// Calculate new Position
newPosition = (CGPoint){ limits.width * drand48(), limits.height * drand48() };
// Set new frame
redButton.frame = (CGRect){ newPosition, redButton.frame.size };
}
- (void) moveButtonWithAnimation {
CGFloat fadeDurration;
if ( !redButton )
return; // only invoke the button if it exists
fadeDurration = 0.0f;
//Fade Out
[UIView animateWithDuration: fadeDurration animations:^{
redButton.alpha = 0.0f;
} completion:^(BOOL finished) {
// Move the button while it is not visible
[self moveButtonRandomly];
[UIView setAnimationDelay:9.0];
// Fade in
[UIView animateWithDuration: fadeDurration animations:^{
redButton.alpha = 4.0f;
}];
}];
}
setAnimationDelay should use in beginAnimation and commitAnimation block, and it was old way to do animation in iOS. In your case try this:
- (void) moveButtonWithAnimation {
CGFloat fadeDurration;
if ( !redButton )
return; // only invoke the button if it exists
fadeDurration = 2.0f;
//Fade Out
[UIView animateWithDuration: fadeDurration animations:^{
redButton.alpha = 0.0f;
} completion:^(BOOL finished) {
// Move the button while it is not visible
[self moveButtonRandomly];
[UIView animateWithDuration:fadeDurration delay:2.0 options:0 animations:^{
redButton.alpha = 1.0f;
} completion:nil];
}];
}
I want to animate a UIImageView left to right with UIPageControl. I have this code but it seems a bit odd...Specifically because what would I do when I reach image 3? I would have to return and that would mess up the mathematical calculations of the views in the pageControl array the way I have it set up:
-(void)createUIViews{
UIImage *image1 = [UIImage imageNamed:#"GiftCard.png"];
firstView = [[UIImageView alloc] initWithImage:image1];
firstView.backgroundColor = [UIColor grayColor];
firstView.tag = 1;
firstView.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin);
[self.view addSubview:firstView];
CGRect newFrame = firstView.frame;
newFrame.origin.x += 40; // shift right by 50pts
newFrame.origin.y += 40;
[UIView animateWithDuration:1.0
animations:^{
firstView.frame = newFrame;
}];
UIImage *image2 = [UIImage imageNamed:#"MyCard.png"];
secondView = [[UIImageView alloc] initWithImage:image2];
secondView.backgroundColor = [UIColor grayColor];
secondView.tag = 1;
secondView.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin);
UIImage *image3 = [UIImage imageNamed:#"GiftCard.png"];
thirdView = [[UIImageView alloc] initWithImage:image3];
thirdView.backgroundColor = [UIColor grayColor];
thirdView.tag = 1;
thirdView.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin);
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self createUIViews];
// Set up the views array with 3 UIImageViews
views = [[NSArray alloc] initWithObjects:firstView, secondView, thirdView, nil];
// Set pageControl's numberOfPages to 3
self.pageControl.numberOfPages = [views count];
// Set pageControl's currentPage to 0
self.pageControl.currentPage = 0;
// Call changePage each time value of pageControl changes
[self.pageControl addTarget:self action:#selector(changePage:) forControlEvents:UIControlEventValueChanged];
}
- (IBAction) changePage:(id)sender {
NSLog(#"pageControl position %d", [self.pageControl currentPage]);
int oldPageControlPosition = [self.pageControl currentPage] - 1;
NSLog(#"old pageControl position %d", oldPageControlPosition);
//0 Get the currentview as referenced by pageControl
UIImageView *oldView = [views objectAtIndex:oldPageControlPosition];
//NSLog(#"views objectAtIndex = %#",[views objectAtIndex:[self.pageControl currentPage]]);
//1 Animate out the old view
CGRect oldViewFrame = oldView.frame;
oldViewFrame.origin.x -= 300;
[UIView animateWithDuration:2.0
delay: 0.5
options: UIViewAnimationOptionCurveEaseIn
animations:^{
oldView.frame = oldViewFrame;
}
completion:nil];
//3 Get next view from array
UIImageView *nextView = [views objectAtIndex:[self.pageControl currentPage]];
//4 Add it to mainview
[self.view addSubview:nextView];
//5 Animate in
CGRect nextViewFrame = nextView.frame;
nextViewFrame.origin.x += 40; // shift right by 50pts
nextViewFrame.origin.y += 40;
[UIView animateWithDuration:1.0
animations:^{
nextView.frame = nextViewFrame;
}];
}
When I reach the end, I try to return, the last position is 2 and oldPosition at that time is 1. Which is correct, array goes from 0 to 1 to 2 for a total of 3 positions. But when I return, the log displays position as 1 instead of 2, which is fine, because I reversed...but old position shows 0 instead of 2.
I couldnt get it to determine direction so I ended up using gesture recognizers with swipe left and swipe right instances. Here is the code:
//Help determine direction of swipe
UISwipeGestureRecognizer *swipeLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipeNext:)];
swipeLeft.direction = UISwipeGestureRecognizerDirectionLeft;
[self.scrollView addGestureRecognizer:swipeLeft];
UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipePrev:)];
swipeRight.direction = UISwipeGestureRecognizerDirectionRight;
[self.scrollView addGestureRecognizer:swipeRight];
Heres the deal:
I code an UIImageView in the viewDidLoad and i want it to move down with my fonction buttonPressed** without creating an other subview like i do.
Heres the code.
-(void)viewDidLoad {
[super viewDidLoad];
banetteImage = [UIImage imageNamed:#"myBanette.png"];
UIImageView *banetteView = [[UIImageView alloc] initWithImage:banetteImage];
banetteView.frame = CGRectMake(100, -740, 568, 790);
banetteView.opaque = NO;
[NSTimer scheduledTimerWithTimeInterval:2.5 target:self selector:#selector(buttonPressed: ) userInfo:nil repeats:NO];
[self.view addSubview:banetteView];
}
-(void)buttonPressed {
double speed = 1 / round(random() % 100) + 1.0;
[UIView beginAnimations:nil context:banetteView];
[UIView setAnimationDuration: 2*speed ];
banetteView.frame = CGRectMake(100, -2, 568, 790);
banetteView.opaque = NO;
UIImageView *banetteView = [[UIImageView alloc] initWithImage:banetteImage];
banetteView2.frame = CGRectMake(100, -740, 568, 790);
banetteView.opaque = NO;
banetteView.hidden = YES;
[self.view addSubview:banetteView];
// set a stop callback so we can cleanup the banette when it reaches the
// end of its animation
[UIView setAnimationDidStopSelector:#selector(onAnimationComplete:finished:context:)];
[UIView setAnimationDelegate:self];
[UIView commitAnimations];
}
-(void)onAnimationComplete:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
UIImageView *banetteView = context;
double speed = 1 / round(random() % 100) + 1.0;
banetteView.frame = CGRectMake(100, -2, 568, 790);
banetteView2.opaque = NO;
[self.view addSubview:banetteView2];
[UIView beginAnimations:nil context:banetteView];
[UIView setAnimationDuration: 2*speed ];
[banetteView release];
}
I found by adapting this code
http://mobile.tutsplus.com/tutorials/iphone/iphone-sdk-learning-about-touch-events-basic-game-animation/