Zaimplementuj niestandardową animację, aby przedstawić widok modalny z określonego widoku na iPadzie

Na iPadzie mamy dużo więcej miejsca do pracy, więc prezentowanie pełnoekranowych widoków modalnych nie jest idealne.

Wiem, jak przedstawić widoki modalne w nowym arkuszu formSheet i bliskie podejście można znaleźć na to pytanie: iPad iTunes Animation

Problem polega na tym, że nie można wybrać, skąd będzie pochodzić animacja, więc po prostu domyślnie i pojawia się z centrum, chcę dostosować go tak, aby wyświetlał się z określonej lokalizacji.

The best example I can Znajdź dla tej animacji można zobaczyć na pierwszych kilku sekund Ten Film

Jeśli ktoś może wskazać mi właściwy kierunek za pomocą kodu, tutoriali lub dokumentacji, byłbym bardzo wdzięczny!

Update:

Po pewnym dochodzeniu odkryłem, że można to zrobić za pomocą warstw i animacji rdzenia dla pierwszej części; a następnie animować go Widok modalny arkusza formularzy, ale nadal nie bardzo rozumiem, jak to osiągnąć, mam nadzieję, że chłopaki mogą pomóc!

Author: Community, 2011-07-07

7 answers

To, co zrobiłem, to stworzenie nowej kategorii Dla UIViewController w następujący sposób

UIViewController + ShowModalFromView.h

#import <Foundation/Foundation.h>
#import <QuartzCore/QuartzCore.h>

@interface UIViewController (ShowModalFromView)

- (void)presentModalViewController:(UIViewController *)modalViewController fromView:(UIView *)view;

@end

UIViewController + ShowModalFromView.m

#import "UIViewController+ShowModalFromView.h"

@implementation UIViewController (ShowModalFromView)

- (void)presentModalViewController:(UIViewController *)modalViewController fromView:(UIView *)view
{
    modalViewController.modalPresentationStyle = UIModalPresentationFormSheet;

    // Add the modal viewController but don't animate it. We will handle the animation manually
    [self presentModalViewController:modalViewController animated:NO];

    // Remove the shadow. It causes weird artifacts while animating the view.
    CGColorRef originalShadowColor = modalViewController.view.superview.layer.shadowColor;
    modalViewController.view.superview.layer.shadowColor = [[UIColor clearColor] CGColor];

    // Save the original size of the viewController's view    
    CGRect originalFrame = modalViewController.view.superview.frame;

    // Set the frame to the one of the view we want to animate from
    modalViewController.view.superview.frame = view.frame;

    // Begin animation
    [UIView animateWithDuration:1.0f
                     animations:^{
                         // Set the original frame back
                         modalViewController.view.superview.frame = originalFrame;
                     }
                     completion:^(BOOL finished) {
                         // Set the original shadow color back after the animation has finished
                         modalViewController.view.superview.layer.shadowColor = originalShadowColor;
                     }];
}

@end
To całkiem proste. Daj mi znać, jeśli to ci pomoże.

UPDATE

Zaktualizowałem odpowiedź, aby używać bloków animacji zamiast [UIView beginAnimations:nil context:nil]; / [UIView commitAnimations] para.

 21
Author: Mihai Fratu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-07 10:11:24

Wygląda na to, że jesteś zasadniczo po przetłumaczeniu (przesunięciu) CALayer skalując ją w dół i obracając ją wokół osi y w tym samym czasie. Spróbuj tego:

NSValue *initialTransformValue = [NSValue valueWithCATransform3D:CATransform3DIdentity];
CATransform3D translation = CATransform3DMakeTranslation(finalPoint.x, finalPoint.y, 0.0);
CATransform3D scalingAndTranslation = CATransform3DScale(translation, kMyScalingFactor, kMyScalingFactor, 1.0);
CATransform3D finalTransform = CATransform3DRotate(scalingAndTranslation, myRotationAngle, 0.0, 1.0, 0.0);
NSArray *keyFrameValues = [NSArray arrayWithObjects:initialTransformValue, [NSValue valueWithCATransform3D:finalTransform], nil];
CAKeyframeAnimation *myAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform"];
myAnimation.values = keyFrameValues;
myAnimation.duration = kMyAnimationDuration;
myAnimation.delegate = self;
myAnimation.removedOnCompletion = NO;
myAnimation.fillMode = kCAFillModeForwards;
[myLayer addAnimation:myAnimation forKey:@"myAnimationKey"];
  • finalPoint powinno być CGPoint w przestrzeni współrzędnych myLayer.
  • kMyScalingFactor powinno być 1.0 Dla skalowania w górę.
  • myRotationAngle powinny być w radianach. Użyj wartości dodatnich do obracania zgodnie z ruchem wskazówek zegara, a wartości ujemnych do przeciwnie do ruchu wskazówek zegara.

Musisz także zaimplementuj obsługę zakończenia animacji, aby animacja była "przyklejona":

- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag {
    myLayer.transform = finalTransform;
    myLayer removeAnimationForKey:@"myAnimationKey"];
}
Mam nadzieję, że to pomoże.
 5
Author: Spiros,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-15 13:08:27

Udało mi się to wcześniej, tylko animując widoki.

1) grafika albumu jest w siatce.
2) Przenieś widok kompozycji albumu za pomocą animacji odwrócenia.
3) Animuj widok poruszający się po ekranie.

Szybko rzuciłem to do kupy. Zakładając, że masz pusty kontroler widoku i 3 widoki.

- (void)viewDidLoad
{
    [super viewDidLoad];

    [self performSelector:@selector(transition) withObject:nil afterDelay:1];
    albumArtworkSquare = [[UIView alloc] initWithFrame:CGRectMake(400, 500, 300, 300)];
    albumArtworkSquare.backgroundColor = [UIColor blackColor];
    [self.view addSubview:albumArtworkSquare];

    frontViewOfAlbumArtwork = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 300)];
    frontViewOfAlbumArtwork.backgroundColor = [UIColor blueColor];
    [albumArtworkSquare addSubview:frontViewOfAlbumArtwork];

    backViewToTransitionTo = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 300)];
    backViewToTransitionTo.backgroundColor = [UIColor grayColor];
}

- (void)transition
{

    [UIView animateWithDuration:2 animations:^{
        albumArtworkSquare.frame = CGRectMake(10, 500, 300, 300);
    }];


    [UIView transitionFromView:frontViewOfAlbumArtwork toView:backViewToTransitionTo duration:2 options:UIViewAnimationOptionTransitionFlipFromRight completion:^(BOOL finished)
     {

         [frontViewOfAlbumArtwork removeFromSuperview];
         [albumArtworkSquare addSubview:backViewToTransitionTo];

     }];

}
 2
Author: Brandon Schlenker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-17 12:53:06

ODPOWIEDŹ Mihai nie radzi sobie z przerzucaniem tak, jak robi to animacja itunes iPada. Zmieniłem go trochę, aby odwrócić widok. Nie potrzebujesz wszelkiego rodzaju szalonych rzeczy do Caanimacji, wystarczy kilka wbudowanych funkcji animacji UIView.

#import <QuartzCore/QuartzCore.h>
@interface UIViewController (ShowModalFromView)

- (void)presentModalViewController:(UIViewController *)modalViewController fromView:(UIView *)view;

@end
@implementation UIViewController (ShowModalFromView)
- (void)presentModalViewController:(UIViewController *)modalViewController fromView:(UIView *)view
{
    NSTimeInterval scaleSpeed = 0.3;
    NSTimeInterval flipSpeed = 0.4;

    UIView __weak *containerView = view.superview;

    view.autoresizesSubviews = YES;

    [self presentModalViewController:modalViewController animated:NO];

    UIView __weak *presentedView = modalViewController.view.superview;

    //intead of show the actual view of modalViewController, we are showing the snapshot of it to avoid layout problem
    UIGraphicsBeginImageContext(presentedView.bounds.size);
    [presentedView.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage* modalSnapshot = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    UIView __weak *originalSuperView = presentedView.superview;   


    CGRect originalFrame = presentedView.frame;
    CGRect frameInContainer = [containerView convertRect:originalFrame fromView:originalSuperView];
    [presentedView removeFromSuperview];
    UIImageView* snapshotView = [[UIImageView alloc] initWithImage:modalSnapshot];
    snapshotView.autoresizingMask = UIViewAutoresizingNone;


    [containerView bringSubviewToFront:view];

    [UIView animateWithDuration:scaleSpeed delay:0 options:UIViewAnimationOptionCurveEaseIn|UIViewAnimationOptionBeginFromCurrentState animations: ^{
        [UIView animateWithDuration:scaleSpeed
                              delay:0
                            options:UIViewAnimationOptionBeginFromCurrentState
                         animations: ^{
                             view.frame = frameInContainer;

                         }

                         completion:nil
         ];


    } completion:^(BOOL finished) {

        [UIView setAnimationBeginsFromCurrentState:YES];
        [UIView transitionWithView:view duration:flipSpeed options:UIViewAnimationOptionCurveEaseIn|UIViewAnimationOptionTransitionFlipFromRight animations:
         ^{
             snapshotView.frame = view.bounds;
             [view addSubview:snapshotView];

         } completion:^(BOOL finished) {
             [originalSuperView addSubview:presentedView];
             [snapshotView removeFromSuperview];
         }
         ];
    }];
}
 2
Author: Hai Feng Kao,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-08 20:52:52

Możesz tego użyć..Do aplikacji opartej na kontrolerze nawigacyjnym..

YourViewController *obj = [[YourViewController alloc]initWithNibName:@"YourViewControllerXIBName" bundle:nil];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration: 1.0];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.navigationController.view cache:YES];
[self.navigationController pushViewController:obj animated:NO];
[UIView commitAnimations];
[obj release];
 1
Author: Mehul Mistri,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-07 05:09:17

Robię coś podobnego w jednym z moich projektów z siatką sztuk płytowych. Takie podejście przyjmuję. Kluczem jest użycie CAAnimationGroup.

1) Cała animacja obejmowałaby skalowanie, obracanie i poruszanie się po ścieżce w tym samym czasie-najpierw dla warstwy graficznej albumu, a następnie dla warstwy widoku modalnego.

2) ożywić warstwę graficzną albumu, odwracając ją o 90 stopni, skalując trochę i przesuwając się do predestynowanej lokalizacji z Aktualnej Lokalizacji. W tym wskaż, że zniknie (pionowo do ekranu).

3) Dodaj widok modalny. Skaluj i przekształcaj widok modalny tak, aby znajdował się dokładnie w miejscu, w którym znajduje się grafika albumu w kroku 1.

4) Animuj widok modalny z tej pozycji, skalując, obracając i poruszając się po ścieżce, aby wypełnić ekran.

5) Usuń widok modalny.

6) prezentuj widok modalny bez animacji.

7) wybrana ścieżka zwykle dodaje środek ekranu jako punkt kontrolny. Ale następnie można to zmienić w zależności od tego, jak ma wyglądać animacja.

Poniżej znajduje się funkcja, w której możesz zobaczyć użycie grupy animacji. Mam nadzieję, że to ci pomoże. Nadal Nie wiem, jak uniknąć przycinania animacji za pomocą pasków nawigacji i pasków kart. :)

+ (void)animateWithCurrentView:(UIView *)currentView 
{
    #define kResizeKey @"bounds.size"
    #define kPathMovement @"position"
    #define kRotation @"transform"
    #define kGroupAnimation @"subviewBeingAnimated"
    #define kLayerAnimation @"animateLayer"

    //flip the view by 180 degrees in its place first.
    currentView.layer.transform = CATransform3DRotate(currentView.layer.transform,radians(180), 0, 1, 0);

    //set the anchor point so that the view rotates on one of its sides.
    currentView.layer.anchorPoint = CGPointMake(0.0, 0.5);



    /**
     * Set up scaling
     */
    CABasicAnimation *resizeAnimation = [CABasicAnimation animationWithKeyPath:kResizeKey];

    //we are going to fill the screen here. So 320,480
    [resizeAnimation setToValue:[NSValue valueWithCGSize:CGSizeMake(320, 480)]];
    resizeAnimation.fillMode            = kCAFillModeForwards;
    resizeAnimation.removedOnCompletion = NO;


    /**
     * Set up path movement
     */
    UIBezierPath *movePath = [UIBezierPath bezierPath];

    //the control point is now set to centre of the filled screen. Change this to make the path different.
    CGPoint ctlPoint       = CGPointMake(160.0, 240.0);

    //This is the starting point of the animation. This should ideally be a function of the frame of the view to be animated. Hardcoded here.
    [movePath moveToPoint:CGPointMake(320, 60)];

    //The anchor point is going to end up here at the end of the animation.
    [movePath addQuadCurveToPoint:CGPointMake(0, 240) controlPoint:ctlPoint];

    CAKeyframeAnimation *moveAnim = [CAKeyframeAnimation animationWithKeyPath:kPathMovement];

    moveAnim.path                = movePath.CGPath;
    moveAnim.removedOnCompletion = YES;

    /**
     * Setup rotation animation
     */
    CABasicAnimation* rotateAnimation = [CABasicAnimation animationWithKeyPath:kRotation];
    //start from 180 degrees (done in 1st line)
    CATransform3D fromTransform       = CATransform3DMakeRotation(radians(180), 0, 1, 0);
    //come back to 0 degrees
    CATransform3D toTransform         = CATransform3DMakeRotation(radians(0), 0, 1, 0);

    //This is done to get some perspective.
    CATransform3D persp1 = CATransform3DIdentity;
    persp1.m34 = 1.0 / -3000;

    fromTransform = CATransform3DConcat(fromTransform, persp1);
    toTransform = CATransform3DConcat(toTransform,persp1);

    rotateAnimation.toValue             = [NSValue valueWithCATransform3D:toTransform];
    rotateAnimation.fromValue           = [NSValue valueWithCATransform3D:fromTransform];
    //rotateAnimation.duration            = 2;
    rotateAnimation.fillMode            = kCAFillModeForwards;
    rotateAnimation.removedOnCompletion = NO;

    /**
     * Setup and add all animations to the group
     */
    CAAnimationGroup *group = [CAAnimationGroup animation]; 

    [group setAnimations:[NSArray arrayWithObjects:moveAnim,rotateAnimation, resizeAnimation, nil]];

    group.fillMode            = kCAFillModeForwards;
    group.removedOnCompletion = NO;
    group.duration            = 0.7f;
    group.delegate            = self;

    [group setValue:currentView forKey:kGroupAnimation];

    /**
     * ...and go
     */
    [currentView.layer addAnimation:group forKey:kLayerAnimation];

}
 1
Author: Anil Puttabuddhi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-17 12:51:38

Jeśli możesz najpierw uzyskać widok modalny, aby pokazać się tam, gdzie chcesz, bez animacji. Powinna być prosta do przodu, a ustawienie granic / ramki view.superview może być przydatne w stylu arkusza.

Jeśli zostanie to rozwiązane, możesz wykonać animację "czysty widok", aby ją tam umieścić, a następnie usunąć widok i" zaprezentować " kontroler modalny (który kontroluje ten widok), aby natychmiast zamienić kontroler w logiczną kontrolę hierarchii widoku.

 0
Author: bshirley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-12 18:33:28