UIBezierPath的简单使用(画自定义图形、手写签名、画进度条、简单动效(气泡动效、加入购物车动效、水波纹动效、角标拖动消失动效))

目录

  • 前言(对UIBezierPath的介绍和描述)
  • 基础API (基础使用)
  • 手写签名 (项目中用过)
  • 简单动效
    1. 进度条动效(项目中用过)
    2. 冒泡泡动效(写来玩的,一般也没啥项目会用到)
    3. 加入购物车动效(可以看看,没准能用到)
    4. 水波纹动效(以前见过支付宝有这个效果)
    5. 角标拖动消失动效(仿QQ效果)

前言

(这一部分是装13的对UIBezierPath的介绍和描述,只想看用法的,可以跳过这部分或者直接下载demo查看。)

UIBezierPath位于UIKit框架中,它的核心是数学公式 -- 伯恩斯坦多项式,后来被法国数学家 Paul de Casteljau通过德卡斯特里奥(de Casteljau) 算法进行了图形化,再后来被法国工程师皮埃尔·贝塞尔(Pierre Bézier)用来辅助汽车的车体工业设计,并广为宣传,从而被大众熟知。

一阶贝塞尔曲线

1.png

二阶贝塞尔曲线

2.png

P0为起始点,P2为终点,P1为曲线弧度的控制点
二阶贝塞尔曲线动图.gif

三阶贝塞尔曲线

3.png

P0为起始点,P3为终点,P1和P2为曲线弧度的控制点


三阶贝塞尔曲线动图.gif

在 P0P1,P1P2,P2P3这三段线(灰色线)上 \color{red}{不断取等比划分点},连接之后形成线段(绿色线)上再取同样的等比划分点,连接之后形成线段(蓝色线)上取同样的等比划分点,然后连接P0,形成圆滑曲线(即最终的红色线)。

贝塞尔曲线可以有n阶,原理都是这样在形成的线段上不断取等比划分点形成曲线。
(n阶是使用若干个二阶和三阶拼凑出来的)


四阶贝塞尔曲线动图.gif

其实就可以想象一根弹性磁性线,固定两端,磁石牵引磁性线使之出现有弧度,磁石的位置就是控制点的位置,磁石可以有n个。

基础API

使用UIBezierPath一般是重写view的drawRect方法,在drawRect方法里创建图形,如果你是在UIViewController里面直接写,那么可以使用[self.view.layer addSublayer:shapeLayer]; 或者self.view.layer.mask = shapeLayer; 来显示。
区别在于addSublayer是直接在当前view上添加一个你绘制的图形,而self.view.layer.mask = shapeLayer;是对你的view进行遮罩。

+ (instancetype)bezierPath;
 //画矩形
 + (instancetype)bezierPathWithRect:(CGRect)rect;
 
 //画圆形或椭圆
 + (instancetype)bezierPathWithOvalInRect:(CGRect)rect;
 
 //画带圆角的矩形
 + (instancetype)bezierPathWithRoundedRect:(CGRect)rect cornerRadius:(CGFloat)cornerRadius; // rounds all corners with the same horizontal and vertical radius
 
 /*可以自定义绘制某个角,带圆角的矩形
    byRoundingCorners:设置需要圆角的角
    cornerRadii:圆角角度 最大角度也就是长宽中小的那个值,超过那个值,你设置再大也就是那样
 */
 + (instancetype)bezierPathWithRoundedRect:(CGRect)rect byRoundingCorners:(UIRectCorner)corners cornerRadii:(CGSize)cornerRadii;
 
 /*画弧线 
    center:圆心位置  
    radius:半径 
    startAngle:起始弧度 
    endAngle:结束弧度 
    clockwise:是否顺时针画圆
*/
 + (instancetype)bezierPathWithArcCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise;
 
 //根据CGPath创建并返回一个新的UIBezierPath对象
 + (instancetype)bezierPathWithCGPath:(CGPathRef)CGPath;

 - (instancetype)init NS_DESIGNATED_INITIALIZER;
 - (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;

 //将起始点移动到某个位置
 - (void)moveToPoint:(CGPoint)point;
 
 //添加一条线
 - (void)addLineToPoint:(CGPoint)point;
 
 //添加一条三阶贝塞尔曲线 controlPoint1、controlPoint2就是两个控制点的位置
 - (void)addCurveToPoint:(CGPoint)endPoint controlPoint1:(CGPoint)controlPoint1 controlPoint2:(CGPoint)controlPoint2;
 
 //添加一条二阶贝塞尔曲线
 - (void)addQuadCurveToPoint:(CGPoint)endPoint controlPoint:(CGPoint)controlPoint;
 
 //添加一条圆弧线  center:圆心位置  radius:半径 startAngle:起始弧度 endAngle:结束弧度 clockwise:是否顺时针画圆
 - (void)addArcWithCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise API_AVAILABLE(ios(4.0));
 
 //使用这个方法可以将起始点和终点连接起来,形成闭合路径,在画图的时候可以用这个方法来代替画最后一根闭合线,但注意是一条直线,如果要要画曲线,还是要手动画
 - (void)closePath;

 //移除所有点,即清屏
 - (void)removeAllPoints;

 //拼接一条线在当前线后面
 - (void)appendPath:(UIBezierPath *)bezierPath;

 //创建并返回一个与当前路径相反的新的贝塞尔路径对象
 - (UIBezierPath *)bezierPathByReversingPath API_AVAILABLE(ios(6.0));

 //用指定的仿射变换矩阵变换路径的所有点,即按照transform设置转换所有点之后重新形成一条新的路径
 - (void)applyTransform:(CGAffineTransform)transform;

 // Path info

 @property(readonly,getter=isEmpty) BOOL empty;
 @property(nonatomic,readonly) CGRect bounds;
 @property(nonatomic,readonly) CGPoint currentPoint;
 - (BOOL)containsPoint:(CGPoint)point;

 // Drawing properties

 @property(nonatomic) CGFloat lineWidth;
 @property(nonatomic) CGLineCap lineCapStyle;
 @property(nonatomic) CGLineJoin lineJoinStyle;
 //最大斜接长度   斜接长度指的是在两条线交汇处内角和外角之间的距离。 只有lineJoin属性为kCALineJoinMiter时miterLimit才有效; 边角的角度越小,斜接长度就会越大;如果斜接长度超过 miterLimit的值,边角会以 lineJoin的 "bevel"即kCALineJoinBevel类型来显示
 @property(nonatomic) CGFloat miterLimit; // Used when lineJoinStyle is kCGLineJoinMiter
 //确定弯曲路径短的绘制精度的因素
 @property(nonatomic) CGFloat flatness;
 
 //判断奇偶数组的规则绘制图像,图形复杂时填充颜色的一种规则。类似棋盘
 @property(nonatomic) BOOL usesEvenOddFillRule; // Default is NO. When YES, the even-odd fill rule is used for drawing, clipping, and hit testing.
//绘制虚线,dash数组存放各段虚线的长度(线长,空隙长,线长,空隙长这种排布),count是数组元素数量,phase是起始位置
 - (void)setLineDash:(nullable const CGFloat *)pattern count:(NSInteger)count phase:(CGFloat)phase;
//检索线型
 - (void)getLineDash:(nullable CGFloat *)pattern count:(nullable NSInteger *)count phase:(nullable CGFloat *)phase;

 // Path operations on the current graphics context

 - (void)fill;
 - (void)stroke;

 // These methods do not affect the blend mode or alpha of the current graphics context
//用指定的混合模式和透明度值来描绘受接收路径所包围的区域,内部填充
 - (void)fillWithBlendMode:(CGBlendMode)blendMode alpha:(CGFloat)alpha;
//用指定的混合模式和透明度值来描绘受接收路径所包围的区域,内部不填充
 - (void)strokeWithBlendMode:(CGBlendMode)blendMode alpha:(CGFloat)alpha;

 - (void)addClip;

其中绘制圆弧时的角度图如下:
圆的角度位置图.png

简单使用效果如下:
简单使用.png

手写签名

效果图如下:

手写签名.gif

\color{red}{核心}:获取手指触碰屏幕的点,连接那些点。
撤销功能:在绘制路径的时候,把每条路径存到一个数组里,当点击撤销的时候,把数组中的最后一条路径删除,重绘路径。
在demo中有两种绘制方法,本质一样,只是第二种是使用二阶贝塞尔曲线来绘制,这样绘制出来的路径更加圆滑。
(这里只贴第二种方法的核心代码,完整代码请前往demo查看)

//这个方法,是用二阶贝塞尔曲线来绘制圆滑的路径
-(void)pan:(UIPanGestureRecognizer *)pan{
    //获取当前点
    CGPoint currentPoint = [pan locationInView:self];
    CGPoint midPoint = [self getMidPoint:previousPoint withP2:currentPoint];
    if (pan.state == UIGestureRecognizerStateBegan) {
        //创建贝塞尔路径
        self.path = [UIBezierPath bezierPath];
        self.path.lineWidth = self.lineWidth;
        //设置路径的起点
         [self.path moveToPoint:currentPoint];
        //保存画出的路径
        [self.pathArray addObject:self.path];
    }
    if (pan.state == UIGestureRecognizerStateChanged) {
        //圆滑曲线连接到当前触摸点
        [self.path addQuadCurveToPoint:midPoint controlPoint:previousPoint];
    }
    previousPoint = currentPoint;
    //重绘
    [self setNeedsDisplay];

}

-(CGPoint)getMidPoint:(CGPoint)p1 withP2:(CGPoint)p2{
    
    return CGPointMake((p1.x + p2.x)/2, (p1.y + p2.y)/2);
}

画进度条

效果图如下:

进度条.gif

这里只做圆形的展示,直线的进度条就是把画圆路径换成画直线而已。
\color{red}{核心}:画两段圆弧,一段作为基底,一段为进度条。用strokeEnd来设置进度条的比例。
如果需要渐变色,可以使用CAGradientLayer来设置颜色。

简单动效

贝塞尔曲线的动效可以跟定时器,UIViewAnimation,帧动画等等结合在一起,因为贝塞尔曲线的可塑性很强,适当结合可以做出多样的动画。

进度条动效

之前有个项目做过根据数据实时变化进度显示,就是使用上面的画进度条方法加上数据实时推送来实现,demo中采用定时器来实现实时变化效果:
简单动效1.gif

冒泡泡动效

\color{red}{核心}:用贝塞尔曲线确定运动路径,使用CAKeyframeAnimation帧动画来实现动效。

冒泡泡动效.png
冒泡泡动效.gif

    //泡泡球
    UIView * bubbleView = [[UIView alloc] initWithFrame:CGRectMake(100, 400, 50, 50)];
    bubbleView.backgroundColor = [UIColor colorWithHexString:@"#E61717" alpha:0.4];
    bubbleView.clipsToBounds = YES;
    bubbleView.layer.cornerRadius = 25;
    [self.view addSubview:bubbleView];
    
    //创建运动轨迹
    UIBezierPath * path = [UIBezierPath bezierPath];
    [path moveToPoint:CGPointMake(125, 425)];
    [path addCurveToPoint:CGPointMake(50, 150) controlPoint1:CGPointMake(30, 300) controlPoint2:CGPointMake(175, 195)];
    [path stroke];
    CAShapeLayer * layer = [[CAShapeLayer alloc] init];
    layer.path = path.CGPath;
    layer.strokeColor = [UIColor blueColor].CGColor;
    layer.fillColor = [UIColor clearColor].CGColor;
    layer.lineWidth = 3;
    [self.view.layer addSublayer:layer];
   
    //帧动画
    CAKeyframeAnimation * keyFrameAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    [keyFrameAnimation setDuration:2];
    keyFrameAnimation.path = path.CGPath;
    //设置为NO,则在动画结束后停在终点,YES则会回到原点
    keyFrameAnimation.removedOnCompletion = YES;
    keyFrameAnimation.fillMode = kCAFillModeForwards;
    //重复次数
//    keyFrameAnimation.repeatCount = MAXFLOAT;
    //添加动画
    [bubbleView.layer addAnimation:keyFrameAnimation forKey:@"movingAnimation"];

加上随机数生成,结束时泡泡炸开等效果,就可以做出好看的冒泡泡动效了:
泡泡.gif

加入购物车动效

在上面的基础上再加些旋转,缩放就可以做出加入购物车的动效:
加入购物车.gif

水波纹动效

\color{red}{核心}:根据公式y = Asin(ωx+φ)+h 得到n个点,用贝塞尔曲线将这些点连接起来,形成一条波浪线,然后用CADisplayLink 不断改变x的值,来使曲线动起来,形成波浪的感觉。
k是改变高度,
ω是改变波浪往前偏移的位置,
φ是改变速度,
A是改变波浪的幅度。

水波纹动效.gif

关键代码:

- (void)drawRect:(CGRect)rect{
    /*
     想有几条波浪就创建几条曲线,
     更改kappa(k)是改变高度,
     更改omega(ω)是改变波浪往前偏移的位置,
     更改phi(φ)是改变速度,
     更改alpha(A)是改变波浪的幅度
     */
    [self drawWaveWithColor:[UIColor colorWithHexString:@"#108EE8" alpha:1] withOmega:self.omega withPhi:self.phi withKappa:self.kappa];
    [self drawWaveWithColor:[UIColor colorWithHexString:@"#108EE8" alpha:0.4] withOmega:self.omega * 1.5 withPhi:self.phi withKappa:self.kappa];
}
-(void)drawWaveWithColor:(UIColor *)color withOmega:(CGFloat)omega withPhi:(CGFloat)phi withKappa:(CGFloat)kappa{
    [color set];
    UIBezierPath * path = [UIBezierPath bezierPath];
    [path moveToPoint:CGPointMake(0, self.bounds.size.height)];
    //正弦曲线公式为:y=Asin(ωx+φ)+k;
    for (CGFloat x = 0.0f; x <= self.bounds.size.width; x++) {
        CGFloat y = self.alpha * sinf(omega * x + phi) + kappa;
        [path addLineToPoint:CGPointMake(x, y)];
    }
    [path addLineToPoint:CGPointMake(self.bounds.size.width, self.bounds.size.height)];
    [path fill];
}

角标拖动消失动效

\color{red}{核心}:5个关键点的确定。
\color{red}{注意}LSBadgeViewxib和手写代码均可调用,但是xib调用时,约束要用相对于view,而不是safeArea,或者你在LSBadgeView.m中自己手动去修改center的赋值,将safeArea距离加上也可以。

坐标数学解析.png

核心代码:

-(void)getPoint{
    
    //获取半径,根据拖动距离,缩小小圆半径
    CGFloat rate = self.currentDistance / self.maxDistance > 1 ? 0 : 1 - (self.currentDistance / self.maxDistance);
    self.beginR = self.currentR * rate;
    
    //计算φ
    CGFloat M = (self.currentPoint.x - self.beginPoint.x) / (self.currentPoint.y - self.beginPoint.y);
    CGFloat angle = atanf(M);
    
    //计算A
    CGFloat Ax = self.beginPoint.x - cosf(angle) * self.beginR;
    CGFloat Ay = self.beginPoint.y + self.beginR * sinf(angle);
    self.pointA = CGPointMake(Ax, Ay);
   
    //计算B
    CGFloat Bx = self.beginPoint.x + cosf(angle) * self.beginR;
    CGFloat By = self.beginPoint.y - self.beginR * sinf(angle);
    self.pointB = CGPointMake(Bx, By);
    
    //计算C
    CGFloat Cx = self.currentPoint.x - cosf(angle) * self.currentR;
    CGFloat Cy = self.currentR * sinf(angle) + self.currentPoint.y;
    self.pointC = CGPointMake(Cx, Cy);
    
    //计算D
    CGFloat Dx = self.currentPoint.x + cosf(angle) * self.currentR;
    CGFloat Dy = self.currentPoint.y - self.currentR * sinf(angle);
    self.pointD = CGPointMake(Dx, Dy);
    
    //计算O
    CGFloat Ox = self.beginPoint.x + (self.currentPoint.x - self.beginPoint.x) / 2;
    CGFloat Oy = self.beginPoint.y + (self.currentPoint.y - self.beginPoint.y) / 2;
    self.pointO = CGPointMake(Ox, Oy);
}

-(void)drawPath{
    
    UIBezierPath * path3 = [UIBezierPath bezierPath];
    //小圆
    [path3 addArcWithCenter:self.beginPoint radius:self.beginR startAngle:0 endAngle:360 clockwise:YES];
    //两条圆弧  按照A -> B -> D -> C -> A 画图
    [path3 moveToPoint:self.pointA];
    [path3 addLineToPoint:self.pointB];
    [path3 addQuadCurveToPoint:self.pointD controlPoint:self.pointO];
    [path3 addLineToPoint:self.pointC];
    [path3 addQuadCurveToPoint:self.pointA controlPoint:self.pointO];
    
    self.pathLayer.path = path3.CGPath;
}

效果图:
角标消失动效.gif
另外

demo中r取的是角标view宽高中的较小值,
圆角矩形角标.png

如果你对demo圆角矩形时候的粘性路径不满意,可以自己去重新计算修改C、D的值,使其落在圆角矩形的边上。

\color{red}{关于帧动画的一些小点:}

  1. fillMode
    kCAFillModeForwards:动画结束后,layer处于动画结束时的状态。
    kCAFillModeBackwards:动画开始前,layer处于动画开始时的状态。
    kCAFillModeBoth:动画开始前,layer处于动画开始时的状态;动画结束后,layer处于动画结束时的状态。
    kCAFillModeRemoved:默认模式,动画开始前和结束后,动画对layer的状态没有影响。也就是说,动画开始前和结束后,layer都会处于添加动画前的状态,即在原点的位置。

注意:kCAFillModeRemoved 和 kCAFillModeBackwards 模式下,removedOnCompletion不管设置为YES还是NO,都会回到原始状态,kCAFillModeForwards 和 kCAFillModeBoth 模式下,removedOnCompletion的设置才有效。

  1. timingFunctions:动画的进场和出场效果
    kCAMediaTimingFunctionLinear(线性):匀速;
    kCAMediaTimingFunctionEaseIn(渐进):动画缓慢进入,然后加速离开;
    kCAMediaTimingFunctionEaseOut(渐出):动画全速进入,然后减速的到达目的地;
    kCAMediaTimingFunctionEaseInEaseOut(渐进渐出):动画缓慢的进入,中间加速,然后减速的到达目的地;
    kCAMediaTimingFunctionDefault (默认时间函数)。

  2. keyTimesvalues:
    keyTimes 给对应帧设置时间,值为0~1(表示的是进行到当前帧时所耗时间占\color{red}{总时间的百分比}),不设置表示匀速完成动画;
    (如: @[@(0), @(0.2), @(0.5), @(1)]; 假设总时间为10s,那么到达p1,用时2s(即0.2),到达p2,用时3s(加起来是0.5),到达p3,用时5s,完成一遍完整动画)

    帧动画keyTimes.png

values 是帧数组。
keyTimes 和 values 联合起来用,但是需要注意,如果你设置了keyFrameAnimation.path,那么这俩就不奏效(其实就是帧动画的两种实现方式,一种是Path实现,一种是Value方式实现)

    //帧动画
    CAKeyframeAnimation * keyFrameAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    [keyFrameAnimation setDuration:10];
    //设置为NO,则在动画结束后停在终点,YES则会回到原点
    keyFrameAnimation.removedOnCompletion = YES;
    keyFrameAnimation.fillMode = kCAFillModeForwards;
    //重复次数
    keyFrameAnimation.repeatCount = MAXFLOAT;
    NSValue * p1 = [NSValue valueWithCGPoint:CGPointMake(50, 120)];
    NSValue * p2 = [NSValue valueWithCGPoint:CGPointMake(50, 200)];
    NSValue * p3 = [NSValue valueWithCGPoint:CGPointMake(150, 150)];
    keyFrameAnimation.values = @[p1, p2, p3];
    keyFrameAnimation.keyTimes = @[@(0.1),@(0.8),@(1)];
    keyFrameAnimation.autoreverses = YES;
    [bubbleView.layer addAnimation:keyFrameAnimation forKey:@"movingAnimation"];
  1. rotationMode:主体沿路径切线方向,即如果你是方块绕不规则路径运动,那么那个方块会根据路径方向自动适当旋转,可以想象小车爬山游戏。默认值是nil。
    kCAAnimationRotateAuto:沿切线自动旋转;
    kCAAnimationRotateAutoReverse:翻转180°后沿切线自动旋转运动。

  2. 停止帧动画

if ([bubbleView.layer animationForKey:@"movingAnimation"]) {//如果动画进行中
        [bubbleView.layer removeAnimationForKey:@"movingAnimation"];//停止动画
    }
  1. 帧动画代理方法:<CAAnimationDelegate>
keyFrameAnimation.delegate = self;
//动画结束
-(void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{
    
}
//动画开始
-(void)animationDidStart:(CAAnimation *)anim{
    
}
  1. animationWithKeyPath的常用属性
//路径动画
CAKeyframeAnimation * pathAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
//旋转动画
CABasicAnimation * rotateAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];

1)position 位置变化(运动路径动画)
2)transform.scale 缩放比例
transform.scale.x 缩放宽的比例
transform.scale.y 缩放高的比例
3)transform.rotation 旋转
transform.rotation.x 围绕x轴旋转
transform.rotation.y 围绕y轴旋转
transform.rotation.z 围绕z轴旋转
4)opacity 透明度
5)cornerRadius 圆角的设置
6)backgroundColor 背景颜色的变化
7)bounds 大小变化,中心不变
8)contentsRect.size.width 横向拉伸缩放
9)shadowColor 阴影色
10)strokeEnd 绘制路径过程动画

总结

贝塞尔曲线的核心就是确定路径的关键点,如果路径的关键点自己算不出来,就找个数学好的朋友,让他/她帮你算吧......

demo地址:https://github.com/cherrys94/UIBezierPathDemo

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

推荐阅读更多精彩内容