FJSegmentedPager(仿简书/微博首页效果、网易新闻、头条滑块视图联动效果) 介绍

之前项目中需要实现这样一个功能,效果如图所示:

*FJSegmentedPager*

虽然这种效果很常见,原理也挺简单,但也有挺多坑,我个人觉得第三方中比较好的就是MXSegmentedPager,我这边是自己实现的,经过项目的验证,自己扩展、封装了下。

gitHub 链接:FJSegmentedPager

集成方法

静态:手动将FJSegmentedPager文件夹拖入到工程中。
动态:CocoaPods:pod 'FJSegmentedPager'

一. 使用方法

A. 去掉头部:

1. 设置segementPageView,设置dataSouce(备注: 如果有需要也设置delegate)

// 滚动 栏
- (FJSegementPageView *)segementPageView {
    if (!_segementPageView) {
        _segementPageView = [[FJSegementPageView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, self.view.frame.size.height)];
        _segementPageView.segmentViewStyle = self.segmentViewStyle;
        _segementPageView.dataSource = self;
    }
    return _segementPageView;
}

2. 实现dataSource 代理

#pragma mark --------------- Custom Delegate
// 子页面 总数
- (NSInteger)numberOfChildViewControllers {
    return self.titleArray.count;
}

// 子页面 标题
- (NSArray<NSString *> *)titlesArrayOfChildViewControllers {
    return self.titleArray;
}

/** 获取到将要显示的页面的控制器
 * reuseViewController : 这个是返回给你的controller, 你应该首先判断这个是否为nil, 如果为nil 创建对应的控制器并返回, 如果不为nil直接使用并返回
 * index : 对应的下标
 */
- (UIViewController<FJSegmentPageChildVcDelegate> *)childViewController:(UIViewController<FJSegmentPageChildVcDelegate> *)reuseViewController withIndex:(NSInteger)index {
    
    UIViewController<FJSegmentPageChildVcDelegate> *childVc = reuseViewController;
    
    if (!childVc) {
        childVc = [[FJSecondShopViewController alloc] init];
    }
    return childVc;
}

如图所示:

FJSegmentedPageViewNoHeader.gif

B.带有头部:

1. 继承自FJSegmentedBaseViewController:

#import "FJSegmentedBaseViewController.h"

@interface FJFirstShopSegmentedViewController : FJSegmentedBaseViewController

@end

2. 设置FJSegementContentCell,然后设置dataSouce(备注: 如果有需要也设置delegate)

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    FJSegementContentCell *segementContentCell = [FJSegementContentCell cellWithTableView:tableView];
    segementContentCell.segmentViewStyle = self.segmentViewStyle;
    segementContentCell.segementPageView.dataSource = self;
    segementContentCell.segementPageView.delegate = self;
    return segementContentCell;
}

3.实现代理方法

#pragma mark --------------- Custom Delegate

#pragma mark ----  FJSegmentPageViewDataSource
// 子页面 总数
- (NSInteger)numberOfChildViewControllers {
    return self.titleArray.count;
}

// 子页面 标题
- (NSArray<NSString *> *)titlesArrayOfChildViewControllers {
    return self.titleArray;
}

/** 获取到将要显示的页面的控制器
 * reuseViewController : 这个是返回给你的controller, 你应该首先判断这个是否为nil, 如果为nil 创建对应的控制器并返回, 如果不为nil直接使用并返回
 * index : 对应的下标
 */
- (UIViewController<FJSegmentPageChildVcDelegate> *)childViewController:(UIViewController<FJSegmentPageChildVcDelegate> *)reuseViewController withIndex:(NSInteger)index {
    UIViewController<FJSegmentPageChildVcDelegate> *childVc = reuseViewController;
    
    if (!childVc) {
        childVc = [[FJFirstShopViewController alloc] init];
    }
    return childVc;
}

#pragma mark ----  FJSegmentPageViewDelegate
// 子页面 即将 显示
- (void)scrollPageController:(UIViewController *)scrollPageController childViewControllWillAppear:(UIViewController *)childViewController withIndex:(NSInteger)index {
    
}

// 子页面 已经 显示
- (void)scrollPageController:(UIViewController *)scrollPageController childViewControllDidAppear:(UIViewController *)childViewController withIndex:(NSInteger)index {
    
}

// 子页面 即将 消失
- (void)scrollPageController:(UIViewController *)scrollPageController childViewControllWillDisappear:(UIViewController *)childViewController withIndex:(NSInteger)index {
    
}

// 子页面 已经 消失
- (void)scrollPageController:(UIViewController *)scrollPageController childViewControllDidDisappear:(UIViewController *)childViewController withIndex:(NSInteger)index {
    
}

4. 设置偏移距离

self.tableViewOffsetY = [self.tableView rectForSection:0].origin.y + 10;

效果如图所示:

FJSegmentedPageView-OneScreen.gif

具体操作详见:Demo

二. 参数 详解

1. 通过FJSegmentViewStyle来配置相关参数


// 指示器 宽度 显示 类型
typedef NS_ENUM(NSInteger, FJSegmentIndicatorWidthShowType) {
    // 自适应
    FJSegmentIndicatorWidthShowTypeAdaption = 0,
    // 固定 宽度
    FJSegmentIndicatorWidthShowTypeAdaptionFixedWidth,
};


// 标题 view 字体颜色 改变 类型
typedef NS_ENUM(NSInteger, FJSegmentTitleViewTitleColorChangeType) {
    // 选中 之后 再 颜色 改变
    FJSegmentTitleViewTitleColorChangeTypeSelectedChange = 0,
    // 颜色 渐变
    FJSegmentTitleViewTitleColorChangeTypeGradualChange,
};


@interface FJSegmentViewStyle : NSObject
// 选择 第几个 tag
@property (nonatomic, assign) NSInteger selectedIndex;
// 标题 栏 高度
@property (nonatomic, assign) CGFloat tagSectionViewHeight;
// 分割线 高度
@property (nonatomic, assign) CGFloat separatorLineHeight;
// 指示条 高度
@property (nonatomic, assign) CGFloat segmentedIndicatorViewHeight;
// 指示条 宽度
@property (nonatomic, assign) CGFloat segmentedIndicatorViewWidth;
// 指示条 距离 底部 间距
@property (nonatomic, assign) CGFloat segmentedIndicatorViewWidthToBottomSpacing;
// 指示条 默认 扩展宽度
@property (nonatomic, assign) CGFloat segmentedIndicatorViewExtendWidth;
// 标题 默认 宽度
@property (nonatomic, assign) CGFloat segmentedTitleViewTitleWidth;
// 标题栏 cell  间距
@property (nonatomic, assign) CGFloat segmentedTagSectionCellSpacing;
// 标题栏 左右 间距
@property (nonatomic, assign) CGFloat segmentedTagSectionHorizontalEdgeSpacing;
// 标题 字体
@property (nonatomic, strong) UIFont *itemTitleFont;
// 标题 选中 字体
@property (nonatomic, strong) UIFont *itemTitleSelectedFont;
// 标题 分隔栏 背景色
@property (nonatomic, strong) UIColor *segmentToolbackgroundColor;
// 分段 标题 字体 普通 颜色
@property (nonatomic, strong) UIColor *itemTitleColorStateNormal;
// 分段 标题 字体 选中 颜色
@property (nonatomic, strong) UIColor *itemTitleColorStateSelected;
// 分段 标题 字体 高亮 颜色
@property (nonatomic, strong) UIColor *itemTitleColorStateHighlighted;
// 分割线 背景色
@property (nonatomic, strong) UIColor *separatorBackgroundColor;
// tableView 背景色
@property (nonatomic, strong) UIColor *tableViewBackgroundColor;
// 指示器 背景色
@property (nonatomic, strong) UIColor *indicatorViewBackgroundColor;
// 指示器 宽度 显示 类型
@property (nonatomic, assign) FJSegmentIndicatorWidthShowType segmentIndicatorWidthShowType;
// 标题 字体 颜色 改变 类型
@property (nonatomic, assign) FJSegmentTitleViewTitleColorChangeType titleColorChangeType;

二. 需求和思路

1. 需求:

  • 最外层的视图包含着一个头部、分类栏以及分类栏对应的分类内容视图。

  • 分类栏下面的内容视图页面可左右滚动,同时分类栏也定位到当前滚动的分类,同理点击分类栏上的分类,分类栏下面的分类视图也滚动到对应位置。

  • 向上滚动分类内容视图,最外层的视图向上移动,直到卡住分类栏,分类栏滚定,分类视图内容继续向上滚动。当向下滚动分类视图内容,滚动到视图内容底部,分类栏跟着向下移动直至原来位置。

2. 思路:

  • 最外层视图为FJSegmentedBaseViewController,包含tableView、tableViewOffsetY、configModelArray,其中tableview是最外层父容器,tableViewOffsetYtableView最大偏移距离、configModelArray 是分类栏模型的数组,根据这个生成分类栏和相关分类类别视图。

  • 头部作为tableview的头部,分类栏和分类内容视图作为一个UITableViewCell叫做FJSegementContentCell

  • 分类类别内容FJSegmentdPageViewController,包含一个可以响应多个手势的tableView,以及当前索引 currentIndex等。

  • 当分类栏处于底部时,向上滑动,最外层的FJSegmentedBaseViewController的tableView响应向上移动,而分类类别内容FJSegmentdPageViewController的tableView不移动;当分类栏处于顶部刚好卡住(偏移距离为tableViewOffsetY)的时候,最外层的FJSegmentedBaseViewController的tableView不响应,同时通知分类类别内容FJSegmentdPageViewController的tableView可以进行移动。

  • 当分类栏处于顶部时,向下滑动,最外层的FJSegmentedBaseViewController的tableView不响应,而分类类别内容FJSegmentdPageViewController的tableView进行移动;当最外层的FJSegmentedBaseViewController的tableView向下移动到离开顶部时,最外层的FJSegmentedBaseViewController的tableView进行响应向下移动同时通知分类类别内容FJSegmentdPageViewController的tableView不移动。

三. 实现

A. FJSegmentedBaseViewController

最外层容器主要包含tableView、tableViewOffsetY、configModelArray。其中tableViewOffsetY是用来判断分类栏卡住的位置,如果这个属性来判断滑动事件的响应者。configModelArray模型数组主要根据这个属性来生成分类栏以及相应的类别视图。

同时也添加了点击状态栏类别tableView返回顶部的事件通知。

1. 根据tableViewOffsetY来判断滑动事件的响应者

#pragma mark --- scrollView delegate

// 子类 必须 调用 super
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {

    CGFloat offsetY = scrollView.contentOffset.y;

    // 滑动 到 顶端
    if (offsetY >= self.tableViewOffsetY) {
        // 如果 不能 移动 就 固定
        if (self.enableScroll == NO) {
            scrollView.contentOffset = CGPointMake(0, self.tableViewOffsetY);
        }
        [[NSNotificationCenter defaultCenter] postNotificationName:kGoTopNotificationName object:[NSNumber numberWithBool:YES]];
        self.enableScroll = NO;
    }
    // 离开 顶端
    else {
        // 如果 不能 移动 就 固定
        if (self.enableScroll == NO) {
            scrollView.contentOffset = CGPointMake(0, self.tableViewOffsetY);
        }
    }
}

#pragma mark --- noti method

- (void)acceptMsg:(NSNotification *)noti {
    if ([noti.name isEqualToString:kLeaveTopNotificationName]) {
        NSNumber *tmpNum = noti.object;
        if (tmpNum.boolValue == YES) {
             self.enableScroll = YES;
        }
    }
}

2.添加点击状态栏类别tableView返回顶部事件通知

// 点击 返回 到 顶部view
- (UIView *)scrollToTopTapView {
    if (!_scrollToTopTapView) {
        _scrollToTopTapView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 30.0f)];
        _scrollToTopTapView.userInteractionEnabled = YES;
        [_scrollToTopTapView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(postScrollToTopViewNoti)]];
        _scrollToTopTapView.backgroundColor = [UIColor clearColor];
    }
    return _scrollToTopTapView;
}

/**
 用KVC取statusBar

 @return statusBar
 */
- (UIView *)statusBar {

    return [[UIApplication sharedApplication] valueForKey:@"statusBar"];
}


- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [[self statusBar] addSubview:self.scrollToTopTapView];
    [self.navigationController setNavigationBarHidden:YES animated:animated];
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    [self.scrollToTopTapView removeFromSuperview];
}

B. FJSegementContentCell

主要包含FJSegementContentView,主要进行参数传递。

C. FJSegementContentView

主要包含分类栏FJSegmentedTagTitleView和分类内容视图FJSegmentedPageContentView,以及通过双方代理处理两者之间的同步关系。

#pragma mark --- custom delegate

/******************************* FJTitleTagSectionViewDelegate ******************************/
// 当前 点击 index
- (void)titleSectionView:(FJSegmentedTagTitleView *)titleSectionView clickIndex:(NSInteger)index {

    self.detailContentView.selectedIndex = index;
}

/******************************* FJDetailContentViewDelegate ******************************/

- (void)detailContentView:(FJSegmentedPageContentView *)detailContentView selectedIndex:(NSInteger)selectedIndex {

    self.tagSecionView.selectedIndex = selectedIndex;
}

D. FJSegmentedTagTitleView

主要是通过UICollectionView来显示分类标题,同时兼容分类栏多个总宽度超过屏幕宽度和小于屏幕宽度的两种情况,以及确保indicatorView的准确。

** 1. 兼容分类栏和屏幕宽度的情况**

// 是否 超过 屏幕 宽度 限制
- (void)beyondWidthLimitWithTitleArray:(NSArray *)titleArray {
    self.isBeyondLimitWidth = NO;
    CGFloat tmpWidth = kFJSegmentedTagSectionCellSpacing;
    for (NSString *tmpTitle in titleArray) {
         tmpWidth += [self titleWidthWithTitle:tmpTitle];
        tmpWidth += kFJSegmentedTagSectionCellSpacing;
    }

    if (tmpWidth > self.frame.size.width) {
        self.isBeyondLimitWidth = YES;
    }
}

依据是否超过屏幕宽度设置边距和距离等:

// 更新 tagItemSize
- (void)updateItemSizeWithTitleArray:(NSArray *)titleArray {

    if (self.isBeyondLimitWidth == NO) {
        self.tagItemSize = CGSizeMake(self.frame.size.width / titleArray.count, self.frame.size.height);
    }
    else {
        self.tagFlowLayout.minimumLineSpacing = kFJSegmentedTagSectionCellSpacing; //最小线间距
        self.tagFlowLayout.minimumInteritemSpacing = kFJSegmentedTagSectionCellSpacing;
    }
    self.tagFlowLayout.itemSize = self.tagItemSize;
    CGRect indicatorViewFrame = self.indicatorView.frame;
    indicatorViewFrame.origin.x = [self indicatorX];
    self.indicatorView.frame = indicatorViewFrame;
    self.selectedIndex  = _selectedIndex;
    self.indicatorView.hidden = NO;
    [self.tagCollectionView reloadData];
}



- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
    CGSize tmpSize = CGSizeZero;
    if (self.isBeyondLimitWidth == NO) {
        tmpSize = CGSizeMake(self.frame.size.width / self.tagTitleArray.count, self.frame.size.height);
    }
    else {
        NSString *titleStr = self.tagTitleArray[indexPath.row];
        CGFloat titleWidth = [titleStr boundingRectWithSize:CGSizeMake(MAXFLOAT, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:kFJSegmentedTitleFontSize} context:nil].size.width;
        tmpSize = CGSizeMake(titleWidth, self.frame.size.height);
    }
    return tmpSize;
}


- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section   {
    CGFloat edgeSpacing = 0;
    if (self.isBeyondLimitWidth) {
        edgeSpacing = kFJSegmentedTagSectionHorizontalEdgeSpacing;
    }
    return UIEdgeInsetsMake(0, edgeSpacing, 0, edgeSpacing);
}

** 2. 确保indicatorView准确

// 更新 指示view  宽度
- (void)updateIndicatorWidthWithSelectedIndex:(NSInteger)selectedIndex {

    NSString *tagTitle = [self.tagTitleArray objectAtIndex:selectedIndex];

    CGFloat titleWidth = [self titleWidthWithTitle:tagTitle];

    self.indicatorWidth = titleWidth + kFJSegmentedIndicatorViewExtendWidth;
    CGRect tmpFrame = self.indicatorView.frame;
    tmpFrame.size.width = self.indicatorWidth;
    self.indicatorView.frame = tmpFrame;

    if (self.isBeyondLimitWidth) {
    
        //获取cell
        UICollectionViewCell *cell = [self.tagCollectionView cellForItemAtIndexPath:[NSIndexPath indexPathForRow:self.selectedIndex inSection:0]];
        //获取cell在当前collection的位置
        CGRect cellInCollection = [self.tagCollectionView convertRect:cell.frame toView:self.tagCollectionView];
    
        //获取cell在当前屏幕的位置
        CGRect cellInSuperview = [self.tagCollectionView convertRect:cellInCollection toView:self];
    
        CGFloat indicatorViewX = cellInSuperview.origin.x - kFJSegmentedIndicatorViewExtendWidth/2.0f;
        if (indicatorViewX < 0) {
            indicatorViewX = kFJSegmentedTagSectionHorizontalEdgeSpacing - kFJSegmentedIndicatorViewExtendWidth/2.0;
        }
        [self updateIndicatorViewWithOriginX:indicatorViewX];
    }
    else {
        CGFloat cellWidth = self.frame.size.width / self.tagTitleArray.count;
        CGFloat indicatorViewX = cellWidth * selectedIndex + cellWidth/2.0 - self.indicatorView.frame.size.width/2.0;
        [self updateIndicatorViewWithOriginX:indicatorViewX];
    }
}

F. FJSegmentedPageContentView

主要利用UICollectionView来显示分类类别视图,主要处理和FJSegmentdPageViewController参数的传递,以及分类栏头部和分类类别视图的同步问题。

** 1. FJSegmentdPageViewController 参数传递

- (void)generateViewControllerArrayWithViewArray:(NSArray *)viewArray {

    if (self.viewControllerArray.count == 0) {
        [viewArray enumerateObjectsUsingBlock:^(FJConfigModel *obj, NSUInteger idx, BOOL * _Nonnull stop) {
            Class clazz = NSClassFromString(obj.viewControllerStr);
            FJSegmentdPageViewController *baseViewController = [[clazz alloc] init];
            baseViewController.currentIndex = idx;
            baseViewController.pageViewControllerParam = obj.pageViewControllerParam;
            [self.viewControllerArray addObject:baseViewController];
        }];
    }
}

** 2. 分类栏头部和分类类别视图的同步问题

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {

    NSInteger index = (NSInteger)roundf(scrollView.contentOffset.x / self.pageCollectionView.frame.size.width);
    if (self.delegate && [self.delegate respondsToSelector:@selector(detailContentView:selectedIndex:)]) {
        [self.delegate detailContentView:self selectedIndex:index];
    }
}

G. FJSegmentdPageViewController

分类类别视图主要通过tableView来展示类别内容,同时通过监听和通知判断当前滑动事件响应者以及返回顶部事件。

1. 通过监听和通知判断当前滑动事件响应者

/************************ UIScrollViewDelegate **********************/

- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
    if (!self.isEnableScroll) {
        [scrollView setContentOffset:CGPointZero];
    }
    CGFloat offsetY = scrollView.contentOffset.y;
    if (offsetY < 0) {
        [[NSNotificationCenter defaultCenter] postNotificationName:kLeaveTopNotificationName object:[NSNumber numberWithBool:YES] userInfo:nil];
    }
}

#pragma mark --- noti method
- (void)acceptMsg:(NSNotification *)notification {
    NSString *notificationName = notification.name;
    if ([notificationName isEqualToString:kGoTopNotificationName]) {
        NSNumber *tmpNum = (NSNumber *)notification.object;
        if (tmpNum.boolValue == YES) {
            self.enableScroll = tmpNum.boolValue;
            self.tableView.showsVerticalScrollIndicator = YES;
        }
    }else if([notificationName isEqualToString:kLeaveTopNotificationName]){
        self.tableView.contentOffset = CGPointZero;
        self.enableScroll = NO;
        self.tableView.showsVerticalScrollIndicator = NO;
    }
}

2. 返回顶部通知响应

// 滚动 到 顶部
- (void)tableViewScrollToTop:(NSNotification *)noti {
    if ([noti.name isEqualToString:kFJSubScrollViewScrollToTopNoti]) {
        NSString *selectedIndex = (NSString *)noti.object;
        if ([selectedIndex isKindOfClass:[NSString class]]) {
            if ([selectedIndex integerValue] == self.currentIndex) {
                [self scrollToTopAnimated:YES];
            }
        }
    }
}

H. FJBaseTableView

FJSegmentdPageViewControllertableView,主要通过函数- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer来让tableView可以响应多个手势。

// 当有 多个手势 都可以 响应
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {

    // 防止 tableView 左右滑动 还可以 上下滑动
    if ([otherGestureRecognizer.view isKindOfClass:[UICollectionView class]]) {
        return NO;
    }

    return YES;
}

四. 写在最后

16_21128_7.jpg

gitHub 链接:FJSegmentedPager

静态:手动将FJSegmentedPager文件夹拖入到工程中。
动态:CocoaPods:pod 'FJSegmentedPager', '~> 1.0.0

大家有兴趣可以看一下,如果觉得不错,麻烦给个喜欢或star,若发现问题或是其他好的想法请及时告知,谢谢!

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

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 11,943评论 4 60
  • 来阜平已经快两个月了,跟他熟络的日子顶多一个月。从第一次全校教职工大会,他笑着打哈哈走进来坐在我的前排,眼神对视了...
    三分之一小姐阅读 314评论 0 0