I'm fixing a word game and I've made a button that allows a user to get a tip... but the tip cost 10 coins.
how can i block the action if the user doesn't have any coins left and at the same time Alert the user to buy coins?
-(IBAction)btnHint:(id)sender {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
CGPoint center = [hints center];
center.x = 160;
center.y = 230;
[hints setCenter:center];
[UIView commitAnimations];
hintView.text = #"founded in 1996, and is a sub of telecome";
coins = coins -10;
}
Something like this:
- (IBAction)btnHint:(id)sender {
if (/* some condition that determines if there are enough coins */) {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
CGPoint center = [hints center];
center.x = 160;
center.y = 230;
[hints setCenter:center];
[UIView commitAnimations];
hintView.text = #"founded in 1996, and is a sub of telecome";
coins = coins -10;
} else {
// show alert
}
}
BTW - you really should migrate to the modern block-based UIView animation instead of the old way you are using.
Related
I'm coding a login view, when the keyboard show, background will move the same distance with an animation, but I find a question that I can't understand, when the animation begin, at the top of the background will display a white area, the white are is just the area that will disappear when the animation finished.
Here is my code
- (void)keyboardWillShow:(NSNotification *)notification{
CGRect keyboardBounds;
[[notification.userInfo valueForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardBounds];
NSNumber * duration = [notification.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey];
NSNumber * curve = [notification.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey];
keyboardBounds = [self.view convertRect:keyboardBounds toView:nil];
CGRect viewFrame = self.view.frame;
viewFrame.origin.y = 0 - keyboardBounds.size.height;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:[duration doubleValue]];
[UIView setAnimationCurve:[curve intValue]];
[UIView setAnimationDelegate:self];
self.bgView.frame = viewFrame;
[UIView commitAnimations];
}
Thanks in advance!
I am trying to make an image start at coordinates x=80 and y=249 which would move to x=284 and y=99. Then from there it would go to x=488 and y=249.
This is what i got, but for some reason the image starts at x=284 and y=99 and moves to x=488 and y=249.
I need help to fix this issue.
-(void)BallArchR{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration: 1.5];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
CGPoint center = [Ball center];
center.x = 284;
center.y = 99;
[Ball setCenter:center];
[UIView commitAnimations];
[self BallArchR2];
}
-(void)BallArchR2{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration: 1.5];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
CGPoint center = [Ball center];
center.x = 488;
center.y = 249;
[Ball setCenter:center];
[UIView commitAnimations];
}
because of you call BallArchR2 method from BallArchR method directly. But in actual, the animation of BallArchR method is not complete and before that BallArchR2 method is called. So, call BallArchR2 method after the completion of first BallArchR method animation. So you can Try this hope it helps you:
-(void)BallArchR{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration: 1.5];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
CGPoint center = [Ball center];
center.x = 284;
center.y = 99;
[Ball setCenter:center];
[UIView commitAnimations];
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 1.55 * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[self BallArchR2];
});
}
-(void)BallArchR2{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration: 1.5];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
CGPoint center = [Ball center];
center.x = 488;
center.y = 249;
[Ball setCenter:center];
[UIView commitAnimations];
}
Hope you can help or explain what's going on here, as I'm not great with UIGraphics contexts.
I have defined a class that automatically scrolls a label back and forth in it's frame when the label text is to long for the given space on the view controllers primary view.
It consists of a scrollview that fits the allocated space in the parent view, and contains a UILabel (subclassed) that is sized to fit it's text.
(The UILabel is a subview in the parent scrollview).
The scrollview commits an animation that scrolls the UILabel left -> right, then when the animation is finished, I fire the delegate '
(void)animationDidStop:animationID(NSString*)finished:(NSNumber *)finished context:(void *)context'
which resets some numbers and restarted the animation scrolling it in the reverse direction right -> left
This works really nicely.
However, if i add another instance of this 'scrolling label' somewhere else in the view controllers master view, as one of the animations stop and the AnimationDidStop delegate gets fired, it relaunches the animations from scratch for the other 'scrolling' label object.
I have tried the following to isolate the firing of the animation with no positive results.
Passing the views context and an identifier to beginAnimations and then trapping them in the (void)animationDidStop method... Didn't make any difference.
This makes me think the method doesn't seem to take
Below is the code that does the animation, and the code that relaunches it in the other direction.
As I say, it works really well on it's own, but when there is more than 1 instance of this class resident on the screen at the same time, the beginAnimations seems to fire for both instances.
Hope you can explain why. Thanks.
- (void)beginAnimationWithOrgigin:(CGPoint)origin Terminus:(CGPoint)terminus {
NSLog (#"Message %# in context %#",((UILabel*)_textLabel).text,_ctx);
CGFloat text_width = ((UILabel*)_textLabel).frame.size.width;
CGFloat display_width = self.frame.size.width;
if ( text_width > display_width ) {
float duration = (text_width - display_width)/40;
[self setContentOffset:origin];
[UIView beginAnimations:((UILabel*)_textLabel).text context:_ctx];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(animationDidStop:finished:context:)];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDelay:1.0];
[UIView setAnimationDuration:duration];
[UIView setAnimationRepeatCount:1];
[self setContentOffset:terminus];
[UIView commitAnimations];
}
}
- (void)animationDidStop:(NSString *)animationID
finished:(NSNumber *)finished
context:(void *)context
{
NSLog(#"Animation Did stop context = %#",context);
if ([animationID isEqualToString:((UILabel*)_textLabel).text]){
static BOOL forward = NO;
if ([finished boolValue]) {
CGPoint origin;
CGPoint terminal_origin;
if (forward){
origin = CGPointMake(0, 0);
terminal_origin = CGPointMake(((UILabel*)_textLabel).frame.size.width - self.frame.size.width, ((UILabel*)_textLabel).frame.origin.y);
}else{
terminal_origin = CGPointMake(0, 0);
origin = CGPointMake(((UILabel*)_textLabel).frame.size.width - self.frame.size.width, ((UILabel*)_textLabel).frame.origin.y);
}
forward = !forward;
[self beginAnimationWithOrgigin:origin Terminus:terminal_origin];
}
}
}
EDIT: Added 28/5/14 # 13:14
After A-Lives advise regarding the use of statics... have modified the code to use it's label as a flag to prompt the change of direction in scrolling.
THIS HAS FIXED THE PROBLEM
- (void)beginAnimationWithOrgigin:(CGPoint)origin Terminus:(CGPoint)terminus Direction:(NSString*)direction{
if (!direction)direction = #"FORWARD";
NSLog (#"Message %# in context %#",((UILabel*)_textLabel).text,_ctx);
CGFloat text_width = ((UILabel*)_textLabel).frame.size.width;
CGFloat display_width = self.frame.size.width;
if ( text_width > display_width ) {
float duration = (text_width - display_width)/40;
[self setContentOffset:origin];
[UIView beginAnimations:direction context:_ctx];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(animationDidStop:finished:context:)];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDelay:1.0];
[UIView setAnimationDuration:duration];
[UIView setAnimationRepeatCount:1];
[self setContentOffset:terminus];
[UIView commitAnimations];
}
}
- (void)animationDidStop:(NSString *)animationID
finished:(NSNumber *)finished
context:(void *)context
{
NSLog(#"Animation Did stop context = %#",context);
NSString *direction;
CGPoint origin;
CGPoint terminal_origin;
if (![animationID isEqualToString:#"FORWARD"]){
origin = CGPointMake(0, 0);
terminal_origin = CGPointMake(((UILabel*)_textLabel).frame.size.width - self.frame.size.width, ((UILabel*)_textLabel).frame.origin.y);
direction = #"FORWARD";
}else{
terminal_origin = CGPointMake(0, 0);
origin = CGPointMake(((UILabel*)_textLabel).frame.size.width - self.frame.size.width, ((UILabel*)_textLabel).frame.origin.y);
direction = #"BACKWARD";
}
[self beginAnimationWithOrgigin:origin Terminus:terminal_origin Direction:direction];
}
The problem was in forgetting that statics really are just ordinary C static variables which are globally accessible across the app.
(i.e, not encapsulated in the scope that defined them.)
Multiple instances of the same class are all reading and writing values to a the same variable causing unpredictable behaviour.
Solution: Pass instance level messages to control toggling activities where you can't guarantee your class is a singleton.
Modified Working Code:
- (void)beginAnimationWithOrgigin:(CGPoint)origin Terminus:(CGPoint)terminus Direction:(NSString*)direction{
if (!direction)direction = #"FORWARD";
NSLog (#"Message %# in context %#",((UILabel*)_textLabel).text,_ctx);
CGFloat text_width = ((UILabel*)_textLabel).frame.size.width;
CGFloat display_width = self.frame.size.width;
if ( text_width > display_width ) {
float duration = (text_width - display_width)/40;
[self setContentOffset:origin];
[UIView beginAnimations:direction context:_ctx];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(animationDidStop:finished:context:)];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDelay:1.0];
[UIView setAnimationDuration:duration];
[UIView setAnimationRepeatCount:1];
[self setContentOffset:terminus];
[UIView commitAnimations];
}
}
- (void)animationDidStop:(NSString *)animationID
finished:(NSNumber *)finished
context:(void *)context
{
NSLog(#"Animation Did stop context = %#",context);
NSString *direction;
CGPoint origin;
CGPoint terminal_origin;
if (![animationID isEqualToString:#"FORWARD"]){
origin = CGPointMake(0, 0);
terminal_origin = CGPointMake(((UILabel*)_textLabel).frame.size.width - self.frame.size.width, ((UILabel*)_textLabel).frame.origin.y);
direction = #"FORWARD";
}else{
terminal_origin = CGPointMake(0, 0);
origin = CGPointMake(((UILabel*)_textLabel).frame.size.width - self.frame.size.width, ((UILabel*)_textLabel).frame.origin.y);
direction = #"BACKWARD";
}
[self beginAnimationWithOrgigin:origin Terminus:terminal_origin Direction:direction];
}
Is their a new way to write this code... Anyway, I need the user to press the button to first go down and then go up the down measurements are 229 for y and 160 for x... how is this done?
- (IBAction)closeHints:(id)sender {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
CGPoint center = [hints center];
center.x = 160;
center.y = 290;
[hints setCenter:center];
[UIView commitAnimations];
}
- (IBAction)closeHints:(id)sender {
[UIView animateWithDuration:0.5
delay:0
options:UIViewAnimationOptionBeginFromCurrentState
animations:^{
CGPoint center = [hints center];
if(hints.center.y != 290){
center.y = 290;
}
else{
center.y = originY; //you should define it
}
[hints setCenter:center];
}
completion:nil];
}
I use the following block of code to slide a UIView down and when finished rotate another UIView.
The second part of the animation, the completion block is only performed once which means the 1st animation is not completed else it would reach the completion block.
On the iphone simulator it looks as if the 1st animation did finish...
can anyone help me figure this out?
my NSLog says:
finished 1st
started 2nd
finished 1st
finished 1st
finished 1st
.
.
.
- (IBAction) move
{
[UIView animateWithDuration:0.7 animations:^{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.7];
[UIView setAnimationRepeatCount:1];
[UIView setAnimationRepeatAutoreverses:NO];
CGPoint pos = movingtTable.center;
float moveDistance = 220.0;
if(!isViewVisible){
//expose the view
pos.y = pos.y+moveDistance;
//disable selection for xy table
xTable.userInteractionEnabled = NO;
yTable.userInteractionEnabled = NO;
//angle = M_PI;
}
else
{
pos.y = pos.y-moveDistance;
xTable.userInteractionEnabled = YES;
yTable.userInteractionEnabled = YES;
//angle = -M_PI;
}
isViewVisible = !isViewVisible;
movingtTable.center = pos;
NSLog(#"finished 1st");
}completion:^(BOOL finished){
NSLog(#"started 2nd");
[UIView animateWithDuration:0.4 animations:^{
//[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.4];
//[UIView setAnimationRepeatCount:1];
//[UIView setAnimationRepeatAutoreverses:NO];
arrows.transform = CGAffineTransformMakeRotation(angle);
}completion:^(BOOL finished){
angle = -angle;
}];
}];
Why are you trying to initialize another UIView animation inside the animateWithDuration block code? Update your code to the following and make sure you're not performing multiple animations of a single view at a time.
- (IBAction) move
{
[UIView animateWithDuration:0.7 animations:^{
CGPoint pos = movingtTable.center;
float moveDistance = 220.0;
if(!isViewVisible){
//expose the view
pos.y = pos.y+moveDistance;
//disable selection for xy table
xTable.userInteractionEnabled = NO;
yTable.userInteractionEnabled = NO;
//angle = M_PI;
}
else
{
pos.y = pos.y-moveDistance;
xTable.userInteractionEnabled = YES;
yTable.userInteractionEnabled = YES;
//angle = -M_PI;
}
isViewVisible = !isViewVisible;
movingtTable.center = pos;
NSLog(#"finished 1st");
}
completion:^(BOOL finished){
NSLog(#"started 2nd");
[UIView animateWithDuration:0.4 animations:^{
arrows.transform = CGAffineTransformMakeRotation(angle);
}completion:^(BOOL finished){
angle = -angle;
}];
}];
BTW: The block code requires some serious refactoring, if you ask me :)
You are mixing and matching paradigms and I believe that is causing the issue you are seeing. You are creating an animation block, but inside of that block you are creating a new animation routine with the 'old' paradigm for running UIView animations. Apple is leading people away from the old paradigm and I would encourage you to ONLY use blocks as well.
This is why the completion block only runs once, the UIView animateWith block code only runs once. However, your internal animation code runs multiple times.
Take out:
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.7];
[UIView setAnimationRepeatCount:1];
[UIView setAnimationRepeatAutoreverses:NO];
If you want your animation block to run several times, then use the full method:
animateWithDuration:delay:options:animations:completion:
Make the delay = 0, and set your options to UIViewAnimationOptionRepeat, or whatever you need to accomplish the number of cycles you want the block to complete.
Here is my suggestion assuming you want it to repeat:
- (IBAction) move
{
[UIView animateWithDuration:0.7
delay:0
options:UIViewAnimationOptionRepeat
animations:^{
CGPoint pos = movingtTable.center;
float moveDistance = 220.0;
if(!isViewVisible) {
//expose the view
pos.y = pos.y+moveDistance;
//disable selection for xy table
xTable.userInteractionEnabled = NO;
yTable.userInteractionEnabled = NO;
//angle = M_PI;
}
else {
pos.y = pos.y-moveDistance;
xTable.userInteractionEnabled = YES;
yTable.userInteractionEnabled = YES;
//angle = -M_PI;
}
isViewVisible = !isViewVisible;
movingtTable.center = pos;
NSLog(#"finished 1st");
}
completion:^(BOOL finished){
NSLog(#"started 2nd");
[UIView animateWithDuration:0.4
animations:^{
arrows.transform = CGAffineTransformMakeRotation(angle);
}
completion:^(BOOL finished){
angle = -angle;
}];
}];
}