Анимировать между двумя состояниями представления, используя пользовательскую анимацию - PullRequest
6 голосов
/ 01 июля 2010

Я хотел бы анимировать между двумя состояниями представления.Скажем, например, у меня есть представление с меткой, и когда я изменяю текст метки, анимация рендерится, которая меняется при перелистывании страницы.

Теперь вы, конечно, можете сделать это с [UIView setAnimationTransition:forView:cache:]:

- (IBAction)nextPage {
    [UIView beginAnimation:nil context:nil];
    [UIView setAnimationDuration:1];
    [UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:pageView cache:NO];
    label.text = @"page 2";
    [UIView commitAnimations];
}

- (IBAction)previousPage {
    [UIView beginAnimation:nil context:nil];
    [UIView setAnimationDuration:1];
    [UIView setAnimationTransition:UIViewAnimationTransitionCurlDown forView:pageView cache:NO];
    label.text = @"page 1";
    [UIView commitAnimations];
}

... но тогда вы не сможете использовать свою собственную пользовательскую анимацию, вы застряли во встроенной анимации(они хороши, но они не приспособлены к моим потребностям).

Таким образом, другой вариант - добавить CAAnimation к слою вида:

- (IBAction)nextPage {
    CAAnimation *animation = [self animationWithDuration:1 forward:NO];
    [pageView.layer addAnimation:animation forKey:@"pageTransition"];
    label.text = @"page 2";
}

- (IBAction)previousPage {
    CAAnimation *animation = [self animationWithDuration:1 forward:YES];
    [pageView.layer addAnimation:animation forKey:@"pageTransition"];
    label.text = @"page 1";
}

Тогда вы можете установить любую анимацию, которую Core Animation позволит вам сделать.Это хорошо работает, если я определяю анимацию CATransition, например kCATransitionReveal: представление в состоянии «страница 2» появляется под представлением в состоянии «страница 1», когда оно выскальзывает.

- (CAAnimation *)animationWithDuration:(float)duration forward:(BOOL)forward {
    CATransition *animation = [CATransition animation]; 
    [animation setType:kCATransitionReveal];
    [animation setSubtype:forward?kCATransitionFromLeft:kCATransitionFromRight];
    [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]];

    animation.duration = duration; 
    return animation; 
}

Но когда я определяю анимацию, например, как CABasicAnimation, видимо только одно состояние представления.

- (CAAnimation *)animationWithDuration:(float)duration forward:(BOOL)forward {
    CATransform3D transform = CATransform3DIdentity;
    transform.m34 = 1.0 / -1000;
    transform = CATransform3DRotate(transform, M_PI, 0.0f, 1.0f, 0.0f);
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform"];
    if(forward) {
        animation.fromValue = [NSValue valueWithCATransform3D:transform];
    } else {
        animation.toValue = [NSValue valueWithCATransform3D:transform];
    }

    animation.duration = duration; 
    return animation; 
}

Вместо этого я хотел бы, чтобы представление в состоянии «страница 1» оставалось видимым до конца анимации, пока представление в состоянии «страница 2» входит в кадр, точно так же, как оно ведет себяс анимацией перехода.

Конечно, я всегда мог возиться с дублированием представления и отображением его в качестве одноуровневого вида, в то время как я оживляю самый передний вид и удаляю его из суперпредставления по завершении ... но должен быть гораздо более прямой путьчтобы добиться этого довольно простого анимационного эффекта, не возиться с видами.

Возможно, что-то сказать слою, но тогда я не знаю что, и вот где мне нужна ваша помощь, ребята :)

Спасибо!

Ответы [ 3 ]

1 голос
/ 09 августа 2010

Недавно я сделал собственный переход между слайдами между подпредставлениями в контроллере. Мой подход состоял в том, чтобы получить растровое изображение вида и вида, добавить их в вид и анимировать этот вид. В конце вы можете просто удалить переходный вид и показать вид. Вот фрагмент метода перехода:

-(void) transitionToView:(UIView *)viewIn lastView:(UIView *)viewOut slideRight:(BOOL)isRight { 
UIGraphicsBeginImageContext(viewOut.frame.size);

UIImageView *bitmapOut = [[UIImageView alloc] initWithFrame: viewOut.frame];

[viewOut.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *viewOutImage = UIGraphicsGetImageFromCurrentImageContext();   
UIGraphicsEndImageContext();
bitmapOut.image = viewOutImage;

UIImageView *bitmapIn = [[UIImageView alloc] initWithFrame: viewIn.frame ];
bitmapIn.frame = CGRectMake(isRight ? 320 : -320, bitmapIn.frame.origin.y, bitmapIn.frame.size.width, bitmapIn.frame.size.height);
UIGraphicsBeginImageContext(viewIn.frame.size);

[viewIn.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *viewInImage = UIGraphicsGetImageFromCurrentImageContext();   
UIGraphicsEndImageContext();

bitmapIn.image = viewInImage;

[self.view addSubview:transitionContainer];

[transitionContainer addSubview:bitmapIn];
[transitionContainer addSubview:bitmapOut];

[self removeAllViews];

[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5f];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(swapViewsAtEndOfTransition:)];
transitionContainer.frame = CGRectMake(isRight ? -320 : 320, 0, 640, 411);
[UIView commitAnimations];

[bitmapOut release]; bitmapOut = nil;
[bitmapIn release]; bitmapIn = nil;}

Затем в селекторе swapViewsAtEndOfTransition вы можете соответствующим образом обновить представления.

0 голосов
/ 23 мая 2012

Прошли годы, но я думаю, что нашел решение для вас.Просто используйте kCATransitionPush вместо kCATransitionReveal.Как это:

- (CAAnimation *)animationWithDuration:(float)duration forward:(BOOL)forward {
    CATransition *animation = [CATransition animation]; 
    [animation setType:kCATransitionPush];
    [animation setSubtype:forward?kCATransitionFromLeft:kCATransitionFromRight];
    [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]];

    animation.duration = duration; 
    return animation; 
}
0 голосов
/ 14 июля 2010

Ну, вы можете создать слой, установить его содержимое на изображение, представляющее конечное состояние вашего представления, а затем применить анимацию к этому слою.Когда анимация закончится, вы можете удалить слой и переключить состояние просмотра.

Я думаю, что это будет работать лучше, чем создание экземпляра всего представления.

...