问题
The best way to understand what I'm trying to explain is to open Google+ app and tap anywhere in background of a post displayed in the main stream of posts.
When you tap it, the entire post moves itself at the center of the screen with a nice animation and it loads the post's comments below it.
I think this is a common UIViewController
containment scenario, where one UIViewController
is inside another. But how the post can moves it animately and "transfering" itself inside the contained view controller?
I've already tried to create a simple button and display an UIViewController
as a popup of one another but don't know how to do what Google+ app (and other ones) do, instead.
UPDATE
Here's the screenshots.
As you can see when you tap into a post, the post slides up and became a new contained UIViewController
.
回答1:
As has been pointed out, there are tons of ways to achieve this UI, but one way is to grab the view out of the tableview cell, move it onto some new backdrop, and change its frame. And when you're putting it back, just reverse the process.
In a little more detail that might be as follows:
In the cell, I have a container view which is a scroll view (whose user interaction is usually disabled).
When user taps on it,
Create a new backdrop view that is transparent that occupies the whole screen;
Give that backdrop a tap gesture recognizer that can reverse the process at a later point;
Move the cell's container view from the cell to this new backdrop view (using
convertRect
so it doesn't move yet);Animate the slight shrinking of the container via transformation (a subtle effect which gives you the effect of having "pushed down" on the view);
In the completion block of that animation, initiate a new animation that:
Restores the transformation back to identity;
Sets the backdrop background color to a largely opaque (but not entirely so) color;
Animate the size of the container view to take up more of the screen
Go ahead and enable user interaction on that container view so you can scroll around;
Have a handler for the tap gesture on our backdrop that reverses that process.
Thus:
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:NO];
PostCell *cell = (id)[tableView cellForRowAtIndexPath:indexPath];
// create subview to obscure the table view behind us
UIView *backdropView = [[UIView alloc] initWithFrame:self.view.bounds];
backdropView.backgroundColor = [UIColor clearColor];
[self.view addSubview:backdropView];
self.backdropView = backdropView;
// add a tap gesture so we can reverse the process
[backdropView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(handleTapGesture:)]];
// move the cell's container view to the backdrop view, preserving its location on the screen
// (so it doesn't look like it moved)
self.viewToMove = cell.containerView;
self.viewToMoveOriginalCell = cell;
self.viewToMoveOriginalFrame = cell.containerView.frame;
// figure out where this goes on the backdrop
CGRect frame = [self.viewToMoveOriginalCell convertRect:self.viewToMoveOriginalFrame
toView:self.backdropView];
// move it there (though it won't appear to move yet, we're just changing its superview)
[self.backdropView addSubview:self.viewToMove];
self.viewToMove.frame = frame;
// now do the animation
[UIView animateWithDuration:0.25
delay:0.0
options:0.0
animations:^{
// first shrinking it a bit
self.viewToMove.transform = CGAffineTransformMakeScale(0.95, 0.95);
}
completion:^(BOOL finished) {
// finally restoring the size and making it bigger
// (and reveal the backdrop that obscures the tableview)
[UIView animateWithDuration:0.5 animations:^{
CGFloat horizontalMargin = (self.view.bounds.size.width - frame.size.width) / 2.0;
backdropView.backgroundColor = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.8];
self.viewToMove.transform = CGAffineTransformIdentity;
self.viewToMove.frame = CGRectMake(horizontalMargin, kVerticalMargin, self.view.bounds.size.width - 2.0 * horizontalMargin, self.view.bounds.size.height - 2.0 * kVerticalMargin);
}];
self.viewToMove.userInteractionEnabled = YES;
}];
}
- (void)handleTapGesture:(UITapGestureRecognizer *)gesture
{
[UIView animateWithDuration:0.5
delay:0.0
options:0
animations:^{
// in case user scrolled in content view, scroll back
[self.viewToMove setContentOffset:CGPointZero animated:YES];
// figure out where to resize view on container view so it's
// going to end up where it will end up in the cell
CGRect frame = [self.viewToMoveOriginalCell convertRect:self.viewToMoveOriginalFrame
toView:self.backdropView];
self.viewToMove.frame = frame;
// make the back drop appear to gracefully disappear
self.backdropView.backgroundColor = [UIColor clearColor];
// shrink content view a tad in the process
self.viewToMove.transform = CGAffineTransformMakeScale(0.95, 0.95);
}
completion:^(BOOL finished) {
// when done with that animation ...
[UIView animateWithDuration:0.25
delay:0.0
options:0
animations:^{
// restore the size of the content view
self.viewToMove.transform = CGAffineTransformIdentity;
}
completion:^(BOOL finished) {
// when all done, put the content view back
// in the cell
[self.viewToMoveOriginalCell addSubview:self.viewToMove];
self.viewToMove.frame = self.viewToMoveOriginalFrame;
// turn off its user interaction again
self.viewToMove.userInteractionEnabled = NO;
// and now safely discard the backdrop
[self.backdropView removeFromSuperview];
}];
}];
}
As you can tell, this is all standard table views and the like. If you wanted to use view controller containment (e.g. if the view had significant user interaction), you could do that, too. It doesn't affect the UX in terms of the growing/shrinking of the cell's container view.
Also, this all is non-autolayout. You could do this with auto layout, but is more of a hassle, IMHO, because you'd probably have to remove and add constraints, but certainly can be done.
来源:https://stackoverflow.com/questions/16989516/uiviewcontroller-containment-with-animation-like-google