How can I show a sequence of buttons highlighting? - iphone

Similar to the Simon games of old, I want to show the user a button sequence & then have them repeat it back. The place I'm stuck is showing the first button highlighted for, say, 500ms, waiting 100ms, showing the second highlighted for 500ms, waiting another 100ms, showing the 3rd & so on.
From other Stackoverflower'ers I've gotten to this block:
redButton.highlighted = YES;
[UIView beginAnimations:#"" context:nil];
[UIView setAnimationStartDate:[NSDate dateWithTimeIntervalSinceNow:1]];
[UIView setAnimationsEnabled:NO];
redButton.highlighted = NO;
[UIView commitAnimations];
[UIView beginAnimations:#"" context:nil];
[UIView setAnimationStartDate: [NSDate dateWithTimeIntervalSinceNow:2]];
[UIView setAnimationsEnabled:NO];
blueButton.highlighted = YES;
[UIView commitAnimations];
The redButton will highlight, but none of the subsequent actions take place.

There might be a way to do this with Core Animation, but it is not necessary. You are not animating the highlighted property, you are just switching it on and off.
I created a simple view-based iPhone application to do this with timers. Here is the code from the view controller:
SimonTestViewController.h:
#import <UIKit/UIKit.h>
#interface SimonTestViewController : UIViewController {
IBOutlet UIButton *redButton;
IBOutlet UIButton *blueButton;
IBOutlet UIButton *greenButton;
IBOutlet UIButton *yellowButton;
}
- (void)highlightButton:(UIButton*)button Delay:(double)delay;
- (void)highlightOn:(NSTimer*)timer;
- (void)highlightOff:(NSTimer*)timer;
#end
SimonTestViewController.m:
#import "SimonTestViewController.h"
#implementation SimonTestViewController
const double HIGHLIGHT_SECONDS = 0.5; // 500 ms
const double NEXT_SECONDS = 0.6; // 600 ms
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self highlightButton:redButton Delay:0.0];
[self highlightButton:blueButton Delay:NEXT_SECONDS];
[self highlightButton:greenButton Delay:NEXT_SECONDS * 2];
[self highlightButton:blueButton Delay:NEXT_SECONDS * 3];
[self highlightButton:yellowButton Delay:NEXT_SECONDS * 4];
[self highlightButton:redButton Delay:NEXT_SECONDS * 5];
}
- (void)highlightButton:(UIButton*)button Delay:(double)delay {
[NSTimer scheduledTimerWithTimeInterval:delay target:self selector:#selector(highlightOn:) userInfo:button repeats:NO];
}
- (void)highlightOn:(NSTimer*)timer {
UIButton *button = (UIButton*)[timer userInfo];
button.highlighted = YES;
[NSTimer scheduledTimerWithTimeInterval:HIGHLIGHT_SECONDS target:self selector:#selector(highlightOff:) userInfo:button repeats:NO];
}
- (void)highlightOff:(NSTimer*)timer {
UIButton *button = (UIButton*)[timer userInfo];
button.highlighted = NO;
}

Related

CoreAnimation: Transferring animating objects to next UIViewController

I am currently using this core animation; (iOS 5, ARC)
- (void)onTimer
{
// build a view from our image
UIImageView* flakeView = [[UIImageView alloc] initWithImage:flakeImage];
// use the random() function to randomize up our flake attributes
int startX = round(random() % 320);
int endX = startX; //round(random() % 320);
double scale = 1 / round(random() % 100) + 1.0;
double speed = 1 / round(random() % 100) + 1.0;
// set the flake start position
flakeView.frame = CGRectMake(startX, -100.0, 25.0 * scale, 25.0 * scale);
flakeView.alpha = 0.8;
// put the flake in our main view
[self.view addSubview:flakeView];
[self.view sendSubviewToBack:flakeView];
[UIView beginAnimations:nil context:(__bridge void*)flakeView];
// set up how fast the flake will fall
[UIView setAnimationDuration:10 * speed];
// set the postion where flake will move to
flakeView.frame = CGRectMake(endX, 500.0, 25.0 * scale, 25.0 * scale);
// set a stop callback so we can cleanup the flake 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 *flakeView = (__bridge UIImageView*)context;
[flakeView removeFromSuperview];
flakeView = nil;
}
fire;
[NSTimer scheduledTimerWithTimeInterval:(0.3) target:self selector:#selector(onTimer) userInfo:nil repeats:YES];
With this code, there are 10s of snow flakes are presented, falling down.
With the help of this code, and some custom view transitions, I am trying to make navigation actions fluid. The problem is I cannot find the proper way to transfer these (animating) context to the next UIViewController so all the animating snow flakes will keep on going where they left, and the next UIViewController's NSTimer will fire new ones.
Any help and suggestions will be appriciated.
Maybe you can put your context in your private extension of this class.
Like:#property (nonatomic,weak)IBOutlet UIImageView*context;
I doubt if you can transfer a view that is animating to another view controller. I suspect that when you remove it from its superview, it will terminate any animations.
You would probably be better off writing code that keeps track of the views that are animating in an array. When it's time to create a new view controller, query the presentationLayer of each image view's layer and get it's position. Then remove all the snowflake views from the current view controller and pass the whole array, plus an array of positions, to the new view controller. Then in the new view controller's viewDidLoad, add the array of snowflake views at their previous positions and start them animating to their previous end positions, and start an animation timer to begin adding more snowflakes.
.h file
#interface BeanManager : NSObject <UINavigationControllerDelegate>
{
NSMutableDictionary *beanDictionary;
UIViewController *currentViewController;
UIImage *coffeebean;
NSTimer *beanTimer;
NSInteger contextTag;
BOOL isDebugging;
}
#property (nonatomic, retain) NSMutableDictionary *beanDictionary;
#property (nonatomic, retain) UIViewController *currentViewController;
#property (nonatomic) BOOL isDebugging;
+ (id)sharedManager;
- (void)invalidate;
- (void)validate;
#end
.m file
+ (id)sharedManager {
static BeanManager *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}
- (id)init {
if (self = [super init]) {
coffeebean = [UIImage imageNamed:#"coffeebean"];
// assign self as navigation controllers delegate
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate.navigationController setDelegate:self];
self.currentViewController = appDelegate.navigationController.visibleViewController;
beanDictionary = [[NSMutableDictionary alloc] init];
NSLog(#"%# : Allocating",[self class]);
[self validate];
}
return self;
}
- (void)dealloc {
if (isDebugging) {
NSLog(#"%#: Deallocating", [self class]);
}
}
#pragma mark - UINavigationController
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
if (isDebugging) {
NSLog(#"%#: Pushing %d beans to new view",[self class], [[beanDictionary allKeys] count]);
}
for (UIImageView *animatingBeans in [beanDictionary allValues]) {
[viewController.view addSubview:animatingBeans];
[viewController.view sendSubviewToBack:animatingBeans];
}
self.currentViewController = viewController;
}
#pragma mark - Internals
- (void)validate
{
beanTimer = [NSTimer scheduledTimerWithTimeInterval:(0.3) target:self selector:#selector(onTimerWithBlock) userInfo:nil repeats:YES];
}
- (void)invalidate
{
[beanTimer invalidate];
}
- (void)onTimerWithBlock
{
// build a view from our flake image
UIImageView* beanView = [[UIImageView alloc] initWithImage:coffeebean];
// use the random() function to randomize up our flake attributes
int startX = round(random() % 320);
int endX = startX; //round(random() % 320);
double scale = 1 / round(random() % 100) + 1.0;
double speed = 1 / round(random() % 100) + 1.0;
// set the flake start position
beanView.frame = CGRectMake(startX, -100.0, 25.0 * scale, 25.0 * scale);
beanView.alpha = 0.8;
beanView.tag = contextTag;
[beanDictionary setObject:beanView forKey:[NSString stringWithFormat:#"%d",contextTag]];
if (contextTag > 1000) {
contextTag = 0;
}
contextTag++;
// put the flake in our main view
[self.currentViewController.view addSubview:beanView];
[self.currentViewController.view sendSubviewToBack:beanView];
[UIView animateWithDuration:(speed * 10) animations:^{
[beanView setFrame:CGRectMake(endX, 500.0, 25.0 * scale, 25.0 * scale)];
} completion:^(BOOL finished)
{
[beanDictionary removeObjectForKey:[NSString stringWithFormat:#"%d",beanView.tag]];
if (isDebugging) {
NSLog(#"%#: Dictionary Count %d",[self class], [[beanDictionary allKeys] count]);
}
[beanView removeFromSuperview];
}];
}
This code seemed to do the work. Just far, I am not using it as a Singleton, but if I will expand this code, it should be implemented as a singleton, just to clarify. And I am using an NSDictionary instead of an NSArray which would work just as is, again I considered I might add some features to it, so I made it an NSDictionary

How can I get rid of "ghost" text that appears in UITextField after clearing the field programmatically?

I have a strange problem with a UITextField - I am setting the value of it to #"" (or anything else still causes it) and then shrinking the field with to zero. Next time I unshrink it, it displays the same value it had before I shrunk it, regardless of my having changed the text in the view. Typing in the field causes the glitch to go away, but it looks bad.
Complete code to reproduce:
throwaway_testViewController.h:
#import <UIKit/UIKit.h>
#interface throwaway_testViewController : UIViewController <UITextFieldDelegate>{
UITextField * unitField;
}
#property (nonatomic, assign) IBOutlet UITextField * unitField;
-(IBAction)setEditingSectionUnits;
-(void)setEditingSectionValue;
-(IBAction)equalsPress;
#end
throwaway_testViewController.m
#import "throwaway_testViewController.h"
#implementation throwaway_testViewController
#synthesize unitField;
#pragma mark - Inputs
-(IBAction)equalsPress{
[UIView animateWithDuration:0.5 animations:^(void){
[unitField setText:#""];
[self setEditingSectionValue];
}];
}
#pragma mark Input Control
-(void)setEditingSectionUnits{
[UIView animateWithDuration:0.5 animations:^(void){
CGRect newRect = unitField.frame;
newRect.size.width = 160;
unitField.frame = newRect;
}completion:^(BOOL completed){
completed ? [unitField setNeedsDisplay] : nil;
}];
[unitField becomeFirstResponder];
}
-(void)setEditingSectionValue{
[UIView animateWithDuration:0.5 animations:^(void){
CGRect newRect = unitField.frame;
newRect.size.width = [unitField.text sizeWithFont:unitField.font constrainedToSize:CGSizeMake(80, 250)].width;;
unitField.frame = newRect;
}completion:^(BOOL completed){
completed ? [unitField setNeedsDisplay] : nil;
}];
[unitField resignFirstResponder];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
[self setEditingSectionValue];
return TRUE;
}
-(void)textFieldDidBeginEditing:(UITextField *)textField{
[self setEditingSectionUnits];
}
#end
In the xib, place a UITextField tied to unitField, and set the delegate of the text field to be file's owner.
Place a UIButton labeled equalsPress and tie it to that IBAction, and another called edit, tied to setEditingSectionUnits. To see the bug reproduced:
Run the app
Press edit
type something into the text field (min 8-10 characters)
press enter on the keyboard
press equalsPress
press edit
Should see: cursor and empty text field
Actually see: whatever you typed last, with a cursor at the start.
Typing makes this text disappear.
I am having trouble replicating your issue I have mocked this up to use the same sort of mechanisms as you and it works as expected.
- (void)viewDidLoad
{
[super viewDidLoad];
[self.unitField setText:#"Testing"];
}
- (IBAction)hideButtonTapped:(id)sender
{
[UIView animateWithDuration:0.5 animations:^(void)
{
[self.unitField setText:#""];
self.unitField.frame = CGRectMake(10, 10, 0, 30);
}
];
}
- (IBAction)showButtonTapped:(id)sender
{
[UIView animateWithDuration:0.5 animations:^(void)
{
self.unitField.frame = CGRectMake(10, 10, 100, 30);
}
];
}
Perhaps you can give more of your code as I feel you may have omitted something important or you can point out where you implementation differs to the above.
after replicating your code, i found that the problem you mentioned occurs only if you press return on the keyboard and then tap the equals press button...
resigning first responder before calling animation block in your setEditingSectionValue method resolved the problem:
-(void)setEditingSectionValue{
[unitField resignFirstResponder];
[UIView animateWithDuration:0.5 animations:^(void){
CGRect newRect = unitField.frame;
newRect.size.width = [unitField.text sizeWithFont:unitField.font constrainedToSize:CGSizeMake(80, 500)].width;;
unitField.frame = newRect;
}completion:^(BOOL completed){
completed ? [unitField setNeedsDisplay] : nil;
}];
}
I came up with a solution to your problem, its not nice, but at least its working :D
-(IBAction)equalsPress{
tmp = nil;
//same code as yours
}
-(void)setEditingSectionUnits{
if (tmp != nil) {
unitField.text = tmp;
}
//same code as yours
}
-(void)setEditingSectionValue{
if ([unitField.text length] > 9) {
tmp = unitField.text;
unitField.text = [unitField.text substringToIndex:9];
[tmp retain];
}else {
tmp = nil;
}
//same code as yours
}
I declared tmp in the header file:
NSString *tmp;
I had a quick look but can you try retaining UITextField:
#property (nonatomic, retain) IBOutlet UITextField * unitField;
Also equalsPress can be
-(IBAction)equalsPress{
[unitField setText:#""];
[UIView animateWithDuration:0.5 animations:^(void){
[self setEditingSectionValue];
}];
}

How to change a popover's appearance

Is there anyway of changing the appearance of a popover? I am interested in changing the border to be lighter perhaps more transparent then black
Here is the sample how to display simple pop-up that will appear animated and disappear animated after few seconds. Header file:
#interface ViewPopup : UIView
{
IBOutlet UILabel *m_lblMessage;
}
#property (nonatomic, retain) UILabel *m_lblMessage;
- (void) showFromView: (UIView*)viewParent;
And implementation part:
#implementation ViewPopup
#synthesize m_lblMessage;
- (void) showFromView: (UIView*)viewParent
{
[viewParent addSubview:self];
[self setCenter: CGPointMake(viewParent.frame.size.width/2, -self.frame.size.height/2)];
[UIView beginAnimations: #"ShowPopup" context: nil];
[UIView setAnimationDuration: 0.5];
[UIView setAnimationDelegate: self];
[UIView setAnimationDidStopSelector: #selector(onAppeared)];
self.transform = CGAffineTransformMakeTranslation(0, self.frame.size.height+40);
[UIView commitAnimations];
}
- (void) onAppeared
{
[self performSelector: #selector(hide) withObject: nil afterDelay: 3];
}
- (void) hide
{
[UIView beginAnimations: #"HidePopup" context: nil];
[UIView setAnimationDuration: 1];
[UIView setAnimationDelegate: self];
[UIView setAnimationDidStopSelector: #selector(removeFromSuperview)];
self.transform = CGAffineTransformIdentity;
[UIView commitAnimations];
}
- (void)dealloc
{
[m_lblMessage release];
[super dealloc];
}
Invocation from any view and from any place in code:
ViewPopup *viewPopup = (ViewPopup*)[[NSBundle mainBundle] getViewFromNib: #"ViewPopup" class: [ViewPopup class] owner: nil];
viewPopup.m_lblMessage.text = #"Hello";
[viewPopup showFromView: someView];
Note that popup graphics is loaded from the ViewPopup.xib file. It has only some graphics and text label.
I don't think so...I have been scouring the internet trying to solve the same problem. It looks like for right now, black is the only option.

Image Intro at iphone application starting

Hi guys I want to create an intro image (fade in and fade out ) for my application.
Here is my code but, when I run the app on the device I have a problem:
My main nib page has been displayed
My image fades in and then fades out and then again fades in and fades out 3 times
Here is my code and my attached file. Please check it out:
.h
#interface myProject : UIViewController {
float alphaValue, imageAlphaValue;
}
UIImageView *IntroImage;
NSTimer *AlphaTimer;
#end
.m
-(void)viewDidLoad
{
imageAlphaValue = 0.0;
alphaValue = 0.035;
IntroImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
[self.view addSubview:IntroImage];
[IntroImage setImage:[UIImage imageNamed:#"yourimagenamehere.png"]]; //use your image here
[IntroImage setBackgroundColor:[UIColor blueColor]];
[IntroImage setAlpha:imageAlphaValue];
[IntroImage release];
AlphaTimer = [NSTimer scheduledTimerWithTimeInterval:(0.05) target:self selector:#selector(setAlpha) userInfo:nil repeats:YES];
[NSTimer scheduledTimerWithTimeInterval:(2.0) target:self selector:#selector(changeAlpha) userInfo:nil repeats:NO];
}
-(void)setAlpha
{
imageAlphaValue = imageAlphaValue + alphaValue;
[IntroImage setAlpha:imageAlphaValue];
}
-(void)changeAlpha
{
alphaValue = -0.035;
}
my sample code
wow.... why you cannot just use something like that to change your image's alpha?
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1.0f];
[UIView setAnimationDelegate:self];
[introImage setAlpha:0.0f];
[UIView commitAnimations];
Seems to be not surprising that the main nib is shown, because it is the viewDidLoad method!
I'd also prefer to make use of the animation stuff like in morion's answer. Even though: The repeated fading is probably caused by viewDidLoad called more than once. Check it out with debugging or logging.

UITextView and UIPickerView with its own UIToolbar

I like to replicate the form behavior of Safari on the iPhone in my own app. If you enter data in an web form you get a separate UIToolbar (previous, next, done) just above the UIKeyboardView. Same for choosing an option: you get the same UIToolbar just above an UIPickerView.
I am looking for demos / sourcode / ideas how to implement this. Would I create my own subview with that toolbar and textview / pickerview? Is there a more elegant way? Especially something that leverages becomeFirstResponder of UITextfield?
So i created a UIViewCOntroller subclass to manage this.
on that i wrote this function to add.
-(void) addToViewWithAnimation:(UIView *) theView
{
UIView* myview = self.view;
CGRect frame = myview.frame;
frame.origin.y = 420;
myview.frame = frame;
UIView* bgView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 420)];
bgView.backgroundColor = [UIColor blackColor];
bgView.alpha = 0.6;
backgroundView = bgView;
[theView addSubview: bgView]; // this adds in the dark background
[theView addSubview:self.view]; // this adds in the pickerView with toolbar.
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
frame = myview.frame;
frame.origin.y = 420 - frame.size.height;
myview.frame = frame;
[UIView commitAnimations];
}
I then created the view in IB, here is what my class Header looked like at the end of that. (there is also a UItoolbar on the view i just do not have a reference to it in my Controller)
#interface PropertyPickerController : UIViewController {
IBOutlet UIPickerView* Picker;
IBOutlet UIButton* DoneButton;
IBOutlet UIButton* CancelButton;
UIView* backgroundView;
NSArray* SimpleObjects;
id PickerObjectDelegate;
SEL PickerObjectSelector;
}
To then hide the view i use.
-(void) removeFromSuperviewWithAnimation
{
UIView* myview = self.view;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(AnimationDidStop:)];
[UIView setAnimationDuration:0.5];
// set fram below window.
CGRect frame = myview.frame;
frame.origin.y = 420;
myview.frame = frame;
backgroundView.alpha = 0; //fades shade to nothing
[UIView commitAnimations];
}
-(void) AnimationDidStop:(id) object
{
[self.view removeFromSuperview]; //removes view after animations.
[backgroundView removeFromSuperview];
}
And last but not least all the delegate functions for the picker.
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
FBSimpleObject* object = (FBSimpleObject*)[SimpleObjects objectAtIndex:row];
return object.Name;
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
}
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{ return 1;}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
return [SimpleObjects count];
}
- (IBAction)CancelButtonClick
{
[self removeFromSuperviewWithAnimation];
}
- (IBAction)DoneButtonClick
{
//This performs a selector when the done button is clicked, makes the controller more versatile.
if(PickerObjectDelegate && PickerObjectSelector)
{
NSMethodSignature* signature = [PickerObjectDelegate methodSignatureForSelector:PickerObjectSelector];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
[invocation setTarget:PickerObjectDelegate];
[invocation setSelector:PickerObjectSelector];
[invocation setArgument:&object atIndex:2];
[invocation retainArguments];
[invocation invoke];
}
}
This is how you do the ToolBar. Basically i use the same concept with a ViewController subclass, and i dont use the standard push view or modal display options. (the example here actually places a Textbox and a toolbar on top of the keyboard.
#interface BugEditCommentController : UIViewController {
UITextView* Comment;
UIToolbar* Toolbar;
}
-(void) addToViewWithAnimation:(UIView*) theView;
To activate this view usually you would call [object becomeFirstResponder];
so if you add this to your view Controller constructor, all you need to do is call [object becomeFirstResponder];
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:#selector(keyboardWillShow:) name: UIKeyboardWillShowNotification object:nil];
[nc addObserver:self selector:#selector(keyboardWillHide:) name: UIKeyboardWillHideNotification object:nil];
abd if you implement this method on your controller (defined in the above code)
-(void) keyboardWillShow:(NSNotification *) note
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
CGRect toolbarFrame = Toolbar.frame;
CGRect keyboardFrame;
CGPoint keyboardCenter;
[[note.userInfo valueForKey:UIKeyboardCenterEndUserInfoKey] getValue:&keyboardCenter];
[[note.userInfo valueForKey:UIKeyboardBoundsUserInfoKey] getValue: &keyboardFrame];
//CGRect toolbarRect = Toolbar.center;
toolbarFrame.origin.y= keyboardCenter.y - ((keyboardFrame.size.height/2) + (toolbarFrame.size.height));
Toolbar.frame = toolbarFrame;
[UIView commitAnimations];
}
-(void) keyboardWillHide:(id) object
{
//you could call [self removeFromSuperviewHere];
}
-(void) removeFromsuperViewWithAnimation
{
[Comment resignFirstResponder];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(AnimationDidStop:)];
CGRect frame = Toolbar.frame;
frame.origin.y = 480;
Toolbar.frame = frame;
[self.view viewWithTag:1].alpha = 0; //fade transparent black background to clear.
[UIView commitAnimations];
}
-(void)AnimationDidStop:(id) object
{
[self.view removeFromSuperview];
}
hope the additional info helps.
I'm looking for the solution for this issue too.
I found this was the best solution, you can use this SCKit to add tool bar to dismiss the UIPickerView or the UIDatePicker as you want.
Following is github link: https://github.com/scelis/SCKit/tree/
Have fun!