iOS开发之自定义一个数据漏斗图

前言:
百度ECharts上有很多漂亮的图表,但是对于native应用并不太友好,今天记录一下用OC自定义一个漏斗图,实现数据动态加载,图表实时更新。

思路:
1.将漏斗图横向切割,假如有四组数据,就横向切割为四等分,每一个部分将由一个UIButton来实现,实际上就是将四个UIButton叠起来(本文记录的是四组数据,所以就以四组数据为例);
2.通过给定数据,计算每一个UIButton对应的四个点,重写UIButton的drawRect方法,利用UIBezierPath+CAShapeLayer绘制每个UIButton的实际大小跟形状;
3.利用CABasicAnimation添加一个绘制动画;
4.添加一个点击响应来显示每一组数据;

整体预览
如下图所示,每一个四边形(最后一个是三角形)都是根据给定数据动态绘制出来的:

funnel.gif

实现步骤
1.首先重写UIButton的drawRect方法,实现一个根据给定四个点动态创建一个UIButton:
.h文件添加一个pointArray

#import <UIKit/UIKit.h>


NS_ASSUME_NONNULL_BEGIN

@interface FHXCustomButton : UIButton

@property (nonatomic, strong) NSMutableArray *pointArray;

@end

NS_ASSUME_NONNULL_END

.m文件实现重写drawRect

#import "FHXCustomButton.h"


@interface FHXCustomButton()

@property (nonatomic, strong) UIBezierPath * path;

@end
@implementation FHXCustomButton

// pointArray
- (void)setPointArray:(NSMutableArray *)pointArray
{
    _pointArray = pointArray;
}

// 绘制图形时添加path遮罩
- (void)drawRect:(CGRect)rect
{
    [super drawRect:rect];
    
    CAShapeLayer *shapLayer = [CAShapeLayer layer];
    shapLayer.fillColor = [UIColor redColor].CGColor;
    self.layer.mask = shapLayer;
    
    //获取四个点
    CGPoint point0 = CGPointFromString(_pointArray[0]);
    CGPoint point1 = CGPointFromString(_pointArray[1]);
    CGPoint point2 = CGPointFromString(_pointArray[2]);
    CGPoint point3 = CGPointFromString(_pointArray[3]);
    
    //构造fromPath
    UIBezierPath * fromPath = [UIBezierPath bezierPath];
    [fromPath moveToPoint:point0];
    [fromPath addLineToPoint:point0];//起始的path也必须是一个矩形,不然动画效果会有区别
    [fromPath addLineToPoint:point1];
    [fromPath addLineToPoint:point1];//同上
    shapLayer.path = fromPath.CGPath;
    
    //构造toPath(最终图形样式)
    UIBezierPath * toPath = [UIBezierPath bezierPath];
    [toPath moveToPoint:point0];
    [toPath addLineToPoint:point3];
    [toPath addLineToPoint:point2];
    [toPath addLineToPoint:point1];
    [toPath closePath];
    
    // 构造动画
    CABasicAnimation * animation = [CABasicAnimation animation];
    animation.keyPath = @"path";
    animation.duration = 1;
    animation.fromValue = (id)fromPath.CGPath;
    shapLayer.path = (__bridge CGPathRef _Nullable)((id)toPath.CGPath);
    [shapLayer addAnimation:animation forKey:nil];
}
// 点击的覆盖方法,点击时判断点是否在path内,YES则响应,NO则不响应
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
    BOOL res = [super pointInside:point withEvent:event];
    if (res)
    {
        if ([self.path containsPoint:point])
        {
            return YES;
        }
        return NO;
    }
    return NO;
}
@end

动态绘制UIButton效果如下图:


customButton.gif

本文是以四组数据为例,所以只需要创建四个上述button,即可实现一个数据漏斗图。

2.利用上述customButton,实现一个数据漏斗图,新建一个view继承UIView:
.文件

#import <UIKit/UIKit.h>
#import "FHXCustomButton.h"
#import "FHXFunnelModel.h"
#import "FHXChartNoDataView.h"

#define SCREEN_WIDTH ([UIScreen mainScreen].bounds.size.width)
#define kViewWidth(View) CGRectGetWidth(View.frame)
#define kViewHeight(View) CGRectGetHeight(View.frame)
#define kMidHeight 3.0f

NS_ASSUME_NONNULL_BEGIN

@interface FHXFunnelView : UIView

/*标题*/
@property(nonatomic,strong)NSString * title;
/*小标题*/
@property(nonatomic,strong)NSMutableArray * desArray;
/*数据*/
@property(nonatomic,strong)FHXFunnelModel * funnelModel;

/*点击展示文案*/
@property(nonatomic,strong)UIButton * showButton;
/*无数据*/
@property(nonatomic,strong)FHXChartNoDataView * noDataView;
@end

NS_ASSUME_NONNULL_END

.m文件里创建四个FHXCustomButton,从上到下一次排开,并在y轴(数值方向)对齐,通过传入的四组数据计算每一个button的位置,这里是将四个button的高度固定为60,第一个button的上边宽固定,下边宽由前两个数据的比例来计算(类似于一个等腰梯形),依次类推,最后一Button将会被绘制成一个等腰三角形,具体实现代码如下

#import "FHXFunnelView.h"
#import "Masonry.h"
#import "UIColor+Extensions.h"
#import "UIButton+HXEnlargeTouchArea.h"
@implementation FHXFunnelView{
    FHXCustomButton * firstBtn;
    FHXCustomButton * secondBtn;
    FHXCustomButton * thirdBtn;
    FHXCustomButton * fourthBtn;
    UILabel * titleLabel;
    CGFloat registerCount;
    CGFloat openCount;
    CGFloat lendCount;
    CGFloat repeatCount;
    NSMutableArray * labelArray;
    NSMutableArray * imageViewArray;
}
//添加漏斗数据
-(void)setFunnelModel:(FHXFunnelModel *)funnelModel{   
    //刷新数据隐藏显示button
    self.showButton.hidden = YES;
    if (funnelModel == nil) {
        //暂无数据
        self.noDataView.hidden = NO;
        return;
    }else{
        self.noDataView.hidden = YES;
    }
    _funnelModel = funnelModel;
    //数据整化
    registerCount = _funnelModel.firstItemNum.floatValue;
    openCount = _funnelModel.secondItemNum.floatValue;
    lendCount = _funnelModel.thirdItemNum.floatValue;
    repeatCount = _funnelModel.fourthItemNum.floatValue;
    
    //处理数据为0的情况
    if (registerCount == 0) {
        //暂无数据
        self.noDataView.hidden = NO;
        return;
    }else{
        self.noDataView.hidden = YES;
    }
    
    if (openCount == 0) {
        openCount = 1;
        lendCount = 1;
        repeatCount = 1;
    }
    if (lendCount == 0) {
        lendCount = 1;
        repeatCount = 1;
    }
    if (repeatCount == 0) {
        repeatCount = 1;
    }
    
    //注册
    firstBtn.frame = CGRectMake(32, 62, SCREEN_WIDTH - 32*2, 60);
    CGFloat baseProportion1 = openCount/registerCount;
    CGFloat leftProportion1 = (1 - baseProportion1)/2.0f;
    CGFloat rightProportion1 = 1 - leftProportion1;
    // 添加路径关键点array
    NSMutableArray *pointArray = [NSMutableArray array];
    [pointArray addObject:NSStringFromCGPoint(CGPointMake(0.f, 0.f))];
    [pointArray addObject:NSStringFromCGPoint(CGPointMake(kViewWidth(firstBtn), 0.f))];
    [pointArray addObject:NSStringFromCGPoint(CGPointMake(kViewWidth(firstBtn) *rightProportion1, firstBtn.frame.size.height))];
    [pointArray addObject:NSStringFromCGPoint(CGPointMake(kViewWidth(firstBtn) *leftProportion1, kViewHeight(firstBtn)))];
    firstBtn.pointArray = [pointArray mutableCopy];
    firstBtn.backgroundColor = [UIColor colorWithHex:0x4162ff];
    [firstBtn setNeedsDisplay];
    
    //开户
    secondBtn.frame = CGRectMake(32, 62 + 60, kViewWidth(firstBtn) *baseProportion1, 60);
    [secondBtn mas_remakeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(firstBtn.mas_bottom).with.offset(kMidHeight);
        make.centerX.equalTo(firstBtn);
        make.width.equalTo(@(kViewWidth(firstBtn) * baseProportion1));
        make.height.equalTo(@60.f);
    }];
    CGFloat baseProportion2 = lendCount/openCount;
    CGFloat leftProportion2 = (1 - baseProportion2)/2.0f;
    CGFloat rightProportion2 = 1 - leftProportion2;
    // 添加路径关键点array
    NSMutableArray *pointArray1 = [NSMutableArray array];
    [pointArray1 addObject:NSStringFromCGPoint(CGPointMake(0.f, 0.f))];
    [pointArray1 addObject:NSStringFromCGPoint(CGPointMake(kViewWidth(secondBtn), 0.f))];
    [pointArray1 addObject:NSStringFromCGPoint(CGPointMake(kViewWidth(secondBtn) *rightProportion2, secondBtn.frame.size.height))];
    [pointArray1 addObject:NSStringFromCGPoint(CGPointMake(kViewWidth(secondBtn) *leftProportion2, kViewHeight(secondBtn)))];
    secondBtn.pointArray = [pointArray1 mutableCopy];
    secondBtn.backgroundColor = [UIColor colorWithHex:0xffce66];
    [secondBtn setNeedsDisplay];
    
    //绑卡
    thirdBtn.frame = CGRectMake(32, 62 + 60, kViewWidth(secondBtn) * baseProportion2, 60);
    [thirdBtn mas_remakeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(secondBtn.mas_bottom).with.offset(kMidHeight);
        make.centerX.equalTo(secondBtn);
        make.width.equalTo(@(kViewWidth(secondBtn) * baseProportion2));
        make.height.equalTo(@60.f);
    }];
    
    CGFloat baseProportion3 = repeatCount/lendCount;
    CGFloat leftProportion3 = (1 - baseProportion3)/2.0f;
    CGFloat rightProportion3 = 1 - leftProportion3;
    // 添加路径关键点array
    NSMutableArray *pointArray2 = [NSMutableArray array];
    [pointArray2 addObject:NSStringFromCGPoint(CGPointMake(0.f, 0.f))];
    [pointArray2 addObject:NSStringFromCGPoint(CGPointMake(kViewWidth(thirdBtn), 0.f))];
    [pointArray2 addObject:NSStringFromCGPoint(CGPointMake(kViewWidth(thirdBtn) *rightProportion3, thirdBtn.frame.size.height))];
    [pointArray2 addObject:NSStringFromCGPoint(CGPointMake(kViewWidth(thirdBtn) *leftProportion3, kViewHeight(thirdBtn)))];
    thirdBtn.pointArray = [pointArray2 mutableCopy];
    thirdBtn.backgroundColor = [UIColor colorWithHex:0xff6f6f];
    [thirdBtn setNeedsDisplay];
    
    //下单
    fourthBtn.frame = CGRectMake(32, 62 + 60, kViewWidth(thirdBtn) * baseProportion3, 60);
    [fourthBtn mas_remakeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(thirdBtn.mas_bottom).with.offset(kMidHeight);
        make.centerX.equalTo(thirdBtn);
        make.width.equalTo(@(kViewWidth(thirdBtn) * baseProportion3));
        make.height.equalTo(@60.f);
    }];
    
    // 添加路径关键点array
    NSMutableArray *pointArray3 = [NSMutableArray array];
    [pointArray3 addObject:NSStringFromCGPoint(CGPointMake(0.f, 0.f))];
    [pointArray3 addObject:NSStringFromCGPoint(CGPointMake(kViewWidth(fourthBtn), 0.f))];
    [pointArray3 addObject:NSStringFromCGPoint(CGPointMake(kViewWidth(fourthBtn) *1/2, fourthBtn.frame.size.height))];
    [pointArray3 addObject:NSStringFromCGPoint(CGPointMake(kViewWidth(fourthBtn) *1/2, kViewHeight(fourthBtn)))];
    fourthBtn.pointArray = [pointArray3 mutableCopy];
    fourthBtn.backgroundColor = [UIColor colorWithHex:0x8ea3ff];
    [fourthBtn setNeedsDisplay];
    
    //扩大button点击区域
    [firstBtn setTouchExpandEdgeWithTop:0 right:40 bottom:0 left:40];
    [secondBtn setTouchExpandEdgeWithTop:0 right:40 bottom:0 left:40];
    [thirdBtn setTouchExpandEdgeWithTop:0 right:40 bottom:0 left:40];
    [fourthBtn setTouchExpandEdgeWithTop:0 right:40 bottom:0 left:40];
}
//大标题
-(void)setTitle:(NSString *)title{
    _title = title;
    titleLabel.text = _title;
}
//小标题
-(void)setDesArray:(NSMutableArray *)desArray{
    _desArray = desArray;
    for (int i = 0; i < _desArray.count; i++) {
        //文字
        UILabel * label = labelArray[i];
        label.text = _desArray[i];
        //标识
        UIImageView * imageView = imageViewArray[i];
        if (i == 0) {
            [label mas_remakeConstraints:^(MASConstraintMaker *make) {
                make.left.mas_equalTo(self).offset(32);
                make.bottom.mas_equalTo(self).offset(-15);
                make.width.equalTo(@25.0f);
                make.height.equalTo(@15.0f);
            }];
            
            [imageView mas_remakeConstraints:^(MASConstraintMaker *make) {
                make.left.equalTo(label);
                make.top.mas_equalTo(label.mas_bottom).offset(5);
                make.width.equalTo(@25.0f);
                make.height.equalTo(@5.0f);
            }];
        }else{
            
            UILabel * preLabel = labelArray[i - 1];
            [label mas_remakeConstraints:^(MASConstraintMaker *make) {
                make.left.mas_equalTo(preLabel.mas_right).offset(14);
                make.centerY.equalTo(preLabel);
                make.width.equalTo(@25.0f);
                make.height.equalTo(@15.0f);
            }];
            
            [imageView mas_remakeConstraints:^(MASConstraintMaker *make) {
                make.left.equalTo(label);
                make.top.mas_equalTo(label.mas_bottom).offset(5);
                make.width.equalTo(@25.0f);
                make.height.equalTo(@5.0f);
            }];
        }       
    }
}
- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        //标题
        titleLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 10, frame.size.width, 40)];
        titleLabel.textAlignment = NSTextAlignmentCenter;
        titleLabel.font = [UIFont boldSystemFontOfSize:18];
        [self addSubview:titleLabel];
        
        //注册
        firstBtn = [FHXCustomButton buttonWithType:UIButtonTypeCustom];
        firstBtn.frame = CGRectMake(32, 62, SCREEN_WIDTH - 32*2, 60);
        firstBtn.layer.masksToBounds = YES;
        firstBtn.layer.cornerRadius = 5.0f;
        firstBtn.tag = 5001;
        [firstBtn addTarget:self action:@selector(btnAction:) forControlEvents:UIControlEventTouchUpInside];
        [self addSubview:firstBtn];

        //开户
        secondBtn = [FHXCustomButton buttonWithType:UIButtonTypeCustom];
        [self addSubview:secondBtn];
        secondBtn.tag = 5002;
        [secondBtn addTarget:self action:@selector(btnAction:) forControlEvents:UIControlEventTouchUpInside];

        //绑卡
        thirdBtn = [FHXCustomButton buttonWithType:UIButtonTypeCustom];
        thirdBtn.frame = fourthBtn.frame;
        [self addSubview:thirdBtn];
        thirdBtn.tag = 5003;
        [thirdBtn addTarget:self action:@selector(btnAction:) forControlEvents:UIControlEventTouchUpInside];
        
        //下单
        fourthBtn = [FHXCustomButton buttonWithType:UIButtonTypeCustom];
        [self addSubview:fourthBtn];
        fourthBtn.tag = 5004;
        [fourthBtn addTarget:self action:@selector(btnAction:) forControlEvents:UIControlEventTouchUpInside];
        
        //创建四个标识标签
        labelArray = [[NSMutableArray alloc]initWithCapacity:0];
        imageViewArray = [[NSMutableArray alloc]initWithCapacity:0];
        for (int i = 0; i < 4; i++) {
            UILabel * testLabel = [[UILabel alloc]init];
            testLabel.textColor = [UIColor colorWithHex:0x333333];
            testLabel.font = [UIFont systemFontOfSize:12];
            testLabel.textAlignment = NSTextAlignmentCenter;
            [labelArray addObject:testLabel];
            [self addSubview:testLabel];
            
            UIImageView * imageVIew = [[UIImageView alloc]init];
            imageVIew.layer.masksToBounds = YES;
            imageVIew.layer.cornerRadius = 2.5f;
            [imageViewArray addObject:imageVIew];
            [self addSubview:imageVIew];
            switch (i) {
                case 0:
                    imageVIew.backgroundColor = [UIColor colorWithHex:0x4262ff];
                    break;
                case 1:
                    imageVIew.backgroundColor = [UIColor colorWithHex:0xFFCE66];
                    break;
                case 2:
                    imageVIew.backgroundColor = [UIColor colorWithHex:0xFF6F6F];
                    break;
                case 3:
                    imageVIew.backgroundColor = [UIColor colorWithHex:0x8EA3FF];
                    break;
                default:
                    break;
            }
        }
    }
    return self;
}
//点击效果
-(void)btnAction:(id)sender{
    self.showButton.hidden = NO;
    UIButton * btn = (UIButton *)sender;
    if (btn.tag == 5001) {
        [self.showButton mas_remakeConstraints:^(MASConstraintMaker *make) {
            make.centerX.mas_equalTo(100 - firstBtn.center.x);
            make.centerY.equalTo(firstBtn);
            make.width.equalTo(@117.0f);
            make.height.equalTo(@43.0f);
        }];
        
        [self.showButton setBackgroundImage:[UIImage imageNamed:@"icon_message_register"] forState:UIControlStateNormal];
        [self.showButton setTitle:[NSString stringWithFormat:@"人数: %.0f",registerCount] forState:UIControlStateNormal];
    }
    if (btn.tag == 5002) {
        [self.showButton mas_remakeConstraints:^(MASConstraintMaker *make) {
            make.centerX.mas_equalTo(100 - secondBtn.center.x);
            make.centerY.equalTo(secondBtn);
            make.width.equalTo(@115.0f);
            make.height.equalTo(@57.0f);
        }];
        [self.showButton setBackgroundImage:[UIImage imageNamed:@"icon_message_other"] forState:UIControlStateNormal];
        //转化率
        NSString * transRateStr = [[NSString stringWithFormat:@"%.2f",openCount/registerCount*100] stringByAppendingString:@"%"];
        [self.showButton setTitle:[NSString stringWithFormat:@"人数: %.0f\n转化率: %@",openCount,transRateStr] forState:UIControlStateNormal];
    }
    
    if (btn.tag == 5003) {
        [self.showButton mas_remakeConstraints:^(MASConstraintMaker *make) {
            make.centerX.mas_equalTo(100 - thirdBtn.center.x);
            make.centerY.equalTo(thirdBtn);
            make.width.equalTo(@115.0f);
            make.height.equalTo(@57.0f);
        }];
        [self.showButton setBackgroundImage:[UIImage imageNamed:@"icon_message_other"] forState:UIControlStateNormal];
        //转化率
        NSString * transRateStr = [[NSString stringWithFormat:@"%.2f",lendCount/openCount*100] stringByAppendingString:@"%"];
        [self.showButton setTitle:[NSString stringWithFormat:@"人数: %.0f\n转化率: %@",lendCount,transRateStr] forState:UIControlStateNormal];
    }
    if (btn.tag == 5004) {
        [self.showButton mas_remakeConstraints:^(MASConstraintMaker *make) {
            make.centerX.mas_equalTo(100 - fourthBtn.center.x);
            make.centerY.equalTo(fourthBtn);
            make.width.equalTo(@115.0f);
            make.height.equalTo(@57.0f);
        }];
        [self.showButton setBackgroundImage:[UIImage imageNamed:@"icon_message_other"] forState:UIControlStateNormal];
        //转化率
        NSString * transRateStr = [[NSString stringWithFormat:@"%.2f",repeatCount/lendCount*100] stringByAppendingString:@"%"];
        [self.showButton setTitle:[NSString stringWithFormat:@"人数: %.0f\n转化率: %@",repeatCount,transRateStr] forState:UIControlStateNormal];
    }
}
- (UIButton *)showButton{
    if (!_showButton) {
        _showButton = [UIButton buttonWithType:UIButtonTypeCustom];
        _showButton.frame = CGRectMake(0, 0, 115, 57);
        [_showButton setTitleColor:[UIColor colorWithHex:666666] forState:UIControlStateNormal];
        _showButton.titleLabel.font = [UIFont systemFontOfSize:12];
        _showButton.titleEdgeInsets = UIEdgeInsetsMake(0, -10, 0, 0);
        _showButton.titleLabel.lineBreakMode = 0;
        [self addSubview:_showButton];   
    }
    return _showButton;
}

-(FHXChartNoDataView *)noDataView{
    if (!_noDataView) {
        _noDataView = [[NSBundle mainBundle]loadNibNamed:@"FHXChartNoDataView" owner:self options:nil][0];
        _noDataView.frame = self.bounds;
        [self addSubview:_noDataView];
        _noDataView.hidden = YES;
        [_noDataView mas_remakeConstraints:^(MASConstraintMaker *make) {
            make.centerX.equalTo(self);
            make.centerY.equalTo(self);
            make.width.equalTo(@128.0f);
            make.height.equalTo(@128.0f);
        }];   
    }
    return _noDataView;
}
@end

因为是纯代码创建的图,所以借用了优秀的Masonry库来添加代码约束。因为这种图在视觉上就是直观的看一个数据转化率,所以可以在计算每个点的位置的时候,将数据整数化,使用整数来计算更方便,因为实际数据是要通过点击事件显示出来的,所以取整数计算点并绘图,不影响结果。

使用
1.创建funnlView(漏斗图)

_funnelView = [[FHXFunnelView alloc]initWithFrame:CGRectMake(0, 64, SCREEN_WIDTH, 360)];
    [self.view addSubview:self.funnelView];
    [self initTestData];

2.添加数据,使用随机数模拟真实数据

//动态添加数据
    FHXFunnelModel * funnelModel = [[FHXFunnelModel alloc]init];
    funnelModel.firstItemNum = [NSString stringWithFormat:@"%d",(arc4random() % 100) + 300];
    funnelModel.secondItemNum = [NSString stringWithFormat:@"%d",(arc4random() % 100) + 200];
    funnelModel.thirdItemNum = [NSString stringWithFormat:@"%d",(arc4random() % 100) + 100];
    funnelModel.fourthItemNum = [NSString stringWithFormat:@"%d",(arc4random() % 100) + 0];
    self.funnelView.funnelModel = funnelModel;
    //大标题
    self.funnelView.title = @"用户数据漏斗图";
    //小标题
    NSArray * array = @[@"注册",@"开户",@"绑卡",@"下单"];
    NSMutableArray * titleArray = [NSMutableArray arrayWithArray:array];
    self.funnelView.desArray = titleArray;

PS:实际应用中,很多数据都是呈现漏斗图的趋势,类似“注册用户-->实名用户-->下单用户-->二次下单用户”这种数据,可根据实际需求,定制各类数据漏斗图。下一步,将会对绘制动画做一下优化。

Demo链接

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

推荐阅读更多精彩内容