UIView的深入理解

一、自定义View需要继承UIView

@interface ZSUIView : UIView

注意的几点问题:

1.initWithFrame

init和initWithFrame都是UIView初始化方法,初始化UIView对象的时候可以通过这两种方式。(使用代码创建UIView)

//第一种方式
ZSUIView  *view=[[ZSUIView alloc]init];
view.frame=CGRectMake(100, 100, 100, 100);
//第二种方式
ZSUIView  *view=[[ZSUIView alloc]initWithFrame:CGRectMake(100, 100, 100, 100)];

init内部会调用initWithFrame,也就是无论第一种还是第二种方式都会调用initWithFrame方法,所以重写initWithFrame才能避免外部初始化UIView的局限性。

自定义初始化方法以init开头,才会调用initWithFrame。

-(instancetype)initWithData:(NSString *)data
{
    if(self=[super init])
    {
    }
    return self;
}

如果用xib创建View,会先initWithCoder方法(加载时),再调用awakeFromNib方法(加载完)。

2.layoutSubviews

用来布局子View的Frame
相比在初始化方法initWithFrame中设置子View的Frame有几点优势
a.分离布局代码,初始化方法中只会在初始化设置一次,如果想再改变需要分别设置,麻烦。
b.子View的布局可以跟随父View布局改变而改变。
其中涉及到layoutSubviews的调用机制,
addsubview的时候

ZSUIView*view=[[ZSUIView alloc]init];
[self.view addSubview:view];//ZSUIView中layoutSubviews被调用。

@implementation ZSUIView
-(void)layoutSubviews
{
    NSLog(@"%@:%@",NSStringFromClass(self.class),NSStringFromSelector(_cmd));
    [super layoutSubviews];
    self.bgview.frame=CGRectMake(10, 10, self.frame.size.width/3, self.frame.size.height/3);
}
@end

父View尺寸(不包括位置)改变的时候

- (IBAction)clickTest:(id)sender {
    CGRect viewFrame=view.frame;
    //viewFrame.origin.x+=10;  //ZSUIView中layoutSubviews不会被调用。
    viewFrame.size.width+=10; //ZSUIView中layoutSubviews被调用。
    view.frame=viewFrame;
  }

如果子View尺寸改变,父View的layoutSubviews同样也会被调用
Xib创建的自定义View同样适用。

所以,给我们布局提供的思路就是,子View的布局跟随父View布局而布局,如果父View布局改变,子View也不会太丑;做一些动态尺寸控件时候子View变化的布局写在layoutSubviews中。

3.UITextField

InPutView:默认键盘
AccessoryInputView:默认无
一个思路是继承UITextField,初始化的时候重写InPutView属性,比如改成PickerView,点击就弹出PickerView,也是自定义键盘的思路。
AccessoryInputView用来做评论回复之类的功能。

4.initWithFrame、initWithCoder、awakeFromNib

通过存代码创建View,initWithFrame被调用
通过xib,sb创建View,先调用initWithCoder,再调用awakeFromNib
此时,initWithCoder中子控件还没有创建出来(解析文件开始调用),在awakeFromNib才创建出来。

二、UIButton

1.背景图片拉伸

-(UIImage*)resizeImage
{
    UIImage *image = self;
    // 设置端盖的值
    CGFloat top = image.size.height * 0.5;
    CGFloat left = image.size.width * 0.5;
    CGFloat bottom = image.size.height * 0.5;
    CGFloat right = image.size.width * 0.5;
    // 设置端盖的值
    UIEdgeInsets edgeInsets = UIEdgeInsetsMake(top, left, bottom, right);
    // 设置拉伸的模式
    UIImageResizingMode mode = UIImageResizingModeStretch;
    // 拉伸图片
    UIImage *newImage = [image resizableImageWithCapInsets:edgeInsets resizingMode:mode];
    return newImage;
}
@end

2.调整按钮内部图片和文字的位置

    //默认图片文字左右结构,改变为右左结构
    CGRect iFrame=self.testBtn.imageView.frame;
    CGRect tFrame=self.testBtn.titleLabel.frame;
    iFrame.origin.x=CGRectGetMaxX(tFrame);
    self.testBtn.imageView.frame=iFrame;
    self.testBtn.titleLabel.frame=tFrame;

三、UIScrollView

1.contentOffset,contentInset

contentOffset是内容相对于tableview-frame起始点的偏移量;header属于tableview内容的一部分;而contentInset不属于tableview内容的一部分。
contentInset是指tableview内容的边距,除内容外还能额外看到的区域。
(做自定义下拉加载悬停就是控制这个属性值)
所以如果给tableview加一个header,默认contentOffset.y从0开始;
如果给tableview加一个contentInset.top,默认contentOffset.y从-top开始,但是从top开始显示;
有导航条的tableview,默认contentOffset.y=-navBarHeight,除非添加以下属性,保证从contentOffset.y从0开始。

if (@available(iOS 11.0, *)) {
        tv.contentInsetAdjustmentBehavior=UIScrollViewContentInsetAdjustmentNever;
    } else {
        self.automaticallyAdjustsScrollViewInsets=NO;
    }

有一些UIScrollView的contentOffset(0,0)但是还有外边框的样式UI,这样做比较符合逻辑。

2.delegate方法

-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    //1->
    NSLog(@"scrollViewWillBeginDragging");
}
-(void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
    //2->
    NSLog(@"scrollViewWillEndDragging");
}
-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
    //3->decelerate为YES 4才会被调用
   //从交互上感受就是 如果用户拖拽之后scrollview有惯性滑动才会调用减速
   //如果拖拽之后就不动了那么就不产生减速效果,也不调用减速代理方法
    NSLog(@"scrollViewDidEndDragging:%d-%f",decelerate,scrollView.contentOffset.x);
}
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    //4.
    NSLog(@"scrollViewDidEndDecelerating:%f",scrollView.contentOffset.x);
}

-(UIView*)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
    //指定scrollview哪个控件进行缩放,同时指定缩放比例就可以完成缩放功能
    //self.scrollview.maximumZoomScale=2;
    //self.scrollview.minimumZoomScale=0.5;
    return nil;
}

3.scrollsToTop

.h文件是这么描述的:
当用户点击状态栏,滑动到顶部,也可以通过scrollViewShouldScrollToTop代理设置;
默认YES;
当在屏幕上有多个UIScrollView,scrollsToTop失效,所以tableview嵌套tableview的情况,就没有scrollsToTop功能,但是如果内部tableview.scrollsToTop=NO;外部tableview.scrollsToTop=YES;就可以生效。

// When the user taps the status bar, the scroll view beneath the touch which is closest to the status bar will be scrolled to top, but only if its `scrollsToTop` property is YES, its delegate does not return NO from `-scrollViewShouldScrollToTop:`, and it is not already at the top.
// On iPhone, we execute this gesture only if there's one on-screen scroll view with `scrollsToTop` == YES. If more than one is found, none will be scrolled.
@property(nonatomic) BOOL  scrollsToTop __TVOS_PROHIBITED;          // default is YES.

四、AutoLayout

1.在xib或者sb中添加控件,默认contrain to margins是选中的,所以这就是为什么设置左边距0会有间距,取消该选中就可以了。

2.UILabel包裹内容

  • 设置UILabel的位置
  • 不设置高度约束,宽度约束设置为<=

3.约束优先级

使用场景:
三个连续相隔20pt的View,如果做到去掉中间的View,右侧的View靠近左侧View20pt。
对右侧的View进行左侧View和中间View20pt的两个约束(当然会报错),只需要把左侧View20pt的约束优先级调整低就不会出错,而且实现该需求。

4.修改约束

把约束拖拽到控制器进行修改。

//约束的改变本质也是改变view的frame
self.grayviewheight.constant=100;
//给改变约束添加动画的方式->
    [UIView animateWithDuration:2.0 animations:^{
  //强制self.view的子控件布局刷新
        [self.view layoutIfNeeded];
    }];

效果相当于

CGRect grayFrame=self.grayview.frame;
grayFrame.size.width=100;
[UIView animateWithDuration:2.0 animations:^{
self.grayview.frame=grayFrame;
}];

5.Masonry

如果你的控件是代码创建的,还需要添加约束,那么->masonry。

  • 给一个UIView添加约束,先添加该UIView,再添加约束。
UIView * mview=[[UIView alloc]init];
mview.backgroundColor=[UIColor orangeColor];
[self.view addSubview:mview];
[mview mas_makeConstraints:^(MASConstraintMaker *make) {}
  • 基本思路就是相对于x控件的偏移约束是x
[mview mas_makeConstraints:^(MASConstraintMaker *make) {
        //1.0 mview左边相对于self.view的左边距离20pt,右边底边距离20,高度100
        make.left.equalTo(self.view.mas_left).offset(20);
        make.right.equalTo(self.view.mas_right).offset(-20);
        make.bottom.equalTo(self.view.mas_bottom).offset(-20);
        make.height.mas_equalTo(100);
        
        //1.1 左边相对于左边则可以省略不写,mas_equalTo包含equalTo
        make.left.mas_equalTo(self.view).offset(20);
        make.right.mas_equalTo(self.view).offset(-20);
        make.bottom.mas_equalTo(self.view).offset(-20);
        make.height.mas_equalTo(100);
        
        //1.2 相对于父控件可以省略不写
        make.left.offset(20);
        make.right.offset(-20);
        make.bottom.offset(-20);
        make.height.mas_equalTo(100);
        
        //1.3 距离相等可以并列写
        make.left.offset(20);
        make.right.bottom.offset(-20);
        make.height.mas_equalTo(100);
        
        //1.3 距离相等可以并列写
        make.left.offset(20);
        make.right.bottom.offset(-20);
        make.height.mas_equalTo(100);
    }];

MASConstraintMaker定义的其他属性可以查看MasonrySDK(反正也是开源的)

  • 更新约束并且添加动画
[mview mas_updateConstraints:^(MASConstraintMaker *make) {
        make.height.mas_equalTo(200);
    }];
    
    [UIView animateWithDuration:1.0 animations:^{
        [self.view layoutIfNeeded];
    }];

6.UITableView

  • cell中的contentView作用是更容易做侧滑删除,收藏。
  • cell真实的frame
    cell:
- (void)awakeFromNib {
    [super awakeFromNib];
    //cell在xib本身定义宽度 
    //NSLog(@"布局cell.width:%f-contentView.width%f",self.frame.size.width,self.contentView.frame.size.width);
}
//父控件尺寸确定好才会调用
-(void)layoutSubviews
{
    //tableview的宽度
    //NSLog(@"布局cell.width:%f-contentView.width%f",self.frame.size.width,self.contentView.frame.size.width);
}

vc:

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//开始是cell在xib中定义的宽度,滑动到第二次加载该view的时候才是tableview的宽度
    ZSTableViewCell * cell=[tableView dequeueReusableCellWithIdentifier:@"cell"];
    NSLog(@"代理方法cell.width:%f-contentView.width%f",cell.frame.size.width,cell.contentView.frame.size.width);
    return cell;
}

所以在cell的layoutSubviews方法中才能拿到实际的frame

  • 静态Cell
    a.创建storyborad,拖一个uitableviewcontroller到sb中。
    b.改变该uitableview类型为static cells,并指定uitableviewcontroller标识。
    c.创建控制器和该uitableviewcontroller关联。
    d.代码跳转
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"sb名称" bundle:nil];
    StaticCellTableViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"tvc标识"];
    [self presentViewController:vc animated:YES completion:nil];
  • 调用顺序
    tableview第一次创建出来:
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"heightForRowAtIndexPath");
    return 50;
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"cellForRowAtIndexPath");
    ZSTableViewCell * cell=[tableView dequeueReusableCellWithIdentifier:@"cell"];
    cell.name=@"";
    return cell;
}
- (void)awakeFromNib {
    [super awakeFromNib];
    NSLog(@"awakeFromNib");
}

-(void)layoutSubviews
{
    NSLog(@"layoutSubviews");
}
-(void)setName:(NSString *)name
{
    NSLog(@"setName");
    _name=name;
}

tableview:heightForRowAtIndexPath(可见范围内的)->
tableview:cellForRowAtIndexPath->
cell:awakeFromNib->
tableview:setData->
cell:layoutSubviews

cellForRowAtIndexPath优先于awakeFromNib,是因为[tableView dequeueReusableCellWithIdentifier:@"cell"]的方法内部让cell初始化;
setData方法优先于layoutSubviews,是因为在每个cellForRowAtIndexPath方法执行完毕才添加该cell到tableview中;
cell:awakeFromNib只会在第一次创建时候调用,原因是tableview复用机制。

所以在layoutSubviews使用模型不会有问题,也能解释为什么layoutSubviews中才能获取真正cell的frame。
  • 不定行高的cell的警告可以通过修改约束优先级擦除。
  • tableview局部刷新的前提是要保证数组数据长度不变,除非使用
self.tableview insertSections:<#(nonnull NSIndexSet *)#> withRowAnimation:<#(UITableViewRowAnimation)#>

self.tableview deleteSections:<#(nonnull NSIndexSet *)#> withRowAnimation:<#(UITableViewRowAnimation)#>

  • cell侧滑按钮设置
    a.只实现单一按钮功能,比如删除
//实现这两个代理
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"删除改行");
}

-(NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return @"删除";
}

b.实现侧滑多按钮功能

-(NSArray<UITableViewRowAction*>*)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewRowAction * row1=[UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"编辑" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {
        NSLog(@"编辑");
    }];
    
    UITableViewRowAction * row2=[UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"删除" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {
        NSLog(@"删除");
    }];
    
    row2.backgroundColor=[UIColor blueColor];
    return @[row1,row2];
}
  • 多cell选中功能
//1.设置属性
self.tableView.allowsMultipleSelectionDuringEditing=YES;
//2.进入tableview编辑模式
 [self.tableView setEditing:YES animated:YES];
//3.获得选中cell的indexPath
NSArray<NSIndexPath*> * selectedRows=self.tableView.indexPathsForSelectedRows;
//注意点:
//批量删除注意点,删除数组中的模型,而不是直接删除对应index,因为删除一个index的元素时,整体数组index会改变
  • 分割线通栏
cell.layoutMargins=UIEdgeInsetsZero;//iOS(8.0)
  • 解决xib初始化控件尺寸的拉伸问题
- (void)awakeFromNib {
    [super awakeFromNib];
    self.autoresizingMask=UIViewAutoresizingNone;
}
  • 解决UITableView刷新跳动问题
if (@available(iOS 11.0, *)) {
        UITableView.appearance.estimatedRowHeight = 0;
        UITableView.appearance.estimatedSectionFooterHeight = 0;
        UITableView.appearance.estimatedSectionHeaderHeight = 0;
    }

7.使用技巧

a.StackView很好用,但是只能是IOS9.0以后。
b.比例控件
xib中控件可以通过向父控件拖拽equal width或者height,然后调节比率完成按照比例实现控件宽高。也可以向自己拖拽aspect ratio属性,控制控件自己的宽高比。
c.居中偏差
控件先horizontally or verticality in container,然后对约束Edit,调整constant的值,让控件按居中位置偏移。
d.实现多个View平分的效果,可以使用辅助View,设置各个View间距为0,然后隐藏掉辅助控件。
e.A B 垂直或者水平中心对齐,可以拖拽B到A身上,也可以多选A,B选择horizontal/vertical centers。

五、CALayer

1.CATransform3D是layer比UIView拓展的属性,支持3D形变。

2.position和anchorPoint

  • 概念:
    position->用来设置CALayer在父层中的位置
    anchorPoint->决定CALayer身上哪个点会在position所指的位置,默认(0.5,0.5)范围0-1

  • 修改anchorPoint的值,position不改变。
    比如:在控制器View上添加一个View,frame是(100,100,100,100)
    View的中心点center=layer.position是(150,150),锚点是(0.5,0.5)
    如果修改锚点值为(0,0),position(150,150)-(当前View左上角),frame变成(150,150,100,100)
    修改anchorPoint为(0,0)->position不变,(150,150)点固定,如果想要保证position所指的位置在修改后的锚点在左上角(0,0),那么自然UIView要向右下方向移动。
    如果修改锚点值为(1,1),position(150,150)-(当前View右下角),frame变成(50,50,100,100)

  • 作用:
    使用旋转动画的话,锚点是旋转点中心点位置,默认是中心旋转,如果设置为(0,0),以左上角为中心点旋转。

3.隐式动画

每一个UIView都关联一个CALayer,默认是RootLayer。
所有非RootLayer,手动创建的CALayer,都有隐式动画。

4.核心动画CAAnimation

CABasicAnimation

    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
    animation.delegate=self;
    //动画选项的设定
    animation.duration = 2.5; // 持续时间
    animation.repeatCount = 1; // 重复次数
    // 起始帧和终止帧的设定
    animation.fromValue = [NSValue valueWithCGPoint:self.phoneBtn.layer.position]; // 起始帧
    animation.toValue = [NSValue valueWithCGPoint:CGPointMake(320, 480)]; // 终止帧
    //动画结束停在终止帧位置
    animation.removedOnCompletion = NO;
    animation.fillMode=kCAFillModeForwards;
    // 添加动画
    [self.phoneBtn.layer addAnimation:animation forKey:@"move-layer"];

CAKeyframeAnimation

    CAKeyframeAnimation * key=[CAKeyframeAnimation animation];
    UIBezierPath * path=[UIBezierPath bezierPath];
    [path moveToPoint:CGPointMake(0, 0)];
    [path addLineToPoint:CGPointMake(1, 1)];
    key.path=path.CGPath;
    key.rotationMode=@"autoReverse";
    [self.phoneBtn.layer addAnimation:key forKey:@"move-layer"];

CATransition
页面翻页各种效果

UIView动画和CA核心动画区别
  • UIView动画是对该UIView的属性进行改变的延时效果
常用属性比如改变frame,transform,alpha。

改变属性的相互响应:

1.当一个view的frame被更改时
a.当更改size时,它的bounds的width和height会被更改为与frame的size一致,但是bounds的origin不会被更改。view的center,layer的position可能会被更改。
b.当更改origin时,对bounds属性无影响。view的center,layer的position可能会被更改。

2.当一个view的bounds被更改时
a.当更改size时,frame的width和size会改为同bounds的size一致,frame的origin有可能更改(取决于layer的anchorPoint)。view的center,layer的position可能会被更改不会更改。
b.当更改origin时,frame无影响,view的center,layer的position不会更改。

3.当view的center更改时
frame的origin会更改,layer的position会更改。

4.当一个view的transform被更改了,即不为CGAffineTransformIdentity。
frame属性可能会更改,view的bounds,center不会变,layer的position不会变。这个很重要,这样保持了在transform后,view的frame虽然改变了,但是内部参考系是不变的,可以继续进行其他变换,只要不更改frame或center或layer的position。

CA核心动画对该UIView的属性不改变(比如一个位移动画让UIView改变位置只是看起来改变了,其实位置还在初始点位置,点击原始位置才会有响应,点击看到UIView的终止帧位置没响应,是一种动画假象)

  • UIView是直接作用在该UIView属性上的,CA核心动画作用在CALayer上
  • 一般有交互事件的UIView,尤其是位移改变还做交互的UIView不做CA核心动画,单纯的帧动画或者转场效果可以做CA核心动画。

UIView物理动画

[UIViewanimateWithDuration:1.0delay:2.0usingSpringWithDamping:0.5initialSpringVelocity:0.1options:UIViewAnimationOptionTransitionFlipFromTopanimations:^{
CGRectviewFrame =_view3.frame;
viewFrame.origin.x+=transweight;
_view3.frame=viewFrame;
}completion:nil];

六、UIImageView

1.显示部分图片(截取图片指定区域显示到当前UIImageView上)

//截取图片上半部分填充到testImg中
self.testImg.layer.contentsRect=CGRectMake(0, 0, 1, 0.5);

2.最近项目中有关于自定义相机以及对拍完照片裁剪的一些问题,总结出来和大家分享一下。

http://www.cocoachina.com/ios/20150605/12021.html

3.UIImageView的contentMode

typedef NS_ENUM(NSInteger, UIViewContentMode) {
//如果包含Scale,按照ImageView尺寸进行填充
    UIViewContentModeScaleToFill, //完全按照ImageView尺寸填充(不会超出ImageView尺寸)
    UIViewContentModeScaleAspectFit, //按照原始图像宽高比在ImageView尺寸内填充(不会超 出ImageView尺寸)
    UIViewContentModeScaleAspectFill, //按照原始图像宽高比填充,使得宽度或者长度等于 ImageView尺寸的宽度或者长度(可能超出ImageView尺寸)
//如果不包含Scale,按照图像原始比例进行填充,结合clipsToBounds属性,保证不超出UIImageView尺寸
    UIViewContentModeRedraw,              
    UIViewContentModeCenter,            
    UIViewContentModeTop,
    UIViewContentModeBottom,
    UIViewContentModeLeft,
    UIViewContentModeRight,
    UIViewContentModeTopLeft,
    UIViewContentModeTopRight,
    UIViewContentModeBottomLeft,
    UIViewContentModeBottomRight,
};

七、UICollectionView

1.使用注意

UICollectionView初始化必须指定该UICollectionView的布局样式Layout。
Layout可以控制该UICollectionView显示样式。

UICollectionViewFlowLayout * layout=[[UICollectionViewFlowLayout alloc]init];
    /*
      中间间隔
      如果UICollectionViewScrollDirectionVertical:
      定义最小间隔的原因是因为CollectionView横向布局放不下会自动换行,所以此时间隔就不是定义的间隔了
    */
    layout.minimumInteritemSpacing=1;
    /*
      行间距
      如果UICollectionViewScrollDirectionHorizontal:
      定义最小行间距的原因是因为CollectionView纵向布局放不下会自动换行,所以此时间隔就不是定义的间隔了
    */
    layout.minimumLineSpacing=1;
    //itemSize
    layout.itemSize=CGSizeMake(100, 100);
    /*
     滑动方向UICollectionViewScrollDirectionVertical
     0246
     1357
     滑动方向UICollectionViewScrollDirectionHorizontal
     01
     23
     45
     67
     */
    layout.scrollDirection=UICollectionViewScrollDirectionHorizontal;
    UICollectionView * collectionView=[[UICollectionView alloc]initWithFrame:CGRectMake(0, 100, 300, 300) collectionViewLayout:layout];
    [collectionView registerNib:[UINib nibWithNibName:@"TestCollectionViewCell" bundle:nil] forCellWithReuseIdentifier:@"testCollectionViewCell"];
    collectionView.delegate=self;
    collectionView.dataSource=self;
    [self.view addSubview:collectionView];

结论:间距和itemSize设置要合理才不会让布局错乱;Bannel和引导页都可以使用横向滑动的CollectionView做。

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