I need to implement a button (let's say with a picture of arrow down before pressed), that when pressed, will open a drop down list other button I'll set dynamically.
The drop needs to show one button at a time, using some kind of animation.
Is there a preferred way of doing it. (never worked with animation before)
Similar source code would be of great help.
Thanks
I did something similar where I had a table view with a navigation bar. The bar had a button to show/hide filters, which would animate down from the top. The code I used was:
CGFloat filterViewHeight = kExtendedFilterViewHeight;
if(![self includeSecondaryFilter])
filterViewHeight = kDefaultFilterViewHeight;
if(!allButton.selected && [self includeSecondaryFilter])
filterViewHeight -= kSecondaryFilterHeight;
filtersView.frame = CGRectMake(0.0, -filterViewHeight, 320.0, filterViewHeight);
[self.view addSubview:filtersView];
CGRect tableViewFrame = itemTableView.frame;
CGRect filtersViewFrame = filtersView.frame;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
[UIView setAnimationDelegate:self];
tableViewFrame.origin.y = filterViewHeight;
tableViewFrame.size.height -= filterViewHeight;
itemTableView.frame = tableViewFrame;
filtersViewFrame.origin.y = 0.0;
filtersView.frame = filtersViewFrame;
[UIView commitAnimations];
Hope this helps!
Related
I have a UIButton in my code that moves steadily across the screen. Currently, when the user presses the button, the alpha changes to 0 and it just disappears. What I'd like to do is run a separate animation after the button is pressed/it has disappeared. Seems easy enough but the catch is I need to run the animation at the exact point of the button when it is pressed. And I'm drawing a blank on how to make this happen. Any help will be much appreciated! I'll post some relevant code below.
-(void)movingbuttons{
movingButton2.center = CGPointMake(x, y);
displayLink = [CADisplayLink displayLinkWithTarget:self selector:#selector(moveObject)];
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
}
-(void)moveObject{
movingButton2.center = CGPointMake(movingButton2.center.x , movingButton2.center.y +1);
}
-(IBAction)button2:(id)sender {
[UIView beginAnimations:nil context:NULL];
[movingButton2 setAlpha:0];
[UIView commitAnimations];
}
Replace your button2 action with below code and implement the someOtherMethodWithAnimation method with the animation you want :)
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1];
movingButton2.alpha = 0;
[UIView commitAnimations];
[self performSelector:#selector(someOtherMethodWithAnimation) withObject:nil afterDelay:1.0];
Replace your animation with:
[UIView animateWithDuration:0.25
animations:^{
self.movingbutton2.alpha = 0.0;
// modify other animatable view properties here, ex:
self.someOtherView.alpha = 1.0;
}
completion:nil];
Just a nit picking point, but is the button in your view controller's .xib file correctly hooked up to your IBOutlets and IBActions?
UPDATE:
You are not limited to modifying that one button in your method. You add what ever code you want in the animation block (see the udated axample above).
UIView animatable properties, there is an animation section there.
Another approach could be (I am just using alpha as an example):
[UIView animateWithDuration:1.0
animations:^{
self.movingButton2.alpha = 0.0;
}
completion:^{
[UIView animatateWithDuration:0.25
animations:^{
self.someOtherView.alpha = 1.0;
}
completion:nil];
}];
This will more likely guarantee the animations will hapen one after another.
I have 3 UITexfield, the user can fill in the first two, but the last one is a category field and displays a UIPickerView when it's clicked.
What I've managed to do so far is :
The user clicks on the catergory textfield -> the picker view appears
Then the user clicks on another textfield -> the picker view disappears and the keyboard shows up
But know I would like to hide the keyboard when the user clicks agains on the category textfield and show the picker view.
This is what I have so far :
- (void)textFieldDidBeginEditing:(UITextField *)textField {
if(textField == categoryTextField){
[categoryTextField resignFirstResponder];
[UIView beginAnimations:#"picker" context:nil];
[UIView setAnimationDuration:0.3];
pickerView.transform = CGAffineTransformMakeTranslation(0,-236);
[UIView commitAnimations];
}else{
[UIView beginAnimations:#"picker" context:nil];
[UIView setAnimationDuration:0.3];
pickerView.transform = CGAffineTransformMakeTranslation(0,236);
[UIView commitAnimations];
}
}
But it doesn't work. Any thought why ?
You're making it too difficult. Set the picker view as the input view of the textfield, and the OS will take care of the animations for you. As each field becomes first responder, the appropriate input view (default keyboard for the text ones, your picker for the third one) will be displayed. You don't need to do any animations yourself.
I don't really see where your problem comes from. I think that maybe your translation makes the pickerView move too far. You should try that :
- (void)textFieldDidBeginEditing:(UITextField *)textField {
if(textField == categoryTextField){
[categoryTextField resignFirstResponder];
[UIView beginAnimations:#"picker" context:nil];
[UIView setAnimationDuration:0.3];
CGRect frame = pickerView.frame;
frame.origin.y = 480 - 236; // assuming your on an iPhone and your picker appears from bottom
pickerView.frame = frame;
[UIView commitAnimations];
}else{
[UIView beginAnimations:#"picker" context:nil];
[UIView setAnimationDuration:0.3];
CGRect frame = pickerView.frame;
frame.origin.y = 480; // assuming your on an iPhone and your picker disappears to bottom
pickerView.frame = frame;
[UIView commitAnimations];
}
}
Hope that helps
I'm building a basic calculator app. The calculator is already fully functional with basic features. The problem I'm having is I ran out of room on the screen to add other, more advanced features. Ideally what I would like to do is create some kind of subclass and view that slides up to to the bottom of the label (where the completed calculations are displayed), when a button on the bottom of the screen is pressed. In other words, I want a view with more operators and computation options to slide up to the bottom of the label and I dont want this view to cover up any digits that are being displayed in the label. Is there anyway to achieve this?
Yes, you can. When your button is pressed, create your new view (with the extra functions), add it as a subview to self.view, and animate a change to it's frame, so that it's frame changes from below the visible view to just below your digits.
Like this:
-(void) buttonPressed {
UIView *myNewView = << create your view >>
myNewView.frame = CGRectMake(0,480, 320,200); // or whatever your width and height are
// 480 means it will be below the visible frame.
[self.view addSubview: myNewView];
float bottom_Y_of_digit_display = 100;// or wherever it is...
[UIView beginAnimations:nil contenxt:nil];
[UIView setAnimationDelay: 0.0];
[UIView setAnimationDuration: 1.0]; // one second.
myNewView.frame = CGRectMake(0,bottom_y_of_digit_display, 320,200);
[UIView commitAnimations];
}
You can use UIAnimations to create an animation out of any changes to UIView properties. You can make your UIView hidden by settings its frame.origin.y to 480 and then change the rect and wrap it in a UIAnimation.
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.75];
CGRect newFrame = newSubView.frame;
newFrame.origin.y -= newSubView.frame.size.height;
newSubView.frame = newFrame;
[UIView commitAnimations];
UPDATE
If you are targeting iOS 4.0 and later then you should use the new UIAnimations interface.
UIViewAnimationOptions options = UIViewAnimationOptionCurveLinear;
[UIView animateWithDuration:0.75 delay:0 options:options
animations:^(){
CGRect newFrame = newSubView.frame;
newFrame.origin.y -= newSubView.frame.size.height;
newSubView.frame = newFrame;
}
completion:^(BOOL finished){
//Do something upon completion
}];
I'm having some trouble with UIView animations on iPad.
I'm working on a project in which I have implemented a "facebook style" menu on the left, using the JTRevealSidebar framework.
This framework works perfectly, however, instead of "pushing" the right side view off the screen, I would like to resize it, so the user can still see the whole content of the right-side view.
I have managed to do this by changing the view's frame as well as doing the offset.
This is what it looks like with the sidebar open:
And when it's closed:
This right-side view contains a navigation bar with two buttons (one button on the left to toggle the left sidebar, and another button on the right to dismiss the controller), and the content itself is a simple UIWebView.
The problem I am facing is during the animation (from the full-screen state to the sidebar open state):
When I change the view's frame, even after doing the translate, the view resizes before the animation starts, which gives a weird effect like this:
I would like to keep the right side of the webview anchored to the right side of the screen and only have the left side change position when animating (basicaly so that the "done" button is always in the same position).
Here is the animation code:
- (void)revealSidebar:(BOOL)shouldReveal {
if (shouldReveal) {
[UIView beginAnimations:#"" context:nil];
[UIView setAnimationDuration:0.3];
// Push the view to the right
contentView.transform = CGAffineTransformTranslate(contentView.transform, CGRectGetWidth(sidebarView.frame), 0);
// Resize the view so it fits on remaining part of the screen
contentView.frame = CGRectMake(contentView.frame.origin.x, contentView.frame.origin.y, contentView.frame.size.width-sidebarView.frame.size.width, contentView.frame.size.height);
// The problem is here: the view's frame is changed before the
// Translate transformation actualy starts...
//
// Is there a way to change the x origin and the width simultaneously ?
[UIView commitAnimations];
} else {
[UIView beginAnimations:#"" context:nil];
[UIView setAnimationDuration:0.3];
// Reset the frame so that it takes up whole screen
contentView.frame = CGRectMake(contentView.bounds.origin.x,contentView.bounds.origin.y,contentView.frame.size.width+sidebarView.frame.size.width,contentView.frame.size.height);
[UIView commitAnimations];
}
_state.isShowing = shouldReveal ? 1 : 0;
}
I've had no luck so far, and was wandering if anyone had any ideas as to how I could achieve this.
Thank you
EDIT 2:
It seems that the subviews are being immediately resized dueto translations being used. So maybe you could just animate the move to the right and then when that has finished set the width:
- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
contentView.frame = CGRectMake(CGRectGetWidth(sidebarView.frame), 0, contentView.frame.size.width-CGRectGetWidth(sidebarView.frame), contentView.frame.size.height);
}
- (void)animationDidStopBack:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
contentView.frame = contentView.bounds;
}
- (void)revealSidebar:(BOOL)shouldReveal {
if (shouldReveal) {
[UIView beginAnimations:#"" context:nil];
[UIView setAnimationDuration:0.1];
[UIView setAnimationDelegate:self];
contentView.frame = CGRectOffset(contentView.bounds, CGRectGetWidth(sidebarView.frame), 0);
[UIView setAnimationDidStopSelector:#selector(animationDidStop:finished:context:)];
[UIView commitAnimations];
} else {
[UIView beginAnimations:#"" context:nil];
[UIView setAnimationDuration:0.3];
[UIView setAnimationDelegate:self];
contentView.frame = CGRectMake(0, 0, contentView.frame.size.width+CGRectGetWidth(sidebarView.frame), contentView.frame.size.height);
[UIView setAnimationDidStopSelector:#selector(animationDidStopBack:finished:context:)];
[UIView commitAnimations];
}
_state.isShowing = shouldReveal ? 1 : 0;
}
It's not perfect but does avoid the blank space on the right and I feel looks better because of that. Particularly if you speed up the animation.
EDIT 1:
try:
[UIView beginAnimations:#"" context:nil];
[UIView setAnimationDuration:0.3];
if (shouldReveal) {
contentView.frame = CGRectMake(CGRectGetWidth(sidebarView.frame), 0, contentView.frame.size.width-CGRectGetWidth(sidebarView.frame), contentView.frame.size.height);
} else {
contentView.frame = CGRectMake(0, 0, contentView.frame.size.width+CGRectGetWidth(sidebarView.frame), contentView.frame.size.height);
}
[UIView commitAnimations];
Old Answer:
sounds /looks like you just need your x position modifying to always be at the edge of the sidebar. untested code assuming your contentview's origin is at far left:
- (void)revealSidebar:(BOOL)shouldReveal {
if (shouldReveal) {
[UIView beginAnimations:#"" context:nil];
[UIView setAnimationDuration:0.3];
// Push the view to the right
contentView.transform = CGAffineTransformTranslate(contentView.transform, CGRectGetWidth(sidebarView.frame), 0);
// Resize the view so it fits on remaining part of the screen
contentView.frame = CGRectMake(contentView.frame.origin.x, contentView.frame.origin.y, contentView.frame.size.width-sidebarView.frame.size.width, contentView.frame.size.height);
[UIView commitAnimations];
} else {
[UIView beginAnimations:#"" context:nil];
[UIView setAnimationDuration:0.3];
// Resize the view so it fits on full screen
contentView.frame = CGRectMake(sidebarView.frame.size.width, contentView.frame.origin.y, contentView.frame.size.width-sidebarView.frame.size.width, contentView.frame.size.height);
[UIView commitAnimations];
}
_state.isShowing = shouldReveal ? 1 : 0;
}
if the origin is actually centred then:
contentView.frame = CGRectMake(sidebarView.frame.size.width+(contentView.frame.size.width/2), contentView.frame.origin.y, contentView.frame.size.width-sidebarView.frame.size.width, contentView.frame.size.height);
Okay, so I want to make a menu that expands down at the current touch location. I achieve this by adding my menuView with a height of 1 and then changing the height to my desired one like this:
[UIView beginAnimations:NULL context:nil];
CGRect fullRect;
fullRect = CGRectMake(menuView.frame.origin.x, menuView.frame.origin.y, 290, 180);
menuView.frame = fullRect;
[UIView commitAnimations];
Now the problem is that there are 4 buttons in this menuView and these buttons appear first and then the menuView expands down under them. Any ideas how to make the buttons appear with the menuView and not before it?
You have to set menuView.clipsToBounds = YES so the buttons are not shown outside the bounds of your menuView while it is expanding.
I would also add the following to have a fade-in effect for your buttons.
button1.alpha = 0.0; // Do this for each button before the [UIView beginAnimations];
button1.alpha = 1.0; // Do this during the animation block.
I would use a Block animation instead. That way, you can make the buttons appear during or after the animation easily. Try something like:
[UIView animateWithDuration:1.0
animations:^{
CGRect newRect = menuView.frame;
menuView.size.height += 289;
menuView.frame = newRect;
}
completion:^(BOOL finished){
[UIView animateWithDuration:0.1
animations:^{
button.hidden = NO;
}
completion:^(BOOL finished){
;
}];
}];
This will make the button stop hiding at the end of the animation. Of course, you could add more blocks in the completion block to handle more animations, and it is easy to customize this. Hope that helps!