FJImageBrowser图片浏览器

一.框架介绍

由于项目需求,然后也没有找到完全合适的第三方,所以自己写了一个图片浏览器,后来公司几个项目都用到了这个图片浏览器,为了适应各种产品需求,较之前添加了些功能,主要支持:

1.支持模仿微博的直接动画放大功能;
2.支持模仿微信的当下载中的时候,居中显示,下载完成放大,如果已经下载,直接动画放大。
3.支持本地图片和网络图片的混搭,比如说聊天页面有自己发送的本地图片和别人发过来的网络图片,这个框架会自动判断。
4.支持图片复用,一次只加载三张图片,优化内存
5.支持长图、动态图、下载进度显示

二.效果图

当时项目需求如图所示,由于大部分第三方回去的时候会存在抖动问题,所以当时自己简单写了个浏览器,后来其他项目也用到了,所以做了扩展和优化,进行了图片复用,一次只加载三张图片,优化了内存,同时支持长图和动态图,以及进度下载进度显示。

1.UIScrollView 效果图:


UIScrollView_example.gif

2.UICollectionView 模仿微博模式 效果图:


UICollectionView_微博模式.gif

3.UICollectionView 模仿微信模式 效果图:


UICollectionView_微信模式.gif

二.实现方法

(1).创建FJPhotosView实例

FJPhotosView *photosView = [[FJPhotosView alloc] init];
// self.imageArray:              大图url数组 
// selectedIndex:                当前选中图片索引 
// photoViewShowType:            显示模式 
[photosView setParam:self.bigImageArray selectedIndex:indexPath.row photoViewShowType:self.switchShowBtn.selected];
// 设置代理 
photosView.delegate = self;
// 展示图片浏览器
 [photosView show];

其中:

// 显示 模式
typedef NS_ENUM(NSInteger, PhotoViewShowType){
    // 模仿微博显示
    PhotoViewShowTypeOfWeiBo = 0,
    // 模仿微信显示
    PhotoViewShowTypeOfWeiXin = 1,
};

如果

(2).实现代理方法 -- FJPhotosViewDelegate

// 返回临时占位图片(即原来的小图)

- (UIImageView *)photoBrowser:(FJPhotosView *)browser placeholderImageForIndex:(NSInteger)index { 
     //获取占位小图代码;
} 

// 返回临时占位图片位置

-(CGRect)photoBrowser:(FJPhotosView *)browser targetRectForIndex:(NSInteger)index {
     //获取占位图片位置代码;
}

三.代码解析

1.架构解析

A.FJPhotosView:

a.FJPhotosView图片浏览器入口,加载在[UIApplication sharedApplication].keyWindow上,这样可以有效的避免消失时的抖动情况。
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {

        self.backgroundColor = [UIColor blackColor];
    
        self.frame = [UIApplication sharedApplication].keyWindow.bounds;
    
        [[UIApplication sharedApplication].keyWindow addSubview:self];
    }
    return self;
}

b.FJPhotosView拥有一个最外围UIScrollView负责容纳显示视图和一个UILabel负责显示当前序号,然后根据传入的参数进行初始化

  • 主要参数:

      // titleLabel :展示当前页数和总页数
      @property (nonatomic, strong) UILabel *titleLabel;
    
      // UIScrollView: 加载3张展示的视图
      @property (nonatomic, strong) UIScrollView *scrollView;
    
      // photoView array (FJPhotoScrollView 数组)
      @property (nonatomic, strong) NSMutableArray *photoViewArray;
    
      // imageurl array      (imageUrl 数组)
      @property (nonatomic, strong) NSMutableArray *photoImageUrlArray;
    
  • 主要函数:

    //初始化PhontoView(只加载三张展示图)
    - (void)setupPhotoViews {
      if (self.photoImageUrlArray.count > 0) {
        for (NSInteger i = 0; i < 3; i++) {
              FJPhotoScrollView *photoView = [[FJPhotoScrollView alloc] initWithFrame:CGRectMake(self.scrollView.width * i, 0, self.scrollView.width, self.scrollView.height)];
              photoView.delegate = self;
              photoView.parentPhotosView = self;
              [self.scrollView addSubview:photoView];
              [self.photoViewArray addObject:photoView];
            }
            [self setupAvailalbePhotoView];
        }  
      }
    

    根据点击的selectIndex加载前后的两张视图

     // 初始化 可视 photoView
      - (void)setupAvailalbePhotoView {
    
          if (_selectedIndex >= self.photoImageUrlArray.count) {
              _selectedIndex = 0;
          }
          //点击第一张
          if (_selectedIndex == 0) {
              for (NSInteger tmpIndex = 0; tmpIndex < 3; tmpIndex++) {
          
                  if (tmpIndex >= self.photoImageUrlArray.count) {
                      break;
                  }
          
                  if (tmpIndex == 0) {
                      _transferPhotoView = [self.photoViewArray  objectAtIndex:tmpIndex];
                  }
          
                  [self configContentWithPage:tmpIndex photoView:[self.photoViewArray  objectAtIndex:tmpIndex]];
              }
          }
          else if (_selectedIndex == (self.photoImageUrlArray.count - 1)) {//点击最后一张
      
              NSInteger tempIndex = 0;
      
              for (NSInteger index = (self.photoImageUrlArray.count - 1);index >= (self.photoImageUrlArray.count - 3); index--) {
                  if (index < 0) {
                      continue;
                  }
          
                  if (index == _selectedIndex) {
                      _transferPhotoView = [self.photoViewArray  objectAtIndex:tempIndex];
                  }
                  [self configContentWithPage:index photoView:[self.photoViewArray  objectAtIndex:tempIndex++]];
              }
          }
          //点击中间图片
          else {
              if (self.photoViewArray.count > 2) {
                  _transferPhotoView = [self.photoViewArray  objectAtIndex:1];
                  //先加载中间
                  [self configContentWithPage:_selectedIndex photoView:[self.photoViewArray  objectAtIndex:1]];
          
                  [self configContentWithPage:_selectedIndex - 1 photoView:[self.photoViewArray  objectAtIndex:0]];
          
                  [self configContentWithPage:_selectedIndex + 1 photoView:[self.photoViewArray  objectAtIndex:2]];
              }
          }
    
          if (self.photoImageUrlArray.count > 1) {
              self.titleLabel.text = [NSString stringWithFormat:@"%@/%ld",@(_selectedIndex+1),     (long)self.photoImageUrlArray.count];
          }
    
          self.scrollView.contentSize = CGSizeMake(self.photoImageUrlArray.count * FW(self.scrollView), self.scrollView.bounds.size.height);
    
          [self.scrollView scrollRectToVisible:CGRectMake(_selectedIndex * FW(self.scrollView), 0, FW(self.scrollView), FH(self.scrollView)) animated:NO];
      }
    

    将相应的参数传给FJPhotoScrollView,让FJPhotoScrollView进行图片的显示

         // 配置 相关 图片
      - (void)configContentWithPage:(NSInteger)page photoView:(FJPhotoScrollView*)photoView {
          id variable = [self.photoImageUrlArray  objectAtIndex:page];
          [photoView setParamWithVariable:variable currentIndex:page photoViewShowType:_photoViewShowType];
          photoView.frame = CGRectMake(page * FW(_scrollView), FY(photoView), FW(photoView), FH(photoView));
          photoView.backgroundColor = [UIColor blackColor];
      }
    

    通过 UIScrollViewDelegate 进行图片的缩放

      // 图片 放大 缩小
      - (void)scrollViewDidZoom:(FJPhotoScrollView *)photoView {
          if (photoView == self.scrollView){
              return;
          }
    
          CGSize boundsSize = self.scrollView.bounds.size;
          CGRect contentsFrame = photoView.myImageView.frame;
    
          if (contentsFrame.size.width < boundsSize.width) {
      
              contentsFrame.origin.x = (boundsSize.width - contentsFrame.size.width) / 2.0f;
          }
          else {
              contentsFrame.origin.x = 0.0f;
          }
    
          if (contentsFrame.size.height < boundsSize.height) {
      
              contentsFrame.origin.y = (boundsSize.height - contentsFrame.size.height) / 2.0f;
          }
          else {
              contentsFrame.origin.y = 0.0f;
          }
    
          photoView.myImageView.frame = contentsFrame;
    
      }
    
      图片滚动加载前后图片
    
      // 图片 滚动
      - (void)scrollViewDidScroll:(UIScrollView *)aScrollView {
    
          static NSInteger temp_lastPage = -1;
    
          CGFloat pageWidth = self.scrollView.frame.size.width;
    
          NSInteger page = floor((self.scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
    
          NSInteger photoCount = [self.photoImageUrlArray count];
    
          if (page >= photoCount) {
              return;
          }
    
          _currentSelectIndex = page;
    
          _titleLabel.text = [NSString stringWithFormat:@"%ld/%ld",(long)page+1, (long)photoCount];
    
          if (aScrollView == self.scrollView && temp_lastPage!=page) {
      
              if (_currShowImageIndex > -1 && _currShowImageIndex < 3) {
          
                  FJPhotoScrollView *subPhotoScrollView = [self.photoViewArray  objectAtIndex:_currShowImageIndex];
          
                  subPhotoScrollView.zoomScale = 1;
          
                  temp_lastPage = page;
                }
          }
    
          if (aScrollView != self.scrollView) {
              return;
          }
    
          if (_lastPage != page) {
      
              for (NSInteger i = 0; i<[self.photoViewArray count]; i++) {
          
                  FJPhotoScrollView *tmpPhotoScrollView = [self.photoViewArray  objectAtIndex:i];
          
                  if (FX(tmpPhotoScrollView) == page * FW(aScrollView)) {
              
                      _currShowImageIndex = i;
              
                      break;
                  }
              }
      
              if (page > 0 && page < self.photoImageUrlArray.count - 1) {
          
                  for (NSInteger i = 0; i < 3; i++) {
              
                      UIImageView *tmpImageView = [self.photoViewArray  objectAtIndex:_currShowImageIndex];
              
                      FJPhotoScrollView *tmpPhotoScrollView = [self.photoViewArray  objectAtIndex:i];
                      //加载下一页
                      if ((FX(tmpImageView) - FX(tmpPhotoScrollView)) > FW(self.scrollView)) {
                  
                          [self configContentWithPage:page + 1 photoView:tmpPhotoScrollView];
                  
                      }
                      //加载上一页
                      else if ((FX(tmpPhotoScrollView) - FX(tmpImageView)) > FW(self.scrollView)) {
                  
                          [self configContentWithPage:page - 1 photoView:tmpPhotoScrollView];
          
                      }
                  }
              }
              _lastPage = page;
          }
          aScrollView.userInteractionEnabled=YES;
      }
    

B.FJPhotoScrollView:

a.FJPhotoScrollView继承自FJBaseScrollView,本身是一个UIScrollView,拥有myImageView(主展示图)、originalImageView(占位小图)和progressLayer(进度条):

// 展示图
@property(nonatomic, strong)  UIImageView *myImageView;
// 进度条
@property (nonatomic, strong) CAShapeLayer *progressLayer;
// 占位图
@property (nonatomic, strong) UIImageView *originalImageView;

b.FJPhotoScrollView通过设置参数函数进行图片类型判断、动画效果选择、下载进度显示。
核心函数:
// 设置相关参数
- (void)setParamWithVariable:(id)variable currentIndex:(NSInteger)currentIndex photoViewShowType:(PhotoViewShowType)photoViewShowType {

    //初始位置
    _variable = variable;
    self.currentIndex = currentIndex;
    // 获取原图位置
    CGRect originalRect = [self targetRectForIndex:currentIndex];
    self.myImageView.frame = originalRect;
    // 获取 临时占位图
    self.originalImageView = [self placeholderImageForIndex:currentIndex];

    // 微博 显示 方式 (直接放大)
    if (photoViewShowType == PhotoViewShowTypeOfWeiBo) {
    
        [self showDirectlyAmplifyPhotoViewAnimation:_variable];
    }

    // 微信 显示 方式 (加载完成后 放大)
    else if(photoViewShowType == PhotoViewShowTypeOfWeiXin && [self isImageUrl:variable]) {
        // 图片未下载 先显示在 中部
        NSString *tmpImageUrl = (NSString *)variable;
        if ([self.myImageView exitCurrentImage:tmpImageUrl] == NO) {
            [UIView animateWithDuration:FJDefaultAnimationTime animations:^{
            
                [self setMyimageViewInTheMiddle:self.originalImageView];
            
            } completion:^(BOOL finished) {
            
                [self showImageViewDowningProgerss:tmpImageUrl isAnimation:YES];
            }];
        }
        // 图片已下载 直接放大
        else {
            [self showDirectlyAmplifyPhotoViewAnimation:_variable];
        }
    }
}

variable 之所以是id类型,主要是为了做本地图片和网络图片的兼容,通过函数isImageUrl判断是否为网络图片:

// 判断 是否 为 网络 图片
- (BOOL)isImageUrl:(id)variable {
    BOOL isImageUrl = NO;
    // NSString 类型
    if ([variable isKindOfClass:[NSString class]]) {
        NSString *tmpStr = (NSString *)variable;
        isImageUrl = [tmpStr isHttpUrl];
    }
    return isImageUrl;
}

如果非网络图片就是本地图片,本地图片就直接动画放大显示,如果是网络图片,判断是否下载,如果未下载,判断如果是微信模式,就先居中显示,然后去下载,如果是微博模式,就直接放大下载。

// 显示 直接 放大 图片 动画
- (void)showDirectlyAmplifyPhotoViewAnimation:(id)variable {

    [UIView animateWithDuration:FJDefaultAnimationTime animations:^{
    
        [self setFrameAndZoom:self.originalImageView];
    
    } completion:^(BOOL finished) {
    
        self.userInteractionEnabled = YES ;
        // 网络 图片
        if ([self isImageUrl:variable]) {
        
            [self showImageViewDowningProgerss:(NSString *)_variable isAnimation:NO];
        
        }
        // 本地 图片
        else {
            //变换完动画 从网络开始加载图
            self.myImageView.image = [self getImage:variable];
            [self setFrameAndZoom:self.myImageView];//设置最新的网络下载后的图的frame大小
        }
    }];
}

网络图片显示下载进度,下载完成后动画展现

// 显示 下载进入和 下载完成 展现 动画
- (void)showImageViewDowningProgerss:(NSString *)imageUrl isAnimation:(BOOL)isAnimation{
    //变换完动画 从网络开始加载图
    NSString *imageUrlStr = [[imageUrl stringByReplacingOccurrencesOfString:@"\\" withString:@""] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    [self.myImageView sd_setImageWithURL:[NSURL URLWithString:imageUrlStr] placeholderImage:self.myImageView.image       options:SDWebImageRetryFailed|SDWebImageLowPriority progress:^(NSInteger receivedSize, NSInteger expectedSize) {
    
        if (receivedSize > 0 && expectedSize > 0) {
            CGFloat progress = receivedSize / (float)expectedSize;
            progress = progress < 0.01 ? 0.01 : progress > 1 ? 1 : progress;
            if (isnan(progress)) progress = 0;
            self.progressLayer.hidden = NO;
            self.progressLayer.strokeEnd = progress;
        }
    
    } completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
    
        self.progressLayer.hidden = YES;
        if (isAnimation) {
            [UIView animateWithDuration:FJDefaultAnimationTime animations:^{
                [self setFrameAndZoom:self.myImageView];
            }];
        }
        else {
             [self setFrameAndZoom:self.myImageView];
       }
    }];
}

微信模式未下载情况先显示在中间函数:

// 微信 模式 还没下载完成 显示在中间
- (void)setMyimageViewInTheMiddle:(UIImageView *)imageView {
    //设置空image时的情况
    //ImageView.image的大小
    CGFloat   imageH;
    CGFloat   imageW;

    if(imageView == nil) {
    
        imageH = self.myImageView.height;
        imageW = self.myImageView.width;
    
        self.myImageView.image = IMG(@"default_avatar_geren_134.png");
    
    }
    else {
        imageW  = imageView.width;
        imageH = imageView.height;
    
        if (imageW < 0.5 || imageH < 0.5) {
        
            imageH = self.myImageView.height;
            imageW = self.myImageView.width;
        }
        self.myImageView.image = imageView.image;
    }

    if (imageW < 0.5 || imageH < 0.5) {
        imageH = SCREEN_WIDTH / 2.5;
        imageW = SCREEN_WIDTH / 2.5;
    }
    CGFloat imageX = (SCREEN_WIDTH/2.0) - (imageW/2.0);
    CGFloat imageY = (SCREEN_HEIGHT/2.0) - (imageH/2.0);

    self.myImageView.frame = CGRectMake(imageX, imageY, imageW, imageH);
}

下载完成后或是本地图片直接放大以及图片缩放被说计算函数:

// 微博 模式 直接 放大
-(void)setFrameAndZoom:(UIImageView *)imageView {

    //ImageView.image的大小
    CGFloat   imageH;
    CGFloat   imageW;


    //设置空image时的情况
    if(imageView.image == nil || imageView.image.size.width == 0 || imageView.image.size.height == 0) {
        //设置主图片
        imageH = SCREEN_HEIGHT;
        imageW = SCREEN_WIDTH;
        self.myImageView.image = IMG(@"default_avatar_geren_134.png");
    
    }
    //不空
    else{
        //设置主图片
        imageW  = imageView.image.size.width;
       imageH = imageView.image.size.height;
        self.myImageView.image = imageView.image;
    }

    //设置主图片Frame 与缩小比例
    //横着
    if(imageW >= (imageH * (SCREEN_WIDTH/SCREEN_HEIGHT))){
    
        //设置居中frame
        CGFloat  myX_ =  0;
        CGFloat  myW_ = SCREEN_WIDTH;
        CGFloat  myH_  = myW_ *(imageH/imageW);;
        CGFloat  myY_ = SCREEN_HEIGHT - myH_ - ((SCREEN_HEIGHT - myH_)/2);
    
        self.myImageView.frame = CGRectMake(myX_, myY_, myW_, myH_);
        if (myH_ > SCREEN_HEIGHT) {
            self.contentSize = CGSizeMake(SCREEN_WIDTH, myH_);
        }

        //判断原图是小图还是大图来判断,是可以缩放,还是可以放大
        if (imageW >  myW_) {
            self.maximumZoomScale = 3*(imageW/myW_ ) ;//放大比例
        
          }
        else{
            self.minimumZoomScale = (imageW/myW_);//缩小比例
        
        }
    }
    //竖着
    else {
        CGFloat  myX_ = 0;
        CGFloat  myY_ = 0;
        CGFloat  myW_ = SCREEN_WIDTH;
        CGFloat  myH_ = floor(imageH / (imageW / self.width));
        if (myH_ > SCREEN_HEIGHT) {
            self.contentSize = CGSizeMake(SCREEN_WIDTH, myH_);
        }

        //变换设置frame
        self.myImageView.frame = CGRectMake(myX_, myY_, myW_, myH_);
    
        //判断原图是小图还是大图来判断,是可以缩放,还是可以放大
    
        if (imageH >  myH_) {
            self.maximumZoomScale =  3*(imageH/myH_ ) ;//放大比例
        
        }
        else {
            self.minimumZoomScale = (imageH/myH_);//缩小比例
        }
    }
}

实现单击,如果当前滚动到的图片在原主界面可视范围内,就动态返回原主界面当前滚动到的图片位置,如果不在当前可视范围内,就动画消失函数:
// tap事件
- (void)singleTap {
CGRect originalRect = [self targetRectForIndex:_currentIndex];
self.userInteractionEnabled = NO;
self.zoomScale = 1;

    [UIView animateWithDuration:0.5 animations:^{
        if (CGRectEqualToRect(originalRect, CGRectZero)) {
            self.alpha = 0;
        }else{
            self.myImageView.frame = originalRect;
        }
        self.superview.superview.backgroundColor = [UIColor clearColor];
        self.superview.backgroundColor = [UIColor clearColor];
        self.backgroundColor = [UIColor clearColor];
    } completion:^(BOOL finished) {
        if (self.delegate && [self.delegate respondsToSelector:@selector(scrollViewDidClick)]) {
            [self.delegate performSelector:@selector(scrollViewDidClick)];
        }
    }];
}

C.FJBaseScrollView

a.FJBaseScrollView是FJPhotoScrollView的基类,主要实现单击返回原主界面,双击将图片放大的效果,
通过touchesBegan函数来识别单击和双击:

// touch begin 标识双击和单击
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    NSTimeInterval delaytime = 0.3;
    _point = [[touches anyObject] locationInView:self];
    switch (touch.tapCount) {
        case 1:
            break;
        case 2: {
            [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(singleTap) object:nil];
            [self performSelector:@selector(doubleTap) withObject:nil afterDelay:delaytime];
            break;
        default:
            break;
        }
    }
}


// touch end
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    switch (touch.tapCount) {
        case 1:
            [self performSelector:@selector(singleTap) withObject:nil afterDelay:.2];
            break;
        default:
            break;
    }
}

双击调用缩放方法:

 // 双击
-(void)doubleTap {
    if(_isScaled == YES){
        [self zoomToPointInRootView:_point atScale:1];
        _isScaled = NO;
    }else{
        [self zoomToPointInRootView:_point atScale:2];
        _isScaled = YES;
    }
}

设置UIScrollView缩放效果:

// 放大 或 缩小
- (void)zoomToPointInRootView:(CGPoint)center atScale:(float)scale {
    CGRect zoomRect;
    zoomRect.size.height = self.frame.size.height / scale;
    zoomRect.size.width  = self.frame.size.width  / scale;
    zoomRect.origin.x    = center.x - (zoomRect.size.width  / 2.0);
    zoomRect.origin.y    = center.y - (zoomRect.size.height / 2.0);
    [self zoomToRect:zoomRect animated:YES];
}

单击调用代理动态返回原来界面:

// 单击
-(void)singleTap {
    if (self.delegate && [self.delegate respondsToSelector:@selector(scrollViewDidClick)]) {
        [self.delegate performSelector:@selector(scrollViewDidClick)];
    }
}

四.最后

送给大家一张很喜欢的图:

加油.jpg

这是gitHub链接地址,大家有兴趣可以看一下,如果觉得不错,麻烦给个喜欢或star,如果有问题请及时反馈,谢谢!

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

推荐阅读更多精彩内容