UICollectionView框架总结

一、UIcollectionView介绍

1.1、简介

首先看苹果官方文档 UICollectionView Class Reference 的介绍:

The UICollectionView class manages an ordered collection of data items and presents them using customizable layouts. Collection views provide the same general function as table views except that a collection view is able to support more than just single-column layouts. Collection views support customizable layouts that can be used to implement multi-column grids, tiled layouts, circular layouts, and many more. You can even change the layout of a collection view dynamically if you want.

在WWDC2012中的Introducing Collection Views,苹果首次介绍了UICollectionView,类似UITableView的用法使人很容易接受,但强大的自定义布局,又使其相较于UITableView有了选择它的更多理由,UITableView中的表格只支持单排列表,没有办法支持网格列表模式。

一句话总结就是:UICollectionView与UITableView相似,却提供了可自定义多列网格(Grild)的功能。

下面通过一张图片来了解UICollectionView的构成:

text

1.2、UICollectionView用来做什么

UICollectionView 类用于管理有序的数据单元,并且可以定制化的显示他们。UICollectionView 除了提供和tableview相同的一般的方法外,还支持一列以上的布局。UICollectionView 支持的定制化布局能够实现网格或是瓷砖的布局效果。你甚至可以动态的改变Collectionview的布局。

二、UICollectionView与UITableView比较

2.1、UICollectionViewDataSource

UICollectionViewDelegate-负责提供展示的数据,实现下面两个必须的委托方法,其实与UITableView并无二意

  • numberOfItemsInsection: 某个Section里面有多少item
  • cellForItemAtIndexPath: 对于某个位置应该显示什么样的cell,里面会涉及到cell的复用,可参考UITableView

2.2、UICollectionViewDelegate

UICollectionViewDelegate-负责用户的交互、cell的外形,委托方法和UITableView相似,可以选择性实现以下委托方法。

  • collectionView:shouleHighlightItemAtIndexPath:是否支持高亮?
  • collectionView:didHighlightItemAtIndexPath:如果支持高亮,那么高亮;
  • collectionView:shouldSelectItemAtIndexPath:询问是否可以被选中?
  • collectionView:didUnhighlightItemAtIndexPath:如果支持高亮,那么现在取消高亮;
  • collectionView:didSelectItemAtIndexPath:如果支持可以被选中,那么选中 cell;

2.3、UICollectionViewLayout

在布局上,与UITableView直接使用系统提供的样式,UICollectionView使用的是UICollectionViewLayout来自定义布局样式。

  • UICollectionViewLayout是一个抽象基类,需要继承它来为CollectionView生成Layout信息。Layout对象的作用是决定Cells,Supplementary Views和Decoration Views在CollectionView中的布局位置。系统也提供了UICollectionViewFlowLayout-l流水式布局效果
  • UICollectionView的显示效果几乎全部由UICollectionViewLayout负责,而真正存储着每一个cell的位置、大小等属性的是UICollectionViewLayoutAttributes。每一个cell对应着一个属于自己的UICollectionViewLayoutAttributes,而UICollectionViewLayout正是利用UICollectionViewLayoutAttributes里存在的信息对每一个cell进行布局。

三、UICollectionView层次结构

UICollectionView类负责管理数据的有序集合以及以自定义布局的模式来呈现这些数据,它提供了一些常用的表格功能,此外还增加了许多单栏布局。UICollectionView支持可以用于实现多列网格、平铺的布局、圆形的布局和更多的自定义布局,甚至可以动态的改变它的布局。

3.1、UICollectionView基本使用

我们要使用UICollectionView得实现UICollectionViewDataSource,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout这三个协议。UICollectionViewDataSource是它的数据源,UICollectionDelegate是它的呈现样式,UICollectionViewDelegateFlowLayout是它的布局样式。

3.1.1 初始化

UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];

UICollectionView *colView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:layout];

3.1.2 注册UICollectionView使用的cell类型

[colView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"myCell"];

3.1.3 设置代理

colView.delegate = self;

colView.dataSource = self;

3.1.4 实现协议UICollectionViewDataSource

//配置UICollectionView的每个section的item数
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    return [[self loadData] count];
}

//配置section数
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
    return 1;
}

//呈现数据
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *cellID = @"myCell";
    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellID forIndexPath:indexPath];
    cell.backgroundColor = [UIColor redColor];
    return cell;
}

3.1.5 UICollectionViewDelegateFlowLayout

//配置每个item的size
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
    return CGSizeMake(100, 60);
}

//配置item的边距
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
    return UIEdgeInsetsMake(20, 20, 0, 20);
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
    return CGSizeMake(200, 60);
}

3.1.6 UICollectionViewDelegate

复制代码
//点击item时触发
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"您点击了item:%@", [[self loadData] objectAtIndex:indexPath.row]);
    [collectionView cellForItemAtIndexPath:indexPath].backgroundColor = [UIColor redColor];
    
}

//当前item是否可以点击
- (BOOL) collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(nonnull NSIndexPath *)indexPath
{
    if (indexPath.row % 2)
    {
        return YES;
    }
    
    return NO;
}
//cell点击时是否高亮,点击cell时的样式和点击后cell的样式 
- (BOOL)collectionView:(UICollectionView *)collectionView shouldHighlightItemAtIndexPath:(NSIndexPath *)indexPath
{
    return YES;
}

- (void)collectionView:(UICollectionView *)collectionView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath
{
    UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];
    cell.backgroundColor = [UIColor redColor];
}

- (void)collectionView:(UICollectionView *)collectionView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath
{
    UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];
    cell.backgroundColor = [UIColor grayColor];
}

3.2、自定义UICollectionViewFlowLayout

使用UICollectionViewFlowLayout之前,我们来了解它内部常用的属性

//同一组当中,垂直方向:行与行之间的间距;水平方向:列与列之间的间距
@property (nonatomic) CGFloat minimumLineSpacing;
//垂直方向:同一行中的cell之间的间距;水平方向:同一列中,cell与cell之间的间距
@property (nonatomic) CGFloat minimumInteritemSpacing;
//每个cell统一尺寸
@property (nonatomic) CGSize itemSize;
//滑动反向,默认滑动方向是垂直方向滑动
@property (nonatomic) UICollectionViewScrollDirection scrollDirection;
//每一组头视图的尺寸。如果是垂直方向滑动,则只有高起作用;如果是水平方向滑动,则只有宽起作用。
@property (nonatomic) CGSize headerReferenceSize;
//每一组尾部视图的尺寸。如果是垂直方向滑动,则只有高起作用;如果是水平方向滑动,则只有宽起作用。
@property (nonatomic) CGSize footerReferenceSize;
//每一组的内容缩进
@property (nonatomic) UIEdgeInsets sectionInset;

3.2.1 NYWaterflowLayout(瀑布流样式)

NYWaterflowLayout继承与UICollectionViewLayout 重写部分方法

核心代码

- (void)prepareLayout
{
    [super prepareLayout];
    
    // 清楚以前计算的所有高度
    [self.columnHeights removeAllObjects];
    for (NSInteger i = 0; i < self.columnCount; i++) {
        [self.columnHeights addObject:@(self.edgeInsets.top)];
    }
    
    // 清楚之前所有的布局属性
    [self.attrsArray removeAllObjects];
    // 开始创建每一个cell对应的布局属性
    NSInteger count = [self.collectionView numberOfItemsInSection:0];
    for (NSInteger i = 0; i < count; i++) {
        //创建位置
        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
        UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:indexPath];
        [self.attrsArray addObject:attributes];
    }
}
// 决定cell的排布
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
{
    return self.attrsArray;
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
    // 创建布局属性
    UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
    
    // collectionView的宽度
    CGFloat collectionViewWidth = self.collectionView.frame.size.width;
    
    // 设置布局属性的frame
    CGFloat width = (collectionViewWidth - self.edgeInsets.left - self.edgeInsets.right - (self.columnCount - 1) * self.columnMargin) / self.columnCount;
    CGFloat h = [self.delegate waterflowLayout:self heightForItemAtIndex:indexPath.item itemWidth:width];
//    CGFloat h = 50 + arc4random_uniform(100);
    
    // 找出高度最短的那一列
    __block NSInteger destColumn = 0;
    __block CGFloat minColumnHeight = [self.columnHeights[0] doubleValue];
    [self.columnHeights enumerateObjectsUsingBlock:^(NSNumber  *columnHeightNumber, NSUInteger idx, BOOL * _Nonnull stop) {
        CGFloat columnHeight = columnHeightNumber.doubleValue;
        if (minColumnHeight > columnHeight) {
            minColumnHeight = columnHeight;
            destColumn = idx;
        }
    }];

    // 获取最短列的xy
    CGFloat x = self.edgeInsets.left + destColumn * (width + self.columnMargin);
    CGFloat y = minColumnHeight;
    if (y != self.edgeInsets.top) {
        y += self.rowMargin;
    }
    
    attributes.frame = CGRectMake(x, y, width, h);
    
    //更新最短那列的高度
    self.columnHeights[destColumn] = @(CGRectGetMaxY(attributes.frame));
    
    return attributes;
}
// 设置CollectionViewContentSize
- (CGSize)collectionViewContentSize
{
    __block CGFloat maxColumnHeight = [self.columnHeights[0] doubleValue];
    [self.columnHeights enumerateObjectsUsingBlock:^(NSNumber *columnHeightNumber, NSUInteger idx, BOOL * _Nonnull stop) {
        CGFloat columnHeight = columnHeightNumber.doubleValue;
        if (maxColumnHeight < columnHeight) {
            maxColumnHeight = columnHeight;
        }
    }];
    return CGSizeMake(0, maxColumnHeight + self.edgeInsets.bottom);
}

NYWaterflowLayoutDelegate

@required
- (CGFloat)waterflowLayout:(NYWaterflowLayout *)waterflowLayout heightForItemAtIndex:(NSUInteger)index itemWidth:(CGFloat)itemWidth;

@optional
// 瀑布流布局的列数
- (NSInteger)columnCountInWaterflowLayout:(NYWaterflowLayout *)waterflowLayout;
// 列间距
- (CGFloat)columnMarginInWaterflowLayout:(NYWaterflowLayout *)wateflowLayout;
// 行间距
- (CGFloat)rowMarginInWaterflowLayout:(NYWaterflowLayout *)waterflowLayout;
// 边沿间距
- (UIEdgeInsets)edgeInsetsInWaterflowLayout:(NYWaterflowLayout *)waterflowLayout;


效果图

3.2.2 NYCircularLayout(环形布局)

核心代码

- (void)prepareLayout
{
    [super prepareLayout];
    
    // 获取item的个数
    _itemCount = (int)[self.collectionView numberOfItemsInSection:0];
    _attributeArray = [[NSMutableArray alloc] init];
    
    // 先设定大圆的半径取长和宽最短的
    CGFloat radius = MIN(self.collectionView.frame.size.width, self.collectionView.frame.size.height)/2;
    // 计算圆心的位置
    CGPoint center = CGPointMake(self.collectionView.frame.size.width/2, self.collectionView.frame.size.height/2);
    // 设置每个item的大小为50*50 则半径为25
    for (int i = 0; i < _itemCount; i++) {
        UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];
        
        // 设置item的大小
        attributes.size = CGSizeMake(50, 50);
        
        // 计算每个item中心的坐标 算出的x,y值还要减去item自身的半径大小
        float x = center.x + cosf(2*M_PI/_itemCount * i)*(radius - 25);
        float y = center.y + sinf(2*M_PI/_itemCount * i)*(radius - 25);
        
        attributes.center = CGPointMake(x, y);
        [_attributeArray addObject:attributes];
    }
}
// 设定区域大小
- (CGSize)collectionViewContentSize
{
    return self.collectionView.frame.size;
}
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
{
    return _attributeArray;
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
    // 创建布局属性
    UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
    return attributes; 
}

效果图

3.2.3 CarouselViewLayout(旋转布局)

核心代码

- (void)prepareLayout {
    [super prepareLayout];
    if (self.visibleCount < 1) {
        self.visibleCount = 3;
    }
    if (self.scrollDirection == UICollectionViewScrollDirectionVertical) {
        _viewHeight = CGRectGetHeight(self.collectionView.frame);
        _itemHeight = self.itemSize.height;
        self.collectionView.contentInset = UIEdgeInsetsMake((_viewHeight - _itemHeight) / 2, 0, (_viewHeight - _itemHeight) / 2, 0);
    } else {
        _viewHeight = CGRectGetWidth(self.collectionView.frame);
        _itemHeight = self.itemSize.width;
        self.collectionView.contentInset = UIEdgeInsetsMake(0, (_viewHeight - _itemHeight) / 2, 0, (_viewHeight - _itemHeight) / 2);
    }
}
- (CGSize)collectionViewContentSize {
    NSInteger cellCount = [self.collectionView numberOfItemsInSection:0];
    if (self.scrollDirection == UICollectionViewScrollDirectionVertical) {
        return CGSizeMake(CGRectGetWidth(self.collectionView.frame), cellCount * _itemHeight);
    }
    return CGSizeMake(cellCount * _itemHeight, CGRectGetHeight(self.collectionView.frame));
}
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
    NSInteger cellCount = [self.collectionView numberOfItemsInSection:0];
    CGFloat centerY = (self.scrollDirection == UICollectionViewScrollDirectionVertical ? self.collectionView.contentOffset.y : self.collectionView.contentOffset.x) + _viewHeight / 2;
    NSInteger index = centerY / _itemHeight;
    NSLog(@"第几个-----%ld",(long)index);
    NSInteger count = (self.visibleCount - 1) / 2;
    // 取第一个和当前位置减1的最大值
    NSInteger minIndex = MAX(0, (index - count));
    // 取最后一个和当前位置加1的最小值
    NSInteger maxIndex = MIN((cellCount - 1), (index + count));
    NSMutableArray *array = [NSMutableArray array];
    //更新可视范围内的布局
    for (NSInteger i = minIndex; i <= maxIndex; i++) {
        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
        UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:indexPath];
        [array addObject:attributes];
    }
    return array;
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
    attributes.size = self.itemSize;
    
    CGFloat cY = (self.scrollDirection == UICollectionViewScrollDirectionVertical ? self.collectionView.contentOffset.y : self.collectionView.contentOffset.x) + _viewHeight / 2;
    CGFloat attributesY = _itemHeight * indexPath.row + _itemHeight / 2;
    attributes.zIndex = -ABS(attributesY - cY);
    
    CGFloat delta = cY - attributesY;
    CGFloat ratio =  - delta / (_itemHeight * 2);
    CGFloat scale = 1 - ABS(delta) / (_itemHeight * 6.0) * cos(ratio * M_PI_4);
//    attributes.transform = CGAffineTransformMakeScale(scale, scale);
    
    CGFloat centerY = attributesY;
    switch (self.carouselAnim) {
        case HJCarouselAnimRotary:
            attributes.transform = CGAffineTransformRotate(attributes.transform, - ratio * M_PI_4);
            centerY += sin(ratio * M_PI_2) * _itemHeight / 2;
            break;
        case HJCarouselAnimCarousel:
            centerY = cY + sin(ratio * M_PI_2) * _itemHeight * INTERSPACEPARAM;
            break;
        case HJCarouselAnimCarousel1:
            centerY = cY + sin(ratio * M_PI_2) * _itemHeight * INTERSPACEPARAM;
            if (delta > 0 && delta <= _itemHeight / 2) {
                attributes.transform = CGAffineTransformIdentity;
                CGRect rect = attributes.frame;
                if (self.scrollDirection == UICollectionViewScrollDirectionVertical) {
                    rect.origin.x = CGRectGetWidth(self.collectionView.frame) / 2 - _itemSize.width * scale / 2;
                    rect.origin.y = centerY - _itemHeight * scale / 2;
                    rect.size.width = _itemSize.width * scale;
                    CGFloat param = delta / (_itemHeight / 2);
                    rect.size.height = _itemHeight * scale * (1 - param) + sin(0.25 * M_PI_2) * _itemHeight * INTERSPACEPARAM * 2 * param;
                } else {
                    rect.origin.x = centerY - _itemHeight * scale / 2;
                    rect.origin.y = CGRectGetHeight(self.collectionView.frame) / 2 - _itemSize.height * scale / 2;
                    rect.size.height = _itemSize.height * scale;
                    CGFloat param = delta / (_itemHeight / 2);
                    rect.size.width = _itemHeight * scale * (1 - param) + sin(0.25 * M_PI_2) * _itemHeight * INTERSPACEPARAM * 2 * param;
                }
                attributes.frame = rect;
                return attributes;
            }
            break;
        case HJCarouselAnimCoverFlow: {
            CATransform3D transform = CATransform3DIdentity;
            transform.m34 = -1.0/400.0f;
            transform = CATransform3DRotate(transform, ratio * M_PI_4, 1, 0, 0);
            attributes.transform3D = transform;
        }
            break;
        default:
            break;
    }
    
    if (self.scrollDirection == UICollectionViewScrollDirectionVertical) {
        attributes.center = CGPointMake(CGRectGetWidth(self.collectionView.frame) / 2, centerY);
    } else {
        attributes.center = CGPointMake(centerY, CGRectGetHeight(self.collectionView.frame) / 2);
    }
    
    return attributes;
}
//当滑动停止时使得item的位置位于中心
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity {
    CGFloat index = roundf(((self.scrollDirection == UICollectionViewScrollDirectionVertical ? proposedContentOffset.y : proposedContentOffset.x) + _viewHeight / 2 - _itemHeight / 2) / _itemHeight);
    if (self.scrollDirection == UICollectionViewScrollDirectionVertical) {
        proposedContentOffset.y = _itemHeight * index + _itemHeight / 2 - _viewHeight / 2;
    } else {
        proposedContentOffset.x = _itemHeight * index + _itemHeight / 2 - _viewHeight / 2;
    }
    return proposedContentOffset;
}

效果图

image

3.2.4 banner轮播器

3.2.4.1 UIScrollView实现

核心代码

//初始化ImageView
- (void)initLayoutSubview
{
    [self.scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(self);
    }];
    
    CGSize size = self.scrollView.bounds.size;
    _preImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, size.width, size.height)];
    [_scrollView addSubview:_preImageView];
    
    _currentImageView = [[UIImageView alloc] initWithFrame:CGRectMake(size.width, 0, size.width, size.height)];
    [_scrollView addSubview:_currentImageView];
    
    _nextImageView = [[UIImageView alloc] initWithFrame:CGRectMake(size.width * 2, 0, size.width, size.height)];
    [_scrollView addSubview:_nextImageView];
    
    self.scrollView.contentSize = CGSizeMake(3 * self.scrollView.bounds.size.width, 0);

    WS(weakSelf);
    [self.pageControl mas_makeConstraints:^(MASConstraintMaker *make) {
        make.bottom.equalTo(weakSelf.mas_bottom).offset(-10);
        make.width.equalTo(weakSelf.mas_width);
        make.height.equalTo(@(60));
    }];
    
    self.currentPage = 0;
    self.pageControl.numberOfPages = self.bannersArray.count;
    self.pageControl.currentPage = _currentPage;
    
    [self startTimer];
    
}
//准备加载页
- (void)pageLoad
{
    _preImageView.image = nil;
    _currentImageView.image = nil;
    _nextImageView.image = nil;
    _pageControl.currentPage = _currentPage;
    
#pragma mark -设置图片
    NSString *str = self.bannersArray[_currentPage == 0 ? self.bannersArray.count - 1 : _currentPage - 1];
    _preImageView.image = [UIImage imageNamed:str];
    str = self.bannersArray[_currentPage];
    _currentImageView.image = [UIImage imageNamed:str];
    str = self.bannersArray[_currentPage == self.bannersArray.count-1 ? 0 : _currentPage + 1];
    _nextImageView.image = [UIImage imageNamed:str];

    _scrollView.contentOffset = CGPointMake(self.frame.size.width, 0);
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    [self scrollViewDidEnd];
    [self startTimer];
}

- (void)scrollViewDidEnd
{
    int index = _scrollView.contentOffset.x / self.window.bounds.size.width;
    if (index == 0) {
        _currentPage = _currentPage == 0 ? self.bannersArray.count - 1 : _currentPage - 1;
    } else if (index == 2)
    {
        _currentPage = _currentPage + 1 == self.bannersArray.count ? 0 : _currentPage + 1;
    }
    
    [self pageLoad];
}

SDCycleScrollViewhttp://www.oschina.net/p/sdcyclescrollview

效果图

附录

UICollectionView思维导图

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

推荐阅读更多精彩内容