iOS开发 | 双面view
2017-12-13 本文已影响1279人
无夜之星辰
iu
旋转.gif
正面
反面
图片是反的.gif
将一个view绕y轴旋转180度是这样的:
旋转.gif
正面是:
正面
反面是:
反面
有时我们可能需要将背面设置成不同的图片或view,如下:
双面view.gif这种效果如何实现?
我的思路:
在一个透明view上依次放两个view,下面那个是bottomView,上面那个是topView,将bottomView旋转180度。翻转的时候,将透明view旋转180度。
为什么要将bottomView旋转180度?
如果不旋转,效果是这样的:
图片是反的.gif
图片是反的。为了能在旋转180度之后得到正确的图片,只有先将它旋转180度,这样两次旋转180后就是正的了。这就是为什么要先将bottomView旋转180度的原因。
切换两个view的时机?
当动画进行到一半的时候,将bottomView移到上面。
代码实现:
这是一个自定义view
.h文件:
#import <UIKit/UIKit.h>
@interface TwoSidedView : UIView
/** 顶部view */
@property (nonatomic, strong) UIView *topView;
/** 底部view */
@property (nonatomic, strong) UIView *bottomView;
/**
翻转
@param duration 翻转动画所需时间
@param completion 动画结束后的回调
*/
- (void)turnWithDuration:(NSTimeInterval)duration completion:(void(^)(void))completion;
@end
.m文件:
#import "TwoSidedView.h"
@implementation TwoSidedView
/** 设置顶部view */
- (void)setTopView:(UIView *)topView {
_topView = topView;
[self addSubview:topView];
[self bringSubviewToFront:_topView];
}
/** 设置底部view */
- (void)setBottomView:(UIView *)bottomView {
_bottomView = bottomView;
[self addSubview:_bottomView];
[self sendSubviewToBack:_bottomView];
// 翻转180度
CATransform3D transform = CATransform3DMakeRotation(M_PI, 0, 1, 0);
_bottomView.layer.transform = transform;
}
/**
翻转
@param duration 翻转动画所需时间
@param completion 动画结束后的回调
*/
- (void)turnWithDuration:(NSTimeInterval)duration completion:(void(^)(void))completion{
if (!self.topView || !self.bottomView) {
NSAssert(NO, @"未设置topView或bottomView");
}
// 动画进行到一半的时候将bottomView移到上层
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(duration / 2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self bringSubviewToFront:self.bottomView];
});
// 翻转180度
[UIView animateWithDuration:duration animations:^{
CATransform3D transform = CATransform3DMakeRotation(M_PI, 0, 1, 0);
self.layer.transform = transform;
} completion:^(BOOL finished) {
if (completion) {
completion();
}
}];
}
@end
这里是demo
2017/12/15更新
根据评论列表中的表鱼香肉丝_我鱼呢的建议,将翻转动画改为UIView
提供的系统方法。代码如下:
#import "TwoSidedView.h"
@implementation TwoSidedView {
BOOL _isTurning; // 是否正在翻转
BOOL _isReversed; // 是否反面朝上
}
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
_isTurning = NO;
_isReversed = NO;
}
return self;
}
/** 设置顶部view */
- (void)setTopView:(UIView *)topView {
_topView = topView;
[self addSubview:_topView];
[self bringSubviewToFront:_topView];
}
/** 设置底部view */
- (void)setBottomView:(UIView *)bottomView {
_bottomView = bottomView;
[self addSubview:_bottomView];
[self sendSubviewToBack:_bottomView];
}
/**
翻转
@param duration 翻转动画所需时间
@param completion 动画结束后的回调
*/
- (void)turnWithDuration:(NSTimeInterval)duration completion:(void(^)(void))completion{
if (!self.topView || !self.bottomView) {
NSAssert(NO, @"未设置topView或bottomView");
}
// 正在动画中不能重复执行
if (_isTurning) {
return;
}
_isTurning = YES;
if (_isReversed) { // 此时反面朝上
// 从反面翻转到正面
[UIView transitionFromView:self.bottomView toView:self.topView duration:duration options:UIViewAnimationOptionTransitionFlipFromLeft completion:^(BOOL finished) {
!completion ?: completion();
_isTurning = NO;
_isReversed = NO;
}];
} else { // 此时正面朝上
// 从正面翻转到反面
[UIView transitionFromView:self.topView toView:self.bottomView duration:duration options:UIViewAnimationOptionTransitionFlipFromRight completion:^(BOOL finished) {
!completion ?: completion();
_isTurning = NO;
_isReversed = YES;
}];
}
}
@end
代码已更新到GitHub,感谢大家的建议。