In my app there is an animation. when I press a button the animation (lets say a box moves from the left to the right.) is performed and the ViewController is changed by "pushViewContreller". What I want is when I use popViewController from the secondViewController, the firstViewController should be opened and the box should move from right to left(reverse action). Thanks in advance.
Before navigate , save START position and END position of box, and when you come back then move box from END position to START position.
if you want to move a box then you can use this code.
First of all make two CGRect say CGRect left and CGRect right.
then in viewWillAppear of firstViewController write this code.
CGRect left = //Your left side Frame
CGRect right = //Your right side frame
if (CGRectContainsPoint(right, YourObject.center))
{
[UIView animateWithDuration:0.3 animations:^{
[YourObject setFrame:left];
}];
}
In this code viewWillAppear will call every time you when you pop secondViewController and if your box will be on right it will make animation of taking it to left.
on button click write this code
CGRect left = //Your left side Frame
[UIView animateWithDuration:0.3 animations:^{
[YourObject setFrame:left];
}];
Hope you will be happy after using this code........
Related
I am trying to make a simple application where there are 3 buttons. When user clicks any of the button, they are animated(moved) to their new positions! All this works from this code:
[UIView animateWithDuration:1.2
delay:0.1
options: UIViewAnimationCurveEaseOut
animations:^
{
//Moving the Sum (UIButton which will move through this animation)
CGRect frame = Sum.frame;
frame.origin.y = -20;
frame.origin.x = (-120);
Sum.frame = frame;
.....
....
}
completion:^(BOOL finished)
{
NSLog(#"Completed");
//adding subview after the animation is complete! newView is an example!
[self.view addSubview:newView];}];
The Problem is that once i add a subview to the main view, All buttons come back to their old position! meaning they weren't moved permanently.. how can i solve this? Plz help guys!
What happens when you add a view? A layout is performed. You could have done two mistakes
You are using autolayout.
If you are using autolayout, changing frames directly is not advised and a relayout will update the views to their original position using current constraints.
You are setting the frame position in layoutSubviews, viewWillLayout or viewDidLayout.
Check where you are setting the original position. Can the method be called multiple times?
You have save the X,Y Position of the new frame & then set this frame by coding.
This code animates my view every time it's run, except for the first time. When the keyboard is displayed or hidden, a UIView is repositioned:
[UIView
animateWithDuration:0.26
animations:^{
[self setupActiveOverlayViewFrame];
}completion:nil];
-(void)setupActiveOverlayViewFrame {
float optimalOverlayHeight = [self.activePanel optimalHeight];
float realOverlayHeight = MIN(optimalOverlayHeight, self.displayView.frame.size.height);
if (self.activePanel.frame.size.height != realOverlayHeight) {
self.activePanel.frame = CGRectMake(self.activePanel.frame.origin.x, 0, self.activePanel.frame.size.width, realOverlayHeight);
}
self.activePanel.center = [self correctCenterForOverlay];
}
The method I posted is just to show that all it does is re-size and re-position it.
The first time this code is run, it doesn't animate. It just jumps into position. Every time after that, it animates correctly.
Its possible that the "keyboard did display" notification is being called before your view is fully set up, like if you've pushed a view controller onto a navigation controller and immediately give a text view focus on viewDidLoad
You can either keep track of when the keyboard is up or down and when viewDidAppear is called, check if the keyboard is up, and run it. Or you can postpone giving focus to a text view/field until viewDidAppear: is called.
I got the same problem. I want to advice you to check Panel center before(!) animating to find out has it right position at the first run. If it's not. Just set right position. Also try the next code
[self setupActiveOverlayViewFrame];
[UIView animateWithDuration:0.26
animations:^{
[self.view layoutIfNeeded];
}completion:nil];
P.S. If you are using autolayout better use constraints to move your views using the code above.
Im struggling with some iOS development and I hope someone will be able to help me with an advice. I want to implement a stack of UIViews that will look like a deck of cards. User should be able to swipe out 'cards' with touch. I thought of UIScrollViews with pagingEnabled to give an impression that cards are separate. However, UIScrollView can swipe from horizontally where something appears from left or right side. I want my deck of cards to be in the middle of the screen so the user can swipe cards from the deck without seeing the card appearing on the left or right side.
Also, I was thinking of using Touch Methods ( touchesBegan, touchesMoved, etc.) to move views. It could work... but Im worried that I wont be able to reproduce proper mechanics of the card ( friction, bouncing effect when the swipe is to short and so on..).
Can someone please point me to a proper technique or advice some tutorials? I did some research already but I couldn't find anything that would be helpful.
Here is an image of the effect that I would like to achieve.
And what I want to achieve is to swipe cards out of the deck.
Thanks a lot!
I guess you want a swipe to take the top card of the stack and “shuffle” it to the bottom of the stack, revealing the second card on the stack, like this:
The animation is much smoother in real life. I had to use a low frame rate to make the animated GIF small.
One way to do this is to create a subclass of UIView that manages the stack of card views. Let's call the manager view a BoardView. We'll give it two public methods: one for shuffling the top card to the bottom, and one for shuffling the bottom card to the top.
#interface BoardView : UIView
- (IBAction)goToNextCard;
- (IBAction)goToPriorCard;
#end
#implementation BoardView {
BOOL _isRestacking;
}
We'll use the _isRestacking variable to track whether the board view is animating the movement of a card off to the side.
A BoardView treats all of its subviews as card views. It takes care of stacking them up, with the top card centered. In your screen shot, you offset the lower cards by slightly randomized amounts. We can make it look a little sexier by rotating the lower cards randomly. This method applies a small random rotation to a view:
- (void)jostleSubview:(UIView *)subview {
subview.transform = CGAffineTransformMakeRotation((((double)arc4random() / UINT32_MAX) - .5) * .2);
}
We'll want to apply that to each subview as it's added:
- (void)didAddSubview:(UIView *)subview {
[self jostleSubview:subview];
}
The system sends layoutSubviews whenever a view's size changes, or when a view has been given new subviews. We'll take advantage of that to lay out all of the cards in a stack in the middle of the board view's bounds. But if the view is currently animating a card out of the way, we don't want to do the layout because it would kill the animation.
- (void)layoutSubviews {
if (_isRestacking)
return;
CGRect bounds = self.bounds;
CGPoint center = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));
UIView *topView = self.subviews.lastObject;
CGFloat offset = 10.0f / self.subviews.count;
for (UIView *view in self.subviews.reverseObjectEnumerator) {
view.center = center;
if (view == topView) {
// Make the top card be square to the edges of the screen.
view.transform = CGAffineTransformIdentity;
}
center.x -= offset;
center.y -= offset;
}
}
Now we're ready to handle the shuffling. To “go to the next card”, we need to animate moving the top card off to the side, then move it to the bottom of the subview stacking order, and then animate it back to the middle. We also need to nudge the positions of all of the other cards because they've all moved closer to the top of the stack.
- (void)goToNextCard {
if (self.subviews.count < 2)
return;
First, we animate the movement of the top card off to the side. To make it look sexy, we rotate the card as we move it.
UIView *movingView = self.subviews.lastObject;
[UIView animateWithDuration:1 delay:0 options:UIViewAnimationCurveEaseInOut animations:^{
_isRestacking = YES;
CGPoint center = movingView.center;
center.x = -hypotf(movingView.frame.size.width / 2, movingView.frame.size.height / 2);
movingView.center = center;
movingView.transform = CGAffineTransformMakeRotation(-M_PI_4);
}
In the completion block, we move the card to the bottom of the stack.
completion:^(BOOL finished) {
_isRestacking = NO;
[self sendSubviewToBack:movingView];
And to move the now-bottom card back into the stack, and nudge all of the other cards, we'll just call layoutSubviews. But we're not supposed to call layoutSubviews directly, so instead we use the proper APIs: setNeedsLayout followed by layoutIfNeeded. We call layoutIfNeeded inside an animation block so the cards will be animated into their new positions.
[self setNeedsLayout];
[UIView animateWithDuration:1 delay:0 options:UIViewAnimationCurveEaseInOut | UIViewAnimationOptionAllowUserInteraction animations:^{
[self jostleSubview:movingView];
[self layoutIfNeeded];
} completion:nil];
}];
}
That's the end of goToNextCard. We can do goToPriorCard similarly:
- (void)goToPriorCard {
if (self.subviews.count < 2)
return;
UIView *movingView = [self.subviews objectAtIndex:0];
[UIView animateWithDuration:1 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
_isRestacking = YES;
CGPoint center = movingView.center;
center.x = -movingView.frame.size.height / 2;
movingView.center = center;
movingView.transform = CGAffineTransformMakeRotation(-M_PI_4);
} completion:^(BOOL finished) {
_isRestacking = NO;
UIView *priorTopView = self.subviews.lastObject;
[self bringSubviewToFront:movingView];
[self setNeedsLayout];
[UIView animateWithDuration:1 delay:0 options:UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionAllowUserInteraction animations:^{
[self jostleSubview:priorTopView];
[self layoutIfNeeded];
} completion:nil];
}];
}
Once you have BoardView, you just need to attach a swipe gesture recognizer that sends it the goToNextCard message, and another swipe gesture recognizer that sends it the goToPriorCard message. And you need to add some subviews to act as cards.
Another detail: to get the edges of the cards to look smooth when they're jostled, you need to set UIViewEdgeAntialiasing to YES in your Info.plist.
You can find my test project here: http://dl.dropbox.com/u/26919672/cardstack.zip
Icarousel has that exact built in scrolling using UIImageViews.
https://github.com/nicklockwood/iCarousel. There's several different effects in there, I forget the name of the one you're describing.
In the Comcast Xfinity iPad app, there is a small button called "Filter by" at the bottom of the screen.
When a user touch the button, a overlay menu will slide up (like the menu UI in Android).
Can anyone give me some hints about how to create this kind of overlay menu?
Thanks.
For this you can create a UIView in your nib and make it look like the menu you need, then in viewdidload you can set its origin to be just off the screen and when you want it to appear just use an animation to slide it up into view and then slide it back off the screen when you're done.
In viewDidLoad:
CGRect frame = [your_menu_view].frame;
frame.origin.y += frame.size.height;
[your_menu_view].frame = frame;
When you are ready to show it:
NSTimeInterval animationDuration = 0.3;//play around with the animation length here
CGRect frame = [your_menu_view].frame;
[UIView beginAnimations:#"MenuSlideIn" context:nil];
[UIView setAnimationDuration:animationDuration];
frame.origin -= frame.size.height;
[your_menu_view].frame = frame;
[UIView commitAnimations];
Then use the same to get rid of it except subtract add its height.
haven't tested it but it should work.
Basically I have created a UISwipeGestureRecognizer for my UITableView for when the user swipes from left to right. When the user swipes right to left, the DELETE renders and functions as it should.
I'm trying to get a new custom UIButton to render exactly the same way the DELETE button renders when swiped. It doesn't slide in but sort of slowly reveals itself from right to left?
I would like to do this for my custom UIButton to appear in the same place as DELETE except this time only when the user swipes right to left.
I have this method set as the #selector after a swipe has been detected right to left:
- (void)displayAddArchiveView:(UIGestureRecognizer *)gestureRecognizer {
// Assume this is the view container that will contain my UIButton
GreenGradientView *archiveView = [[GreenGradientView alloc] initWithFrame:CGRectMake(211.0, 3.0, 63.0, 30.0)];
if (gestureRecognizer.state == UIGestureRecognizerStateEnded) {
CGPoint swipeLocation = [gestureRecognizer locationInView:self.reportsTableView];
NSIndexPath *swipedIndexPath = [self.reportsTableView indexPathForRowAtPoint:swipeLocation];
ReportsTableViewCell *swipedCell = (ReportsTableViewCell *)[self.reportsTableView cellForRowAtIndexPath:swipedIndexPath];
[self tableView:reportsTableView willBeginEditingRowAtIndexPath:swipedIndexPath];
// HERE I should do some sort of UIView animation block to slowly reveal it
// from the right to left or something? Any suggestions. Not sure how to go about it?
[swipedCell addSubview:archiveView];
}
}
I have indicated by comments inside the code block my thoughts. The custom UIView actually does show up after swiping so I know it works. It's just a matter of getting the animation right, identical to how the DELETE button reveals itself? Suggestions?
Thanks!
You could try something like this
CGRect finalFrame = archiveView.frame;
archiveView.frame = CGRectMake(finalFrame.origin.x + finalFrame.size.width, finalFrame.origin.y, 0, finalFrame.size.height);
[UIView animateWithDuration:0.3 animations:^{
archiveView.frame = finalFrame;
}];
Basically I've reset the frame so it has no width and set the origin on the far right (so that it grows from the right towards the left). Then in the animation block, i set the frame to what I want it to be at the end. In your case you can just save the final frame in a local variable before you reset the frame to have zero width.