贝塞尔曲线iOS动画

1. iOS动画

总的来说,从涉及类的形式来看,iOS动画有:基于UIView的仿射形变动画,基于CAAnimation及其子类的动画,基于CG的动画。这篇文章着重总结前两种动画。

2. UIView动画

设置UIView形变动画有两种常见用到的属性,.frame,.transform,所以有的人也可以分别称之为:

① frame动画

② transform动画

这两种动画只需要在动画语法中适当的位置,基于UIView和CALayer的属性设置变化值即可。这种动画,不需要调用核心动画CAAnimation里面的专用类和API。

其中,frame动画设置方式有限,必须确切地制定形变前后的frame,平移还好,特别是旋转的时候,只能通过数学知识计算出新的frame。这就得不偿失了。所以,更多的时候,当涉及一些frame,bounds,center的改变或是形变的时候可以用transform来取代frame

2.1 设置UIView动画的两种语法形式

begin --- commit

//偏移动画[UIView beginAnimations:@"move"context:nil];[UIView setAnimationDuration:2];[UIView setAnimationDelegate:self];imageContainView.frame=CGRectMake(80,80,200,200);[label1 setBackgroundColor:[UIColor yellowColor]];[label1 setTextColor:[UIColor redColor]];[UIView commitAnimations];

animations block

//缩放动画view.transform=CGAffineTransformIdentity;[UIView animateWithDuration:1.0fanimations:^{view.transform=CGAffineTransformMakeScale(2.0f,2.0f);}];

2.2 设置属性形变动画的两种类型

UIView的CGAffineTransform类型属性:animatedView.transform一般是View的旋转,拉伸移动等属性,是二维的,通常使用都是前缀CGAffineTransform的类。

CGAffineTransform transform=CGAffineTransformScale(imageContainView.transform,1.2,1.2);[UIView beginAnimations:@"scale"context:nil];[UIView setAnimationDuration:2];[UIView setAnimationDelegate:self];[imageView setTransform:transform];[UIView commitAnimations];

CALayer的CATransform3D类型属性:animaView.layer.transform通过.layer.transform可以在3D模式下面的变化,通常使用的都是前缀为CATransform3D的类。

imageView.layer.transform=CATransform3DIdentity;[UIView animateWithDuration:1.0fanimations:^{imageView.layer.transform=CATransform3DMakeScale(2.0,2.0,1.0);}];

2.3 与动画相关的属性

2.3.1 UIView与动画相关的属性--与CGAffineTransform对应

下面是UIView的一些属性介绍

@property(nonatomic)CGRect            frame;@property(nonatomic)CGRect            bounds;// default bounds is zero origin, frame size. animatable@property(nonatomic)CGPoint          center;// center is center of frame. animatable@property(nonatomic)CGAffineTransform transform;// default is CGAffineTransformIdentity. animatable@property(nonatomic)CGFloat          contentScaleFactorNS_AVAILABLE_IOS(4_0);@property(nonatomic,getter=isMultipleTouchEnabled)BOOL multipleTouchEnabled __TVOS_PROHIBITED;// default is NO@property(nonatomic,getter=isExclusiveTouch)BOOL      exclusiveTouch __TVOS_PROHIBITED;// default is NO

在实际开发中,使用场景:

(1) 当涉及一些frame, bounds, center的改变或是形变的时候可以用transform来取代 frame。

(2) 一般在实际开发中都是平移,旋转,缩放组合使用。

2.3.2 CALayer与动画相关的属性--与CATransform3D对应

下面是CALayer的一些属性介绍

//宽度和高度@propertyCGRect bounds;//位置(默认指中点,具体由anchorPoint决定)@propertyCGPoint position;//锚点(x,y的范围都是0-1),决定了position的含义@propertyCGPoint anchorPoint;//背景颜色(CGColorRef类型)@propertyCGColorRef backgroundColor;//形变属性@propertyCATransform3D transform;//边框颜色(CGColorRef类型)@propertyCGColorRef  borderColor;//边框宽度@propertyCGFloat borderWidth;//圆角半径@propertyCGFloat cornerRadius;//内容(比如设置为图片CGImageRef)@property(retain)id contents;

2.4 管理二维形变和三维形变的封装类:CGAffineTransform与CATransform3D

2.4.1 CGAffineTransform操作API

CGAffineTransform结构体定义

structCGAffineTransform{CGFloat a,b,c,d;CGFloat tx,ty;};

它其实表示的是一个矩阵:

image

因为最后一列总是是(0,0,1),所以有用的信息就是前面两列。对一个view进行仿射变化就相当于对view上的每个点做一个乘法,结果就是:

image

a表示x水平方向的缩放,tx表示x水平方向的偏移 d表示y垂直方向的缩放,ty表示y垂直方向的偏移 如果b和c不为零的话,那么视图肯定发生了旋转,旋转角度这样计算:tan(angle) = b / a

如果这样:

image

这个就是没有变化的最初的样子。

CGAffineTransform操作API

//还原CGAffineTransformIdentity//位移仿射  ---- 理解为平移 (CGFloat tx,CGFloat ty) CGAffineTransformMakeTranslation CGAffineTransformTranslate//旋转仿射 ---- 理解为旋转 (CGFloat angle)CGAffineTransformMakeRotationCGAffineTransformRotate//缩放仿射  --- 理解缩放大小 (CGFloat sx, CGFloat sy)CGAffineTransformMakeScale CGAffineTransformScale

CGAffineTransform操作的数学本质

CGPoint转换公式

image

矩阵乘法运算原理演示

image

2.4.2 CATransform3D操作API

//还原CATransform3DIdentity//位移3D仿射  ==> (CGFloat tx, CGFloat ty, CGFloat tz)CATransform3DMakeTranslationCATransform3DTranslation//旋转3D仿射 ==> (CGFloat angle, CGFloat x, CGFloat y, CGFloat z)CATransform3DMakeRotationCATransform3DRotation//缩放3D仿射 ==>  (CGFloat angle, CGFloat x, CGFloat y, CGFloat z)CATransform3DMakeScaleCATransform3DScale//叠加3D仿射效果CATransform3DConcat//仿射基础3D方法,可以直接做效果叠加CGAffineTransformMake(sx,shx,shy,sy,tx,ty)//检查是否有做过仿射3D效果  == ((CATransform3D t))CATransform3DIsIdentity(transform)//检查2个3D仿射效果是否相同CATransform3DEqualToTransform(transform1,transform2)//3D仿射效果反转(反效果,比如原来扩大,就变成缩小)CATransform3DInvert(transform)

2.4.3 CATransform3D与CGAffineTransform相互转换API

//将一个CGAffinrTransform转化为CATransform3DCATransform3D CATransform3DMakeAffineTransform(CGAffineTransform m);//判断一个CATransform3D是否可以转换为CAAffineTransformbool CATransform3DIsAffine(CATransform3D t);//将CATransform3D转换为CGAffineTransformCGAffineTransform CATransform3DGetAffineTransform(CATransform3D t);

2.5 “组合动画” 与 CGAffineTransformConcat

2.5.1 连接设置多个属性组合成一个动画

连接设置两个以上属性的动画,可以先调用含有formMake的API,然后再调用只含form的API。例如,这样:

alertView.transform=CGAffineTransformMakeScale(.25,.25);alertView.transform=CGAffineTransformTranslate(alertView.transform,0,600);

2.5.2 利用CGAffineTransformConcat设置组合动画

另外,可以直接利用CGAffineTransformConcat来组合多种含有formMake的形变API。

CGAffineTransform viewTransform=CGAffineTransformConcat(CGAffineTransformMakeScale(.25,.25),CGAffineTransformMakeTranslation(0,600));alertView.transform=viewTransform;

关于组合3D形变也有相应的API ---CATransform3DConcat,关于3D形变下一篇会专门介绍。

CGAffineTransformConcat组合多种形变动画小例子

-(void)viewDidAppear:(BOOL)animated{///  初始化动画开始前label的位置CGFloat offset=label1.frame.size.height*0.5;label1.transform=CGAffineTransformConcat(CGAffineTransformMakeScale(0,0),CGAffineTransformTranslate(0,-offset));label1.alpha=0;[UIView animateWithDuration:3\.animations:^{///  还原label1的变换状态并形变和偏移label2label1.transform=CGAffineTransformIdentifier;label1.transform=CGAffineTransformConcat(CGAffineTransformMakeScale(0,0),CGAffineTransformTranslate(0,offset));label1.alpha=1;label2.alpha=0;}];}

组合变换的本质 CGAffineTransformConcat的数学本质是将括号内代表的若干变换的系数矩阵进行相乘。

另一种组合变换 基于已有的CGAffineTransform连续追加新的CGAffineTransform:

CGAffineTransform transform=CGAffineTransformIdentity;transform=CGAffineTransformScale(transform,0.5f,0.5f);transform=CGAffineTransformRotate(transform,30.0f/180.0f*M_PI);transform=CGAffineTransformTranslate(transform,200.0f,0.0f);layerView.layer.affineTransform=transform;

2.6 动画后将属性还原

当我们改变过一个view.transform属性或者view.layer.transform的时候需要恢复默认状态的话,记得先把他 们重置为:

view.transform=CGAffineTransformIdentity;view.layer.transform=CATransform3DIdentity;

2.7 注意点: transform对frame的影响

官方文档上关于transform属性的说明:

Changes to this property can be animated. However, if the transform property contains a non-identity transform, the value of the frame property is undefined and should not be modified. In that case, you can reposition the view using the center property and adjust the size using the bounds property instead.

如果在程序中改变了某个控件的transform,那么请不要使用这个控件的frame计算子控件的布局,应该使用bounds+center代替。

3. CAAnimation核心动画

CAAnimation——所有动画对象的父类

3.1 设置动画的一种语法形式

addAnimation

/**

*  抖动效果

*/-(void)shakeAnimation{CAKeyframeAnimation*anima=[CAKeyframeAnimation animationWithKeyPath:@"transform.rotation"];//在这里@"transform.rotation"==@"transform.rotation.z"NSValue*value1=[NSNumber numberWithFloat:-M_PI/180*4];NSValue*value2=[NSNumber numberWithFloat:M_PI/180*4];NSValue*value3=[NSNumber numberWithFloat:-M_PI/180*4];anima.values=@[value1,value2,value3];anima.repeatCount=MAXFLOAT;[_demoView.layer addAnimation:anima forKey:@"shakeAnimation"];}

3.2 CAAnimation继承结构

CAAnimation{CAPropertyAnimation{CABasicAnimation{CASpringAnimation}CAKeyframeAnimation}CATransition        CAAnimationGroup}

是所有动画对象的父类,负责控制动画的持续时间和速度,是个抽象类,不能直接使用,应该使用它具体的子类

3.3 CAAnimation类的属性

带*号代表来自CAMediaTiming协议的属性)

*duration:动画的持续时间

*repeatCount:重复次数,无限循环可以设置HUGE_VALF或者MAXFLOAT

*repeatDuration:重复时间

removedOnCompletion:默认为YES,代表动画执行完毕后就从图层上移除,图形会恢复到动画执行前的状态。如果想让图层保持显示动画执行后的状态,那就设置为NO,不过还要设置fillMode为kCAFillModeForwards

*fillMode:决定当前对象在非active时间段的行为。比如动画开始之前或者动画结束之后

*beginTime:可以用来设置动画延迟执行时间,若想延迟2s,就设置为CACurrentMediaTime()+2,CACurrentMediaTime()为图层的当前时间

timingFunction:速度控制函数,控制动画运行的节奏

delegate:动画代理

3.4 几个重要属性值

removedOnCompletion属性值

CAAnimation——动画填充模式

默认为YES,代表动画执行完毕后就从图层上移除,图形会恢复到动画执行前的状态。如果想让图层保持显示动画执行后的状态,那就设置为NO,不过还要设置fillMode为kCAFillModeForwards

fillMode属性值

CAAnimation——控制恢复到动画执行前

要想fillMode有效,最好设置removedOnCompletion = NO

kCAFillModeRemoved 这个是默认值,也就是说当动画开始前和动画结束后,动画对layer都没有影响,动画结束后,layer会恢复到之前的状态

kCAFillModeForwards 当动画结束后,layer会一直保持着动画最后的状态

kCAFillModeBackwards 在动画开始前,只需要将动画加入了一个layer,layer便立即进入动画的初始状态并等待动画开始。

kCAFillModeBoth 这个其实就是上面两个的合成.动画加入后开始之前,layer便处于动画初始状态,动画结束后layer保持动画最后的状态

如果fillMode = kCAFillModeForwards同时removedOnComletion = NO,那么在动画执行完毕后,图层会保持显示动画执行后的状态。但在实质上,图层的属性值还是动画执行前的初始值,并没有真正被改变。

timingFunction属性值

CAAnimation——动画速度控制函数

kCAMediaTimingFunctionLinear(线性):匀速,给你一个相对静态的感觉

kCAMediaTimingFunctionEaseIn(渐进):动画缓慢进入,然后加速离开

kCAMediaTimingFunctionEaseOut(渐出):动画全速进入,然后减速的到达目的地

kCAMediaTimingFunctionEaseInEaseOut(渐进渐出):动画缓慢的进入,中间加速,然后减速的到达目的地。这个是默认的动画行为。

4. CABasicAnimation

基本动画,是CAPropertyAnimation的子类

4.1 特别属性说明:

keyPath: 要改变的属性名称(传字符串)

fromValue: keyPath相应属性的初始值

toValue: keyPath相应属性的结束值

4.2 keyPath可以是哪些值

CATransform3D{//rotation旋转transform.rotation.x    transform.rotation.y    transform.rotation.z//scale缩放transform.scale.x    transform.scale.y    transform.scale.z//translation平移transform.translation.x    transform.translation.y    transform.translation.z}CGPoint{position    position.x    position.y}CGRect{bounds    bounds.size    bounds.size.width    bounds.size.height    bounds.origin    bounds.origin.x    bounds.origin.y}property{opacity    backgroundColor    cornerRadius    borderWidth    contents    Shadow{shadowColor        shadowOffset        shadowOpacity        shadowRadius}}

4.3 举例

缩放动画 -- transform.scale

//心脏缩放动画CABasicAnimation*scaleAnimation=[CABasicAnimation animationWithKeyPath:@"transform.scale"];//选中的这个keyPath就是缩放scaleAnimation.fromValue=[NSNumber numberWithDouble:0.5];//一开始时是0.5的大小scaleAnimation.toValue=[NSNumber numberWithDouble:1.5];//结束时是1.5的大小scaleAnimation.duration=1;//设置时间scaleAnimation.repeatCount=MAXFLOAT;//重复次数[_heartImageView.layer addAnimation:scaleAnimation forKey:@"CQScale"];//添加动画

旋转动画 -- transform.rotation.z

//风车旋转动画CABasicAnimation*rotationAnimation=[CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];rotationAnimation.fromValue=[NSNumber numberWithDouble:0.f];rotationAnimation.toValue=[NSNumber numberWithDouble:2*M_PI];rotationAnimation.duration=2.f;rotationAnimation.repeatCount=MAXFLOAT;[_fengcheImageView.layer addAnimation:rotationAnimation forKey:@"CQRotation"];

平移动画 -- position.x/position.y

//平移动画CABasicAnimation*positionAnimation=[CABasicAnimation animationWithKeyPath:@"position.x"];positionAnimation.fromValue=[NSNumber numberWithDouble:0.f];positionAnimation.toValue=[NSNumber numberWithDouble:SCREEN_WIDTH];positionAnimation.duration=2;positionAnimation.repeatCount=MAXFLOAT;[_arrowImageView.layer addAnimation:positionAnimation forKey:@"CQPosition"];

5. CAKeyframeAnimation关键帧动画

5.1 参数数组形式

//根据values移动的动画CAKeyframeAnimation*catKeyAnimation=[CAKeyframeAnimation animationWithKeyPath:@"position"];CGPoint originalPoint=self.catImageView.layer.frame.origin;CGFloat distance=50;NSValue*value1=[NSValue valueWithCGPoint:CGPointMake(originalPoint.x+distance,originalPoint.y+distance)];NSValue*value2=[NSValue valueWithCGPoint:CGPointMake(originalPoint.x+2*distance,originalPoint.y+distance)];NSValue*value3=[NSValue valueWithCGPoint:CGPointMake(originalPoint.x+2*distance,originalPoint.y+2*distance)];NSValue*value4=[NSValue valueWithCGPoint:originalPoint];catKeyAnimation.values=@[value4,value1,value2,value3,value4];catKeyAnimation.duration=2;catKeyAnimation.repeatCount=MAXFLOAT;catKeyAnimation.removedOnCompletion=NO;[self.catImageView.layer addAnimation:catKeyAnimation forKey:nil];

5.2 path形式

//指定pathUIBezierPath*path=[UIBezierPath bezierPathWithOvalInRect:CGRectMake(0,200,200,200)];//指定path的动画UIBezierPath*path2=[UIBezierPath bezierPath];[path2 moveToPoint:CGPointMake(100,100)];[path2 addLineToPoint:CGPointMake(100,200)];[path2 addLineToPoint:CGPointMake(200,200)];[path2 addLineToPoint:CGPointMake(200,100)];[path2 addLineToPoint:CGPointMake(100,100)];CAKeyframeAnimation*penguinAnimation=[CAKeyframeAnimation animationWithKeyPath:@"position"];penguinAnimation.path=path2.CGPath;penguinAnimation.duration=2;penguinAnimation.repeatCount=MAXFLOAT;penguinAnimation.removedOnCompletion=NO;[self.penguinImageView.layer addAnimation:penguinAnimation forKey:nil];

6. 组动画

6.1 组动画

上面单一动画的情况在实际开发中实际比较少,更多的时候是组合这些动画:创建不同类型的动画对象,设置好它们的参数,然后把这些动画对象存进数组,传进组动画对象的animations属性中去。

6.2 示例

//创建组动画CAAnimationGroup*animationGroup=[CAAnimationGroup animation];animationGroup.duration=3;animationGroup.repeatCount=MAXFLOAT;animationGroup.removedOnCompletion=NO;/* beginTime 可以分别设置每个动画的beginTime来控制组动画中每个动画的触发时间,时间不能够超过动画的时间,默认都为0.f *///缩放动画CAKeyframeAnimation*animation1=[CAKeyframeAnimation animationWithKeyPath:@"transform.scale"];animation1.values=@[[NSNumber numberWithFloat:1.0],[NSNumber numberWithFloat:0.5],[NSNumber numberWithFloat:1.5],[NSNumber numberWithFloat:1.0]];animation1.beginTime=0.f;//按照圆弧移动动画CAKeyframeAnimation*animation2=[CAKeyframeAnimation animationWithKeyPath:@"position"];UIBezierPath*bezierPath=[UIBezierPath bezierPath];[bezierPath moveToPoint:CGPointMake(300,200)];[bezierPath addQuadCurveToPoint:CGPointMake(200,300)controlPoint:CGPointMake(300,300)];[bezierPath addQuadCurveToPoint:CGPointMake(100,200)controlPoint:CGPointMake(100,300)];[bezierPath addQuadCurveToPoint:CGPointMake(200,100)controlPoint:CGPointMake(100,100)];[bezierPath addQuadCurveToPoint:CGPointMake(300,200)controlPoint:CGPointMake(300,100)];animation2.path=bezierPath.CGPath;animation2.beginTime=0.f;//透明度动画CABasicAnimation*animation3=[CABasicAnimation animationWithKeyPath:@"opacity"];animation3.fromValue=[NSNumber numberWithDouble:0.0];animation3.toValue=[NSNumber numberWithDouble:1.0];animation3.beginTime=0.f;//添加组动画animationGroup.animations=@[animation1,animation2,animation3];[_penguinImageView.layer addAnimation:animationGroup forKey:nil];

7. 贝塞尔曲线

前面关键帧动画章节提到了贝塞尔曲线,这个曲线很有用,在iOS开发中有两种形式可用:CGMutablePathRef和UIBezierPath,均可以通过制定控制点数组的形式唯一确定曲线,也可以通过矩形内切椭圆唯一确定曲线。下面是两者的例子:

7.1 CGMutablePathRef

通过关键点曲线连接唯一确定

// 贝塞尔曲线关键帧// 设置路径, 绘制贝塞尔曲线CGMutablePathRef path=CGPathCreateMutable();CGPathMoveToPoint(path,NULL,200,200);// 起始点CGPathAddCurveToPoint(path,NULL,100,300,300,500,200,600);// CGPathAddCurveToPoint(path, NULL, 控制点1.x, 控制点1.y, 控制点2.x, 控制点2.y, 终点.x, 终点.y);// 设置path属性keyframeAnimation.path=path;CGPathRelease(path);// 设置其他属性keyframeAnimation.duration=4;keyframeAnimation.beginTime=CACurrentMediaTime()+1;// 设置延迟2秒执行, 不设置这个属性, 默认直接执行// 3\. 添加动画到图层, 会自动执行[_layer addAnimation:keyframeAnimation forKey:@"GGKeyframeAnimation"];

7.2 UIBezierPath

通过矩形内切椭圆唯一确定

CAKeyframeAnimation*anima=[CAKeyframeAnimation animationWithKeyPath:@"position"];UIBezierPath*path=[UIBezierPath bezierPathWithOvalInRect:CGRectMake(SCREEN_WIDTH/2-100,SCREEN_HEIGHT/2-100,200,200)];anima.path=path.CGPath;anima.duration=2.0f;[_demoView.layer addAnimation:anima forKey:@"pathAnimation"];

通过关键点直线连接唯一确定

-(void)pathAnimation2{//创建pathUIBezierPath*path=[UIBezierPath bezierPath];//设置线宽path.lineWidth=3;//线条拐角path.lineCapStyle=kCGLineCapRound;//终点处理path.lineJoinStyle=kCGLineJoinRound;//多条直线[path moveToPoint:(CGPoint){0,SCREEN_HEIGHT/2-50}];[path addLineToPoint:(CGPoint){SCREEN_WIDTH/3,SCREEN_HEIGHT/2-50}];[path addLineToPoint:(CGPoint){SCREEN_WIDTH/3,SCREEN_HEIGHT/2+50}];[path addLineToPoint:(CGPoint){SCREEN_WIDTH*2/3,SCREEN_HEIGHT/2+50}];[path addLineToPoint:(CGPoint){SCREEN_WIDTH*2/3,SCREEN_HEIGHT/2-50}];[path addLineToPoint:(CGPoint){SCREEN_WIDTH,SCREEN_HEIGHT/2-50}];//    [path closePath];CAKeyframeAnimation*anima=[CAKeyframeAnimation animationWithKeyPath:@"position"];anima.path=path.CGPath;anima.duration=2.0f;anima.fillMode=kCAFillModeForwards;anima.removedOnCompletion=NO;anima.timingFunction=[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];[_demoView.layer addAnimation:anima forKey:@"pathAnimation"];}

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

推荐阅读更多精彩内容