iOS开发 | 双面view

作者: 无夜之星辰 | 来源:发表于2017-12-13 15:58 被阅读1279次
iu

将一个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,感谢大家的建议。

相关文章

网友评论

  • moonCoder:- (void)viewTranstion {
    [self.view endEditing:YES];
    CATransition *animation = [CATransition animation];
    animation.delegate = self;
    animation.duration = 0.5;
    animation.timingFunction = UIViewAnimationCurveEaseInOut;
    animation.type = @"oglFlip";
    animation.subtype = kCATransitionFromRight;
    [[self.view layer] addAnimation:animation forKey:@"animation"];
    }
    这是我实现的代码
    无夜之星辰:欧阳大佬这个nice
  • 鱼香肉丝_我鱼呢:之前写过这个东西,思路是一样的
    写完之后才反应过来,这是苹果自带的过度动画效果,几行代码就行
    鱼香肉丝_我鱼呢:@无夜之星辰 这种思路写,有些莫名其妙的坑可能你没遇到:1.旋转的方向,理论上两次旋转方向是相反的,但是直接旋转180‘方向应该是控制不了的,2.会出现模糊情况(文字),按说文字是矢量的,怎么都不会模糊,3.旋转的时候,这两个view必须要另有一个共同superView负责旋转动画(就是说动画不能直接加在这两个view上),否则那个效果是无法形容的而且诡异的, 我当时碰到的主要就是这三个坑, 当然都有方式可以处理掉,但是这就是UIView的过度动画,没必要自己处理动画细节
    鱼香肉丝_我鱼呢:@无夜之星辰 “UIViewController系统提供的转场动画”是指:`UIVIew.transition(from....to.....)`? ,这个东西不是只能用在`UIViewController.view`的,而是`UIView`的过度动画,还有一个`UIView.transition(with...)`看你需求需要用哪一个
    无夜之星辰:@鱼香肉丝_我鱼呢 我知道UIViewController有个系统提供的转场动画是这样的,UIView的是哪个API能否告知下?
  • 骨古:博主 你这个循环转换 是怎么实现的 demo中没有看到
    骨古:@无夜之星辰 谢谢博主
    无夜之星辰:我添加这个功能了,代码更新到GitHub了
  • 萧城x:可以
  • TinXie:很棒! 讓我受用無窮~
    无夜之星辰:有用就好:grin:
  • 夜半醒:没出轨好意思开写技术贴?
    夜半醒:@无夜之星辰 :smirk::smirk:算了,你不懂这个梗
    无夜之星辰:@夜半醒 意思是你出轨了才好意思?
  • 史努比不是小孩:简书上的人都说我们喜欢自黑,然后他们来黑我们,你在简书上发文章不瑟瑟发抖吗
    无夜之星辰:没事,我们可以黑回去
  • CepheusSun:双面 cell 呢,collectionview 点击 cell 翻转 :grin: 快师傅怎么考虑
    无夜之星辰:@HHL_ 你自己试试吧
    否极泰来_L:你就不能在cell上放个双面view吗?
    无夜之星辰:还没研究
  • 37e4dd6ddc60:快师傅不撤么
    37e4dd6ddc60:@无夜之星辰 我在简书写的两篇文章都删了:blush:
    无夜之星辰:简书不少所谓的文艺青年讨厌程序员,那我偏要在简书写
  • Maj_sunshine:上班还能写这个 美滋滋啊羡慕:dizzy_face:
    无夜之星辰:不是很忙,边重构边总结

本文标题:iOS开发 | 双面view

本文链接:https://www.haomeiwen.com/subject/agbnixtx.html