Xamarin PushViewController Zoom to subview - ios

Using Xamarin.iOS to develop an iPhone app.
I would like to achieve the same kind of animation as in the iPhone iOS7 Home Screen, where you zoom in to an app. I have a set of pictures in a Collection view. Each picture corresponds to a person, where you can tap the pic, to get to the next view controller, where you get information about the person .
Right now I am animating from bottom to top - would it be possible to achieve my desired animation type?
public override void ItemSelected (UICollectionView collectionView, NSIndexPath indexPath)
{
UIStoryboard MainStoryboard = UIStoryboard.FromName ("MainStoryboard_iPhone",null);
PersonDetailViewController personDetailViewController = MainStoryboard.InstantiateViewController ("PersonDetailViewController") as PersonDetailViewController;
personDetailViewController.personID = _viewController.Category.Persons [indexPath.Row].Id;
this._viewController.NavigationController.PushViewController (personDetailViewController,false);
var animation = CABasicAnimation.FromKeyPath("transform.translation.y");
animation.Duration = 0.3f;
animation.From = NSNumber.FromFloat(this._viewController.View.Frame.Height);
animation.To = NSNumber.FromFloat(0f);
this._viewController.NavigationController.View.Layer.AddAnimation(animation, "animate");
this._viewController.NavigationController.View.Layer.AnimationForKey("animate");
}

Check out this sample at objc.io of a zooming transition - hopefully you can translate from the Objective-C. Here's the animation part:
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIViewController* fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
[[transitionContext containerView] addSubview:toViewController.view];
toViewController.view.alpha = 0;
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
fromViewController.view.transform = CGAffineTransformMakeScale(0.1, 0.1);
toViewController.view.alpha = 1;
} completion:^(BOOL finished) {
fromViewController.view.transform = CGAffineTransformIdentity;
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];
}

Related

Animate a single shared element from UITableView to detail view

So I am attempting recreate something like this:
At the moment I'm trying JUST to animate a single element in this case the right box which is is UIImageView.
Currently I'm having trouble with the animateTransition function which seems to incorrectly move my UIImageView. For one, it starts at the top left always and secondly doesn't move into the correct position. (It seems like the issue is with the X position).
Here is my code (it's pretty rough):
-(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext{
DetailViewController *toViewController = (DetailViewController *)[transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
TableViewController* fromViewController = (TableViewController *)[transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UITableViewCell *cell = [fromViewController.tableView cellForRowAtIndexPath:[fromViewController.tableView indexPathForSelectedRow]];
UIImageView *cellImage = [cell viewWithTag:1];
[[transitionContext containerView] addSubview:cellImage];
[[transitionContext containerView] addSubview:toViewController.view];
[[transitionContext containerView] bringSubviewToFront:cellImage];
NSLog(#"FromFrame: %#, toFrame: %#", NSStringFromCGRect(cellImage.frame), NSStringFromCGRect(toViewController.headerImage.frame));
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
CGPoint finalCenterPoint = toViewController.headerImage.center;
cellImage.center = finalCenterPoint;
toViewController.view.alpha = 1;
} completion:^(BOOL finished) {
fromViewController.view.transform = CGAffineTransformIdentity;
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];
}
Would love some feedback. Also, I managed to find a solution using snapshots however I'm not sure they are the most performant way of doing this?
The other consideration is how would I handle NON shared elements?

popspringanimation very choppy in UINavigationController Delegate

In UINavigationController Delegate I add pop animation in the transition, what I did is as following:
- (NSTimeInterval) transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext {
return self.duration;
}
- (void) animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
UIView *containerView = [transitionContext containerView];
UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
// I get some cell from initialization
UIImageView *avatarImage = [[UIImageView alloc] initWithFrame:frame];
avatarImage.image = _cell.avatarImageView.image;
avatarImage.clipsToBounds = YES;
avatarImage.layer.cornerRadius = avatarImage.frame.size.width/2.0;
CGFloat originSize = avatarImage.frame.size.width;
[fromViewController.view addSubview:avatarImage];
CGFloat avatarSize = CURRENT_SCREEN_WIDTH * 0.15;
CGFloat avatarPositionY = CURRENT_SCREEN_WIDTH * 0.4;
POPSpringAnimation *animation = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerPosition];
animation.toValue = [NSValue valueWithCGPoint:CGPointMake(CURRENT_SCREEN_WIDTH/2.0, avatarPositionY + avatarSize/2.0 - 64)];
animation.springBounciness = 2.0;
[avatarImage.layer pop_addAnimation:animation forKey:#"move"];
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
toViewController.view.alpha = 1;
} completion:^(BOOL finished) {
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
[imageView removeFromSuperview];
[avatarImage removeFromSuperview];
}];
}
But the problem is, it's not smooth at all, what is the problem ?
There can be multiple problems;
Your image is very big (in memory)
The corner radius isn't helping either
You're doing something else on the main thread during during this animation
Try the following and see if the animation is smooth after each change:
Remove/comment:
avatarImage.image = _cell.avatarImageView.image;
Remove/comment:
avatarImage.clipsToBounds = YES;
avatarImage.layer.cornerRadius = avatarImage.frame.size.width/2.0;

Implment iOS system opening app zoom in/out animation effect

If user turn on the iOS 7 or above dynamic effect, when user taps an app icon, the system will have a zoom out/in effect for the app icon and its view, then go to start the app. I want to achieve similar zoom out/in animation. Any good implementations?
I got most code ready, like below, but not the exact animation I want:
#implementation PushAnimator
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext {
return 0.5;
}
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIViewController* fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
[[transitionContext containerView] addSubview:toViewController.view];
toViewController.view.alpha = 0;
UIApplication *app = [UIApplication sharedApplication];
MCAppDelegate *appDelegate = (MCAppDelegate *)app.delegate;
// CGRect fromFrame = appDelegate.UserTouchView.frame;
// CGRect toFrame = toViewController.view.frame;
//
CGFloat xFactor = fromViewController.view.frame.size.width / appDelegate.UserTouchView.frame.size.width;
CGFloat yFactor = fromViewController.view.frame.size.height / appDelegate.UserTouchView.frame.size.height;
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
appDelegate.UserTouchView.transform = CGAffineTransformMakeScale(xFactor,yFactor);
toViewController.view.transform = CGAffineTransformMakeScale(1, 1);
toViewController.view.alpha = 1;
} completion:^(BOOL finished) {
fromViewController.view.transform = CGAffineTransformIdentity;
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];
}
#end

Show scaled UIViewController in another UIViewController

I want to display a scaled down "preview" of another ViewController in another ViewController. Is this possible? No interaction are needed so it can basically be a screenshot, but scaled down. I can be solved by manually take a screenshot and save it as an image, but the ViewController contains a lot of localizations and are constantly updated, so if this can be done programatically.
https://www.dropbox.com/s/kd5vinrym1k7afk/Screenshot%202014-05-13%2015.20.17.png
Is this possible?
Edit: the sub view is stored in a storyboard
Edit: This is how I've solved it:
//Load the viewcontroller and view
previewViewController = [self.storyboard instantiateViewControllerWithIdentifier:[PLACEHOLDER_VIEWCONTROLLER_NAMES objectAtIndex:self.identifier]];
[self addChildViewController:previewViewController];
[self.placeholderView.superview addSubview:previewViewController.view];
previewViewController.view.transform = CGAffineTransformMakeScale(scale*2, scale*2);
CGPoint center = self.placeholderView.center;
center.y += 25;
previewViewController.view.center = center;
Use the viewController.view and then scale it down like:
viewController.view.transform = CGAffineTransformMakeScale(0.5, 0.5);
Add your another view controller view as subview to first viewcontroller
[UIView animateWithDuration:2.0f animations:^{
InnerView.userInteractionEnabled = NO;
//Always starts from original scale
InnerView.transform = CGAffineTransformMakeScale(0.5, 0.5);
//Incremental scale
//InnerView.transform = CGAffineTransformScale(InnerView.transform, 0.5, 0.5);
} completion:^(BOOL finished) {
NSLog(#"in Half size");
}];
[UIView animateWithDuration:2.0f animations:^{
InnerView.transform = CGAffineTransformIdentity;
} completion:^(BOOL finished) {
InnerView.userInteractionEnabled = YES;
NSLog(#"Normal size");
}];

Navigation bar gets adjusted after calling completeTransition: in custom transition

My goal is to provide zooming modal transition from for the user from a view similar as springboard icons zoom in when launching apps.
The presented view controller zooms in correctly, but the navigation bar has wrong position under the status bar. This position gets corrected after calling [transitionContext completeTransition:finished];. How can I make it correct from the beginning of the transition?
This is a screen recording of the bug: http://youtu.be/7LKU4lzb-uw (the glitch is in the 6th second of the recording)
The UIViewControllerAnimatedTransitioning code:
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIView *container = [transitionContext containerView];
CGPoint viewCenter = self.view.center;
CGSize viewSize = self.view.frame.size;
CGSize controllerSize = toViewController.view.frame.size;
CGFloat controllerFromX = viewCenter.x - (controllerSize.width / 2);
CGFloat controllerFromY = viewCenter.y - (controllerSize.height / 2);
CGAffineTransform transform = CGAffineTransformMakeTranslation(controllerFromX, controllerFromY);
transform = CGAffineTransformScale(transform, viewSize.width / controllerSize.width, viewSize.height / controllerSize.height);
if (self.reverse) {
[container insertSubview:toViewController.view belowSubview:fromViewController.view];
} else {
toViewController.view.transform = transform;
[container addSubview:toViewController.view];
}
[UIView animateKeyframesWithDuration:ZoomTransitioningDuration
delay:0
options:0
animations:^{
if (self.reverse) {
fromViewController.view.alpha = 0.0f;
fromViewController.view.transform = transform;
} else {
toViewController.view.transform = CGAffineTransformIdentity;
}
}
completion:^(BOOL finished) {
[transitionContext completeTransition:finished];
}];
}
The problem is that you are setting the transform before inserting the destination view controller's view into the container.
Switching the order should fix it:
if (self.reverse) {
[container insertSubview:toViewController.view belowSubview:fromViewController.view];
} else {
[container addSubview:toViewController.view];
toViewController.view.transform = transform;
}
See point 4 here. Since you've applied a transform prior to inserting the navigation controller's view as a subview, the layout engine doesn't think the navigation bar is at the top edge of the window, and therefore doesn't need to be adjusted to avoid the status bar.
I've found a solution, although pretty hacky. I have to manually adjust the navigation bar frame before the animation starts:
if (self.reverse) {
[container insertSubview:toViewController.view belowSubview:fromViewController.view];
} else {
toViewController.view.transform = transform;
[container addSubview:toViewController.view];
// fix navigation bar position to prevent jump when completeTransition: is called
if ([toViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController* navigationController = (UINavigationController*) toViewController;
UINavigationBar* bar = navigationController.navigationBar;
CGRect frame = bar.frame;
bar.frame = CGRectMake(frame.origin.x, frame.origin.y + 20.0f, frame.size.width, frame.size.height);
}
}
Add the toViewControllerView first to the ContainerView, then set the toViewControllerView transform as given below.
[container addSubview:toViewController.view];
toViewController.view.transform = transform;
This will solve the problem.
This is still a hack, based on Ondřej Mirtes' one but it works better if you have an in-call status bar and you're on iOS8
if([toViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController *navCtrl = (UINavigationController *)toViewController;
UINavigationBar *navBar = navCtrl.navigationBar;
if(navBar.frame.origin.y == 0 && navBar.frame.size.height == 44) {
navBar.frame = CGRectMake(0, 0, navBar.frame.size.width, fmin(44 + [UIApplication sharedApplication].statusBarFrame.size.height, 64));
}
}
Remains ugly though :/

Resources