iOS: 如何为两个 UIView 之间的翻转设置动画?
iOS: How to animate a flip between two UIViews?
我正在尝试为 UIButton 实例和 UIImageView 实例之间的翻转效果设置动画。基本上它是一个 "flip over a playing card" 效果,一侧 (UIImageView) 只是一个很好的图案,当翻转时,它应该显示一个带有一些文本的 UIButton。
我的代码存在以下问题:
- UIButton 的文本sub-view 翻转后不显示
- 翻转动画时阴影消失
这是目标的直观表示:
Here you can download the very simple sample app.
有什么解决上述两个问题的建议吗?
我真的没有想法 - 非常感谢任何帮助!
这是 header 代码:
#import <UIKit/UIKit.h>
@interface CardView : UIControl
@property (nonatomic) BOOL isFrontSide;
- (void)setupView;
- (void)turnCard:(BOOL)inShow withAnimationCompletion:(void (^)(BOOL inFinished))inCompletion;
@end
实现代码如下:
#import "CardView.h"
#import "UIView+Extension.h"
#import <QuartzCore/QuartzCore.h>
#define kAllControlStates (UIControlStateNormal | UIControlStateHighlighted | UIControlStateDisabled| UIControlStateSelected)
@interface CardView()
@end
@implementation CardView
- (void)setupView {
[self styleViewWithRoundedEdges:YES shadowed:YES];
UIImageView *theBackView = [[UIImageView alloc] initWithFrame:self.bounds];
theBackView.image = [UIImage imageNamed:@"pattern.png"];
theBackView.hidden = NO;
theBackView.userInteractionEnabled = NO;
[theBackView styleViewWithRoundedEdges:YES shadowed:NO];
[self addSubview:theBackView];
UIButton *theFrontView = [[UIButton alloc] initWithFrame:self.bounds];
[theFrontView setTitle:@"Push me !" forState:kAllControlStates];
theFrontView.hidden = YES;
theFrontView.userInteractionEnabled = NO;
[theFrontView styleViewWithRoundedEdges:YES shadowed:NO];
[self addSubview:theFrontView];
}
- (void)turnCard:(BOOL)inShow withAnimationCompletion:(void (^)(BOOL inFinished))inCompletion {
[UIView transitionWithView:self duration:0.75
options:inShow ? UIViewAnimationOptionTransitionFlipFromLeft : UIViewAnimationOptionTransitionFlipFromRight
animations:^{
[(self.subviews)[0] setHidden:inShow]; // UIImage
[(self.subviews)[1] setHidden:!inShow]; // UIButton
}
completion:inCompletion];
}
@end
这是一个视觉装饰我的观点的类别:
#import "UIView+Extension.h"
@implementation UIView (Extension)
- (void)styleViewWithRoundedEdges:(BOOL)rounded shadowed:(BOOL)shadowed {
[self styleViewWithRoundedEdges:rounded shadowed:shadowed rasterized:YES];
}
- (void)styleViewWithRoundedEdges:(BOOL)rounded shadowed:(BOOL)shadowed rasterized:(BOOL)rasterized {
if (rounded) {
self.layer.cornerRadius = 3.0;
}
if (shadowed) {
self.layer.shadowColor = [UIColor blackColor].CGColor;
self.layer.shadowOffset = CGSizeMake(2.0, 2.0);
self.layer.shadowOpacity = 0.25;
self.layer.shadowRadius = 1.0;
if(rasterized) {
self.layer.shouldRasterize = YES;
self.layer.rasterizationScale = UIScreen.mainScreen.scale;
}
}
}
@end
尝试使用:
[UIView transitionFromView:self.subviews[0] toView:self.subviews[1] duration:0.5 UIViewAnimationOptionTransitionFlipFromLeft | UIViewAnimationOptionShowHideTransitionViews completion:^(BOOL finished) {
}];
这是我的解决方案,有阴影、圆角且没有性能问题:
在视图控制器的 viewDidLayoutSubviews
回调中调用 [self.yourUICardButtonInstance setupWithImage:[UIImage imageNamed:@"your-image.png"]];
。
Header:
//
// UICardButton.h
// CardFlipDemo
//
// Created by Nicolas Baumgardt on 25/08/15.
// Copyright (c) 2015 Nicolas Baumgardt. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface UICardButton : UIButton
- (void)setupWithImage:(UIImage*)backside;
- (void)flip;
- (void)flipFrontside;
- (void)flipBackside;
@end
实施:
//
// UICardButton.m
// CardFlipDemo
//
// Created by Nicolas Baumgardt on 25/08/15.
// Copyright (c) 2015 Nicolas Baumgardt. All rights reserved.
//
#import "UICardButton.h"
@interface UICardButton ()
@property (nonatomic) BOOL setup;
@property (nonatomic, strong) NSString* text;
@property (nonatomic, strong) UIImageView* subview;
@property (nonatomic) BOOL IBInspectable styled;
@property (nonatomic) BOOL IBInspectable frontside;
@end
@implementation UICardButton
- (void)setupWithImage:(UIImage*)backside {
if (!self.setup) {
// cache properties
self.text = self.currentTitle;
self.subview = [[UIImageView alloc] initWithFrame:self.bounds];
[self.subview setImage:backside];
// initialize card side
if (self.frontside) {
// frontside: with text
self.layer.transform = CATransform3DMakeRotation(0.0, 0.0, 1.0, 0.0);
[self setAttributedTitle:nil forState:UIControlStateNormal];
[self setTitle:self.text forState:UIControlStateNormal];
} else {
// backside: with image
self.layer.transform = CATransform3DMakeRotation(M_PI, 0.0, 1.0, 0.0);
[self addSubview:self.subview];
[self setAttributedTitle:nil forState:UIControlStateNormal];
[self setTitle:@"" forState:UIControlStateNormal];
}
// add a shadow by wrapping the button into a container and add rounded corners
if (self.styled) {
// add a shadow
self.layer.shadowColor = [UIColor blackColor].CGColor;
self.layer.shadowOffset = self.frontside ? CGSizeMake(2.0, 2.0) : CGSizeMake(-2.0, 2.0);
self.layer.shadowOpacity = 0.25;
self.layer.shadowRadius = 1.0;
self.layer.cornerRadius = 3.0;
self.layer.masksToBounds = NO;
// clip card image
self.subview.layer.masksToBounds = YES;
self.subview.layer.cornerRadius = 3.0;
// INFO: rasterization sometimes causes flickering, but enormous performance boost !
self.layer.shouldRasterize = YES;
self.layer.rasterizationScale = UIScreen.mainScreen.scale;
}
self.setup = YES;
}
}
- (void)flip {
if (self.frontside) {
[self flipBackside];
} else {
[self flipFrontside];
}
self.frontside = !self.frontside;
}
- (void)flipFrontside {
self.userInteractionEnabled = NO;
[UIView animateWithDuration:0.25 delay:0.0 options:UIViewAnimationOptionCurveEaseIn animations:^{
self.layer.transform = CATransform3DMakeRotation(M_PI_2, 0.0, 1.0, 0.0);
} completion:^(BOOL finished) {
[self.subview removeFromSuperview];
[self setAttributedTitle:nil forState:UIControlStateNormal];
[self setTitle:self.text forState:UIControlStateNormal];
self.layer.shadowOffset = CGSizeMake(2.0, 2.0);
[UIView animateWithDuration:0.25 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{
self.layer.transform = CATransform3DMakeRotation(0.0, 0.0, 1.0, 0.0);
} completion:^(BOOL finished) {
self.userInteractionEnabled = YES;
}];
}];
}
- (void)flipBackside {
self.userInteractionEnabled = NO;
[UIView animateWithDuration:0.25 delay:0.0 options:UIViewAnimationOptionCurveEaseIn animations:^{
self.layer.transform = CATransform3DMakeRotation(M_PI_2, 0.0, 1.0, 0.0);
} completion:^(BOOL finished) {
[self addSubview:self.subview];
[self setAttributedTitle:nil forState:UIControlStateNormal];
[self setTitle:@"" forState:UIControlStateNormal];
self.layer.shadowOffset = CGSizeMake(-2.0, 2.0);
[UIView animateWithDuration:0.25 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{
self.layer.transform = CATransform3DMakeRotation(M_PI, 0.0, 1.0, 0.0);
} completion:^(BOOL finished) {
self.userInteractionEnabled = YES;
}];
}];
}
@end
这应该有效
[UIView transitionFromView:self.subviews[0] toView:self.subviews[1] duration:0.5 UIViewAnimationOptionTransitionFlipFromLeft | UIViewAnimationOptionShowHideTransitionViews completion:^(BOOL finished) {
}];
我正在尝试为 UIButton 实例和 UIImageView 实例之间的翻转效果设置动画。基本上它是一个 "flip over a playing card" 效果,一侧 (UIImageView) 只是一个很好的图案,当翻转时,它应该显示一个带有一些文本的 UIButton。
我的代码存在以下问题:
- UIButton 的文本sub-view 翻转后不显示
- 翻转动画时阴影消失
这是目标的直观表示:
Here you can download the very simple sample app.
有什么解决上述两个问题的建议吗?
我真的没有想法 - 非常感谢任何帮助!
这是 header 代码:
#import <UIKit/UIKit.h>
@interface CardView : UIControl
@property (nonatomic) BOOL isFrontSide;
- (void)setupView;
- (void)turnCard:(BOOL)inShow withAnimationCompletion:(void (^)(BOOL inFinished))inCompletion;
@end
实现代码如下:
#import "CardView.h"
#import "UIView+Extension.h"
#import <QuartzCore/QuartzCore.h>
#define kAllControlStates (UIControlStateNormal | UIControlStateHighlighted | UIControlStateDisabled| UIControlStateSelected)
@interface CardView()
@end
@implementation CardView
- (void)setupView {
[self styleViewWithRoundedEdges:YES shadowed:YES];
UIImageView *theBackView = [[UIImageView alloc] initWithFrame:self.bounds];
theBackView.image = [UIImage imageNamed:@"pattern.png"];
theBackView.hidden = NO;
theBackView.userInteractionEnabled = NO;
[theBackView styleViewWithRoundedEdges:YES shadowed:NO];
[self addSubview:theBackView];
UIButton *theFrontView = [[UIButton alloc] initWithFrame:self.bounds];
[theFrontView setTitle:@"Push me !" forState:kAllControlStates];
theFrontView.hidden = YES;
theFrontView.userInteractionEnabled = NO;
[theFrontView styleViewWithRoundedEdges:YES shadowed:NO];
[self addSubview:theFrontView];
}
- (void)turnCard:(BOOL)inShow withAnimationCompletion:(void (^)(BOOL inFinished))inCompletion {
[UIView transitionWithView:self duration:0.75
options:inShow ? UIViewAnimationOptionTransitionFlipFromLeft : UIViewAnimationOptionTransitionFlipFromRight
animations:^{
[(self.subviews)[0] setHidden:inShow]; // UIImage
[(self.subviews)[1] setHidden:!inShow]; // UIButton
}
completion:inCompletion];
}
@end
这是一个视觉装饰我的观点的类别:
#import "UIView+Extension.h"
@implementation UIView (Extension)
- (void)styleViewWithRoundedEdges:(BOOL)rounded shadowed:(BOOL)shadowed {
[self styleViewWithRoundedEdges:rounded shadowed:shadowed rasterized:YES];
}
- (void)styleViewWithRoundedEdges:(BOOL)rounded shadowed:(BOOL)shadowed rasterized:(BOOL)rasterized {
if (rounded) {
self.layer.cornerRadius = 3.0;
}
if (shadowed) {
self.layer.shadowColor = [UIColor blackColor].CGColor;
self.layer.shadowOffset = CGSizeMake(2.0, 2.0);
self.layer.shadowOpacity = 0.25;
self.layer.shadowRadius = 1.0;
if(rasterized) {
self.layer.shouldRasterize = YES;
self.layer.rasterizationScale = UIScreen.mainScreen.scale;
}
}
}
@end
尝试使用:
[UIView transitionFromView:self.subviews[0] toView:self.subviews[1] duration:0.5 UIViewAnimationOptionTransitionFlipFromLeft | UIViewAnimationOptionShowHideTransitionViews completion:^(BOOL finished) {
}];
这是我的解决方案,有阴影、圆角且没有性能问题:
在视图控制器的 viewDidLayoutSubviews
回调中调用 [self.yourUICardButtonInstance setupWithImage:[UIImage imageNamed:@"your-image.png"]];
。
Header:
//
// UICardButton.h
// CardFlipDemo
//
// Created by Nicolas Baumgardt on 25/08/15.
// Copyright (c) 2015 Nicolas Baumgardt. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface UICardButton : UIButton
- (void)setupWithImage:(UIImage*)backside;
- (void)flip;
- (void)flipFrontside;
- (void)flipBackside;
@end
实施:
//
// UICardButton.m
// CardFlipDemo
//
// Created by Nicolas Baumgardt on 25/08/15.
// Copyright (c) 2015 Nicolas Baumgardt. All rights reserved.
//
#import "UICardButton.h"
@interface UICardButton ()
@property (nonatomic) BOOL setup;
@property (nonatomic, strong) NSString* text;
@property (nonatomic, strong) UIImageView* subview;
@property (nonatomic) BOOL IBInspectable styled;
@property (nonatomic) BOOL IBInspectable frontside;
@end
@implementation UICardButton
- (void)setupWithImage:(UIImage*)backside {
if (!self.setup) {
// cache properties
self.text = self.currentTitle;
self.subview = [[UIImageView alloc] initWithFrame:self.bounds];
[self.subview setImage:backside];
// initialize card side
if (self.frontside) {
// frontside: with text
self.layer.transform = CATransform3DMakeRotation(0.0, 0.0, 1.0, 0.0);
[self setAttributedTitle:nil forState:UIControlStateNormal];
[self setTitle:self.text forState:UIControlStateNormal];
} else {
// backside: with image
self.layer.transform = CATransform3DMakeRotation(M_PI, 0.0, 1.0, 0.0);
[self addSubview:self.subview];
[self setAttributedTitle:nil forState:UIControlStateNormal];
[self setTitle:@"" forState:UIControlStateNormal];
}
// add a shadow by wrapping the button into a container and add rounded corners
if (self.styled) {
// add a shadow
self.layer.shadowColor = [UIColor blackColor].CGColor;
self.layer.shadowOffset = self.frontside ? CGSizeMake(2.0, 2.0) : CGSizeMake(-2.0, 2.0);
self.layer.shadowOpacity = 0.25;
self.layer.shadowRadius = 1.0;
self.layer.cornerRadius = 3.0;
self.layer.masksToBounds = NO;
// clip card image
self.subview.layer.masksToBounds = YES;
self.subview.layer.cornerRadius = 3.0;
// INFO: rasterization sometimes causes flickering, but enormous performance boost !
self.layer.shouldRasterize = YES;
self.layer.rasterizationScale = UIScreen.mainScreen.scale;
}
self.setup = YES;
}
}
- (void)flip {
if (self.frontside) {
[self flipBackside];
} else {
[self flipFrontside];
}
self.frontside = !self.frontside;
}
- (void)flipFrontside {
self.userInteractionEnabled = NO;
[UIView animateWithDuration:0.25 delay:0.0 options:UIViewAnimationOptionCurveEaseIn animations:^{
self.layer.transform = CATransform3DMakeRotation(M_PI_2, 0.0, 1.0, 0.0);
} completion:^(BOOL finished) {
[self.subview removeFromSuperview];
[self setAttributedTitle:nil forState:UIControlStateNormal];
[self setTitle:self.text forState:UIControlStateNormal];
self.layer.shadowOffset = CGSizeMake(2.0, 2.0);
[UIView animateWithDuration:0.25 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{
self.layer.transform = CATransform3DMakeRotation(0.0, 0.0, 1.0, 0.0);
} completion:^(BOOL finished) {
self.userInteractionEnabled = YES;
}];
}];
}
- (void)flipBackside {
self.userInteractionEnabled = NO;
[UIView animateWithDuration:0.25 delay:0.0 options:UIViewAnimationOptionCurveEaseIn animations:^{
self.layer.transform = CATransform3DMakeRotation(M_PI_2, 0.0, 1.0, 0.0);
} completion:^(BOOL finished) {
[self addSubview:self.subview];
[self setAttributedTitle:nil forState:UIControlStateNormal];
[self setTitle:@"" forState:UIControlStateNormal];
self.layer.shadowOffset = CGSizeMake(-2.0, 2.0);
[UIView animateWithDuration:0.25 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{
self.layer.transform = CATransform3DMakeRotation(M_PI, 0.0, 1.0, 0.0);
} completion:^(BOOL finished) {
self.userInteractionEnabled = YES;
}];
}];
}
@end
这应该有效
[UIView transitionFromView:self.subviews[0] toView:self.subviews[1] duration:0.5 UIViewAnimationOptionTransitionFlipFromLeft | UIViewAnimationOptionShowHideTransitionViews completion:^(BOOL finished) {
}];