实现动画方式深度解析(十八) —— UIView动画 (一)

版本记录

版本号 时间
V1.0 2017.09.24

前言

app中好的炫的动画可以让用户耳目一新,为产品增色不少,关于动画的实现我们可以用基本动画、关键帧动画、序列帧动画以及基于CoreGraphic的动画等等,接下来这几篇我就介绍下我可以想到的几种动画绘制方法。具体Demo示例已开源到Github —— 刀客传奇,感兴趣的可以看我写的另外几篇。
1. 实现动画方式深度解析(一) —— 播放GIF动画(一)
2. 实现动画方式深度解析(二) —— 播放GIF动画之框架FLAnimatedImage的使用(二)
3. 实现动画方式深度解析(三) —— 播放序列帧动画(一)
4. 实现动画方式深度解析(四) —— QuartzCore框架(一)
5. 实现动画方式深度解析(五) —— QuartzCore框架之CoreAnimation(二)
6. 实现动画方式深度解析(六) —— Core Animation Basics(三)
7. 实现动画方式深度解析(七) —— Core Animation之Setting Up Layer Objects(四)
8. 实现动画方式深度解析(八) —— Core Animation之动画层内容 (五)
9. 实现动画方式深度解析(九) —— Core Animation之构建图层层级 (六)
10. 实现动画方式深度解析(十) —— Core Animation之高级动画技巧 (七)
11. 实现动画方式深度解析(十一) —— Core Animation之更改图层的默认行为(八)
12. 实现动画方式深度解析(十二) —— Core Animation之提高动画的性能(九)
13. 实现动画方式深度解析(十三) —— Core Animation之图层样式属性动画(十)
14. 实现动画方式深度解析(十四) —— Core Animation之 KVC 扩展(十一)
15. 实现动画方式深度解析(十五) —— Core Animation之可动画属性 (十二)
16. 实现动画方式深度解析(十六) —— Core Animation之CABasicAnimation动画示例 (十三)
17. 实现动画方式深度解析(十七) —— Core Animation之CAKeyframeAnimation动画示例 (十四)

UIView动画

UIView动画也是系统提供的一种动画实现方式,这种方式是实现很简单。UIView动画可以看做是对Core Animation的封装。

UIView可以进行动画属性如下:

  • frame
  • bounds
  • center
  • transform
  • alpha
  • backgroundColor
  • contentStretch

下面我们看一下UIView提供了有关动画的接口。

@interface UIView(UIViewAnimation)

+ (void)beginAnimations:(nullable NSString *)animationID context:(nullable void *)context;  // additional context info passed to will start/did stop selectors. begin/commit can be nested
+ (void)commitAnimations;                                                 // starts up any animations when the top level animation is commited

// no getters. if called outside animation block, these setters have no effect.
+ (void)setAnimationDelegate:(nullable id)delegate;                          // default = nil
+ (void)setAnimationWillStartSelector:(nullable SEL)selector;                // default = NULL. -animationWillStart:(NSString *)animationID context:(void *)context
+ (void)setAnimationDidStopSelector:(nullable SEL)selector;                  // default = NULL. -animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context
+ (void)setAnimationDuration:(NSTimeInterval)duration;              // default = 0.2
+ (void)setAnimationDelay:(NSTimeInterval)delay;                    // default = 0.0
+ (void)setAnimationStartDate:(NSDate *)startDate;                  // default = now ([NSDate date])
+ (void)setAnimationCurve:(UIViewAnimationCurve)curve;              // default = UIViewAnimationCurveEaseInOut
+ (void)setAnimationRepeatCount:(float)repeatCount;                 // default = 0.0.  May be fractional
+ (void)setAnimationRepeatAutoreverses:(BOOL)repeatAutoreverses;    // default = NO. used if repeat count is non-zero
+ (void)setAnimationBeginsFromCurrentState:(BOOL)fromCurrentState;  // default = NO. If YES, the current view position is always used for new animations -- allowing animations to "pile up" on each other. Otherwise, the last end state is used for the animation (the default).

+ (void)setAnimationTransition:(UIViewAnimationTransition)transition forView:(UIView *)view cache:(BOOL)cache;  // current limitation - only one per begin/commit block

+ (void)setAnimationsEnabled:(BOOL)enabled;                         // ignore any attribute changes while set.
#if UIKIT_DEFINE_AS_PROPERTIES
@property(class, nonatomic, readonly) BOOL areAnimationsEnabled;
#else
+ (BOOL)areAnimationsEnabled;
#endif
+ (void)performWithoutAnimation:(void (NS_NOESCAPE ^)(void))actionsWithoutAnimation NS_AVAILABLE_IOS(7_0);

#if UIKIT_DEFINE_AS_PROPERTIES
@property(class, nonatomic, readonly) NSTimeInterval inheritedAnimationDuration NS_AVAILABLE_IOS(9_0);
#else
+ (NSTimeInterval)inheritedAnimationDuration NS_AVAILABLE_IOS(9_0);
#endif

@end


@interface UIView(UIViewAnimationWithBlocks)

+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(4_0);

+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(4_0); // delay = 0.0, options = 0

+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations NS_AVAILABLE_IOS(4_0); // delay = 0.0, options = 0, completion = NULL

/* Performs `animations` using a timing curve described by the motion of a spring. When `dampingRatio` is 1, the animation will smoothly decelerate to its final model values without oscillating. Damping ratios less than 1 will oscillate more and more before coming to a complete stop. You can use the initial spring velocity to specify how fast the object at the end of the simulated spring was moving before it was attached. It's a unit coordinate system, where 1 is defined as travelling the total animation distance in a second. So if you're changing an object's position by 200pt in this animation, and you want the animation to behave as if the object was moving at 100pt/s before the animation started, you'd pass 0.5. You'll typically want to pass 0 for the velocity. */ 
+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay usingSpringWithDamping:(CGFloat)dampingRatio initialSpringVelocity:(CGFloat)velocity options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(7_0);

+ (void)transitionWithView:(UIView *)view duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options animations:(void (^ __nullable)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(4_0);

+ (void)transitionFromView:(UIView *)fromView toView:(UIView *)toView duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(4_0); // toView added to fromView.superview, fromView removed from its superview

/* Performs the requested system-provided animation on one or more views. Specify addtional animations in the parallelAnimations block. These additional animations will run alongside the system animation with the same timing and duration that the system animation defines/inherits. Additional animations should not modify properties of the view on which the system animation is being performed. Not all system animations honor all available options.
 */
+ (void)performSystemAnimation:(UISystemAnimation)animation onViews:(NSArray<__kindof UIView *> *)views options:(UIViewAnimationOptions)options animations:(void (^ __nullable)(void))parallelAnimations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(7_0);

@end


@interface UIView (UIViewKeyframeAnimations)

+ (void)animateKeyframesWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewKeyframeAnimationOptions)options animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(7_0);
+ (void)addKeyframeWithRelativeStartTime:(double)frameStartTime relativeDuration:(double)frameDuration animations:(void (^)(void))animations NS_AVAILABLE_IOS(7_0); // start time and duration are values between 0.0 and 1.0 specifying time and duration relative to the overall time of the keyframe animation

@end

UIView 动画几个重要接口

下面我们就看一下几个重要的接口。

1. 动画开始

+ (void)beginAnimations:(nullable NSString *)animationID context:(nullable void *)context;  
// additional context info passed to will start/did stop selectors. begin/commit can be nested

2. 结束动画标记

+ (void)commitAnimations; 

3. 设置动画时间

+ (void)setAnimationDuration:(NSTimeInterval)duration; 

4. 设置动画代理

+ (void)setAnimationDelegate:(nullable id)delegate;

5. 设置动画将开始时代理对象执行的SEL

+ (void)setAnimationWillStartSelector:(nullable SEL)selector; 

6. 设置动画结束时代理对象执行的SEL

+ (void)setAnimationDidStopSelector:(nullable SEL)selector; 

7. 设置动画延迟执行的时间

+ (void)setAnimationDelay:(NSTimeInterval)delay;  

8. 设置动画的重复次数

+ (void)setAnimationRepeatCount:(float)repeatCount; 

9. 设置动画的曲线

+ (void)setAnimationCurve:(UIViewAnimationCurve)curve; 

这里有一个枚举值,如下所示:

typedef NS_ENUM(NSInteger, UIViewAnimationCurve) {
    UIViewAnimationCurveEaseInOut,         // slow at beginning and end
    UIViewAnimationCurveEaseIn,            // slow at beginning
    UIViewAnimationCurveEaseOut,           // slow at end
    UIViewAnimationCurveLinear,
};

10. 设置是否从当前状态开始播放动画

+ (void)setAnimationBeginsFromCurrentState:(BOOL)fromCurrentState; 

 // default = NO. If YES, the current view position is always used for new animations -- allowing animations to "pile up" on each other. Otherwise, the last end state is used for the animation (the default).

假设上一个动画正在播放,且尚未播放完毕,我们将要进行一个新的动画:

  • 当为YES时:动画将从上一个动画所在的状态开始播放
  • 当为NO时:动画将从上一个动画所指定的最终状态开始播放(此时上一个动画马上结束)。

11. 设置动画是否继续执行相反的动画

+ (void)setAnimationRepeatAutoreverses:(BOOL)repeatAutoreverses;   

 // default = NO. used if repeat count is non-zero

12. 是否禁用动画效果

对象属性依然会被改变,只是没有动画效果。

+ (void)setAnimationsEnabled:(BOOL)enabled; 

13. 设置视图的过渡效果

+ (void)setAnimationTransition:(UIViewAnimationTransition)transition forView:(UIView *)view cache:(BOOL)cache; 

 // current limitation - only one per begin/commit block

这里有一个枚举UIViewAnimationTransition,如下所示:

typedef NS_ENUM(NSInteger, UIViewAnimationTransition) {
    UIViewAnimationTransitionNone,
    UIViewAnimationTransitionFlipFromLeft,
    UIViewAnimationTransitionFlipFromRight,
    UIViewAnimationTransitionCurlUp,
    UIViewAnimationTransitionCurlDown,
};

14. block动画

有关UIView的block动画,全部在UIView的一个分类UIViewAnimationWithBlocks里面。

@interface UIView(UIViewAnimationWithBlocks)

+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(4_0);

+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(4_0); // delay = 0.0, options = 0

+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations NS_AVAILABLE_IOS(4_0); // delay = 0.0, options = 0, completion = NULL

/* Performs `animations` using a timing curve described by the motion of a spring. When `dampingRatio` is 1, the animation will smoothly decelerate to its final model values without oscillating. Damping ratios less than 1 will oscillate more and more before coming to a complete stop. You can use the initial spring velocity to specify how fast the object at the end of the simulated spring was moving before it was attached. It's a unit coordinate system, where 1 is defined as travelling the total animation distance in a second. So if you're changing an object's position by 200pt in this animation, and you want the animation to behave as if the object was moving at 100pt/s before the animation started, you'd pass 0.5. You'll typically want to pass 0 for the velocity. */ 
+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay usingSpringWithDamping:(CGFloat)dampingRatio initialSpringVelocity:(CGFloat)velocity options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(7_0);

+ (void)transitionWithView:(UIView *)view duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options animations:(void (^ __nullable)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(4_0);

+ (void)transitionFromView:(UIView *)fromView toView:(UIView *)toView duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(4_0); // toView added to fromView.superview, fromView removed from its superview

/* Performs the requested system-provided animation on one or more views. Specify addtional animations in the parallelAnimations block. These additional animations will run alongside the system animation with the same timing and duration that the system animation defines/inherits. Additional animations should not modify properties of the view on which the system animation is being performed. Not all system animations honor all available options.
 */
+ (void)performSystemAnimation:(UISystemAnimation)animation onViews:(NSArray<__kindof UIView *> *)views options:(UIViewAnimationOptions)options animations:(void (^ __nullable)(void))parallelAnimations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(7_0);

@end

UIView 动画简单示例

下面我们就看一下UIView动画实现的简单示例。

1. 简单动画

我们先看一下简单的动画示例。

#import "ViewController.h"

@interface ViewController ()

@property (nonatomic, strong) UIView *animationView;

@end

@implementation ViewController

#pragma mark - Override Base Function

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    //UI
    [self setupUI];
    
    //UIView动画
    [self demoPropertyUIViewAnimation];
}

#pragma mark - Object Private Function

- (void)demoPropertyUIViewAnimation
{
    [UIView beginAnimations:@"animation" context:nil];
    [UIView setAnimationDuration:3.0];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationWillStartSelector:@selector(startAnimation)];
    [UIView setAnimationDidStopSelector:@selector(stopAnimation)];
    [UIView setAnimationRepeatCount:10];
    [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
    self.animationView.frame = CGRectMake(0.0, 0.0, 100.0, 100.0);
    [UIView commitAnimations];
}

- (void)setupUI
{
    self.view.backgroundColor = [UIColor lightGrayColor];
    
    self.animationView = [[UIView alloc] initWithFrame:CGRectMake(250.0, 250.0, 200.0, 200.0)];
    [self.view addSubview:self.animationView];
    self.animationView.backgroundColor = [UIColor redColor];
}

#pragma mark - Action && Notification

- (void)startAnimation
{
    NSLog(@"开始动画");
}

- (void)stopAnimation
{
    NSLog(@"停止动画");
}

@end

下面我们看一下输出以及动画效果。

2017-09-24 20:22:24.254 JJUIViewAnimation_demo9[3301:274498] 开始动画
2017-09-24 20:22:54.252 JJUIViewAnimation_demo9[3301:274498] 停止动画

2. block动画

ios 4.0以后出现的block动画,这种动画也是我们工程中常用的动画形式。

  • 最简洁的Block动画:包含时间和动画
+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations NS_AVAILABLE_IOS(4_0); 

// delay = 0.0, options = 0, completion = NULL
  • 带有动画完成回调的block动画
+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(4_0);

 // delay = 0.0, options = 0
  • 带有延迟时间和过度效果的动画
+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(4_0);

这里有一个枚举值UIViewAnimationOptions,它就是描述过度效果的枚举值。

 UIViewAnimationOptionLayoutSubviews            //进行动画时布局子控件
 UIViewAnimationOptionAllowUserInteraction      //进行动画时允许用户交互
 UIViewAnimationOptionBeginFromCurrentState     //从当前状态开始动画
 UIViewAnimationOptionRepeat                    //无限重复执行动画
 UIViewAnimationOptionAutoreverse               //执行动画回路
 UIViewAnimationOptionOverrideInheritedDuration //忽略嵌套动画的执行时间设置
 UIViewAnimationOptionOverrideInheritedCurve    //忽略嵌套动画的曲线设置
 UIViewAnimationOptionAllowAnimatedContent      //转场:进行动画时重绘视图
 UIViewAnimationOptionShowHideTransitionViews   //转场:移除(添加和移除图层的)动画效果
 UIViewAnimationOptionOverrideInheritedOptions  //不继承父动画设置

 UIViewAnimationOptionCurveEaseInOut            //时间曲线,慢进慢出(默认值)
 UIViewAnimationOptionCurveEaseIn               //时间曲线,慢进
 UIViewAnimationOptionCurveEaseOut              //时间曲线,慢出
 UIViewAnimationOptionCurveLinear               //时间曲线,匀速

 UIViewAnimationOptionTransitionNone            //转场,不使用动画
 UIViewAnimationOptionTransitionFlipFromLeft    //转场,从左向右旋转翻页
 UIViewAnimationOptionTransitionFlipFromRight   //转场,从右向左旋转翻页
 UIViewAnimationOptionTransitionCurlUp          //转场,下往上卷曲翻页
 UIViewAnimationOptionTransitionCurlDown        //转场,从上往下卷曲翻页
 UIViewAnimationOptionTransitionCrossDissolve   //转场,交叉消失和出现
 UIViewAnimationOptionTransitionFlipFromTop     //转场,从上向下旋转翻页
 UIViewAnimationOptionTransitionFlipFromBottom  //转场,从下向上旋转翻页

下面我们还是先看一下示例代码。

- (void)demoBlockUIViewAnimation
{
    self.animationView.frame = CGRectMake(50.0, 250.0, 200.0, 200.0);
    
    [UIView animateWithDuration:3.0 animations:^{
        self.animationView.backgroundColor = [UIColor blueColor];
    } completion:^(BOOL finished) {
        NSLog(@"动画完成了");
    }];
}

上面就是一个很简单的示例,非常简单,下面看一下效果。

3. 转场动画

下面直接看代码。

- (void)demoTransitionUIViewAnimation
{
    self.animationView.frame = CGRectMake(50.0, 250.0, 200.0, 200.0);

    [UIView beginAnimations:@"Animation" context:nil];
    [UIView setAnimationDuration:3.0];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationWillStartSelector:@selector(startAnimation)];
    [UIView setAnimationDidStopSelector:@selector(stopAnimation)];
    [UIView setAnimationRepeatCount:5];
    [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
    [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.animationView cache:YES];
    self.animationView.backgroundColor = [UIColor blueColor];
    [UIView commitAnimations];
}

转场动画有个参数cache,可以设置为YES或者NO,它们有什么区别呢?

首先把要动画的视图进行截图(此处为何要截图说明一下,因为要动画的视图上边一般都会有好多的控件,如果让动画直接操作视图,那么视图带着自身内部的控件,这样做动画的话会增加系统的负担,从而使动画效率降低,所以为了减轻系统负担,使动画更流畅,才对动画视图进行截图处理已完成动画效果),然后对视图的截图进行动画操作。

  • cache选为YES时:系统只会在动画开始的时候对视图进行截图,然后一直到动画结束,都用开始截的那张图,这种方法好处是减轻系统负担,使动画效果更流畅、更自然。但这样也必会有缺点:就是当动画视图中的控件有变化的时候,不能立即更新在视图上,从而达不到实时更新的效果。

  • cache选为NO时:系统会在动画整个过程中对视图进行实时截图,这样当视图中的控件更新时也会实时显示在动画过程中,弥补了cache选择yes得缺点,但这也把cache选择yes的优点变成缺点,是系统效率变慢,如果动画视图中的控件过多,会让动画看起来不那么自然。

这里还要注意:如果要在转换期间更改视图的外观 - 例如,从一个视图翻转到另一个视图 - 然后使用容器视图(UIView的实例),如下所示:

  • Begin an animation block.
  • Set the transition on the container view.
  • Remove the subview from the container view.
  • Add the new subview to the container view.
  • Commit the animation block.

iOS 4.0及更高版本不鼓励使用此方法。 您应该使用transition(with:duration:options:animations:completion:)
方法来执行转换。

后记

未完,待续~~~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容