Masonry框架详细解析(四) —— MASConstraint类解析(一)

版本记录

版本号 时间
V1.0 2018.07.18

前言

我们做APP界面,也就是布局UI,那么关于布局,我们有很多方法,苹果也都提供了支持,市场上我们用的并不是系统提供原生的layout,对于OC语言一般都是使用一个第三方的布局框架 —— Masonry。接下来几篇我们就一起深入看一下这个框架。感兴趣的看上面几篇文章。
1. Masonry框架详细解析(一) —— 基本概览(一)
2. Masonry框架详细解析(二) —— 基本结构API和约束入口(一)
3. Masonry框架详细解析(三) —— MASConstraintMaker工厂类(一)

MASConstraint、MASViewConstraint和MASCompositeConstraint三者之间的关系

首先MASConstraint作为约束,是MASViewConstraintMASCompositeConstraint的父类,其中MASViewConstraint指单个约束,而MASCompositeConstraint指复合约束。

我们可以先看一下下面的示意图,很清晰的说明了三者的关系。

下面我们就看一下这几个类都是做什么用的以及里面都有什么。MASConstraint本类和分类内容如下所示。


MASConstraint本类

1. API

首先看一下API

#import "MASUtilities.h"

/**
 *  Enables Constraints to be created with chainable syntax
 *  Constraint can represent single NSLayoutConstraint (MASViewConstraint) 
 *  or a group of NSLayoutConstraints (MASComposisteConstraint)
 */
// 允许使用可链接语法创建约束。 约束可以表示单个NSLayoutConstraint(MASViewConstraint)
// 或一组NSLayoutConstraints(MASComposisteConstraint)
@interface MASConstraint : NSObject

// Chaining Support

/**
 *  Modifies the NSLayoutConstraint constant,
 *  only affects MASConstraints in which the first item's NSLayoutAttribute is one of the following
 *  NSLayoutAttributeTop, NSLayoutAttributeLeft, NSLayoutAttributeBottom, NSLayoutAttributeRight
 */
// 修改NSLayoutConstraint常数,仅仅影响第一个item的NSLayoutAttribute
// 是下面NSLayoutAttributeTop, NSLayoutAttributeLeft, NSLayoutAttributeBottom, 
// NSLayoutAttributeRight之一的MASConstraints
- (MASConstraint * (^)(MASEdgeInsets insets))insets;

/**
 *  Modifies the NSLayoutConstraint constant,
 *  only affects MASConstraints in which the first item's NSLayoutAttribute is one of the following
 *  NSLayoutAttributeTop, NSLayoutAttributeLeft, NSLayoutAttributeBottom, NSLayoutAttributeRight
 */
// 修改NSLayoutConstraint常数,仅仅影响第一个item的NSLayoutAttribute
// 是下面NSLayoutAttributeTop, NSLayoutAttributeLeft, NSLayoutAttributeBottom, 
// NSLayoutAttributeRight之一的MASConstraints
- (MASConstraint * (^)(CGFloat inset))inset;

/**
 *  Modifies the NSLayoutConstraint constant,
 *  only affects MASConstraints in which the first item's NSLayoutAttribute is one of the following
 *  NSLayoutAttributeWidth, NSLayoutAttributeHeight
 */

// 修改NSLayoutConstraint常数,仅仅影响第一个item的NSLayoutAttribute
// 是下面NSLayoutAttributeWidth, NSLayoutAttributeHeight, 
// 之一的MASConstraints
- (MASConstraint * (^)(CGSize offset))sizeOffset;

/**
 *  Modifies the NSLayoutConstraint constant,
 *  only affects MASConstraints in which the first item's NSLayoutAttribute is one of the following
 *  NSLayoutAttributeCenterX, NSLayoutAttributeCenterY
 */
// 修改NSLayoutConstraint常数,仅仅影响第一个item的NSLayoutAttribute
// 是下面NSLayoutAttributeCenterX, NSLayoutAttributeCenterY, 
// 之一的MASConstraints
- (MASConstraint * (^)(CGPoint offset))centerOffset;

/**
 *  Modifies the NSLayoutConstraint constant
 */
// 修改NSLayoutConstraint常数
- (MASConstraint * (^)(CGFloat offset))offset;

/**
 *  Modifies the NSLayoutConstraint constant based on a value type
 */
// 基于值类型,修改NSLayoutConstraint常数
- (MASConstraint * (^)(NSValue *value))valueOffset;

/**
 *  Sets the NSLayoutConstraint multiplier property
 */
//设置NSLayoutConstraint的multiplier属性
- (MASConstraint * (^)(CGFloat multiplier))multipliedBy;

/**
 *  Sets the NSLayoutConstraint multiplier to 1.0/dividedBy
 */
//设置NSLayoutConstraint的multiplier为1.0/dividedBy
- (MASConstraint * (^)(CGFloat divider))dividedBy;

/**
 *  Sets the NSLayoutConstraint priority to a float or MASLayoutPriority
 */
//设置NSLayoutConstraint的优先级为一个浮点数或者MASLayoutPriority
- (MASConstraint * (^)(MASLayoutPriority priority))priority;

/**
 *  Sets the NSLayoutConstraint priority to MASLayoutPriorityLow
 */
// 设置NSLayoutConstraint的优先级为MASLayoutPriorityLow
- (MASConstraint * (^)(void))priorityLow;

/**
 *  Sets the NSLayoutConstraint priority to MASLayoutPriorityMedium
 */
// 设置NSLayoutConstraint优先级为MASLayoutPriorityMedium
- (MASConstraint * (^)(void))priorityMedium;

/**
 *  Sets the NSLayoutConstraint priority to MASLayoutPriorityHigh
 */
//设置NSLayoutConstraint优先级为MASLayoutPriorityHigh
- (MASConstraint * (^)(void))priorityHigh;

/**
 *  Sets the constraint relation to NSLayoutRelationEqual
 *  returns a block which accepts one of the following:
 *    MASViewAttribute, UIView, NSValue, NSArray
 *  see readme for more details.
 */
//设置约束关系为NSLayoutRelationEqual,返回一个block,
//接收一下类型参数MASViewAttribute, UIView, NSValue, NSArray
- (MASConstraint * (^)(id attr))equalTo;

/**
 *  Sets the constraint relation to NSLayoutRelationGreaterThanOrEqual
 *  returns a block which accepts one of the following:
 *    MASViewAttribute, UIView, NSValue, NSArray
 *  see readme for more details.
 */
//设置约束关系为NSLayoutRelationGreaterThanOrEqual,返回一个block,
//接收一下类型参数MASViewAttribute, UIView, NSValue, NSArray
- (MASConstraint * (^)(id attr))greaterThanOrEqualTo;

/**
 *  Sets the constraint relation to NSLayoutRelationLessThanOrEqual
 *  returns a block which accepts one of the following:
 *    MASViewAttribute, UIView, NSValue, NSArray
 *  see readme for more details.
 */
//设置约束关系为NSLayoutRelationLessThanOrEqual,返回一个block,
//接收一下类型参数MASViewAttribute, UIView, NSValue, NSArray
- (MASConstraint * (^)(id attr))lessThanOrEqualTo;

/**
 *  Optional semantic property which has no effect but improves the readability of constraint
 */
// 可选的语义属性,它不起作用,但提高了约束的可读性
- (MASConstraint *)with;

/**
 *  Optional semantic property which has no effect but improves the readability of constraint
 */
// 可选的语义属性,它不起作用,但提高了约束的可读性
- (MASConstraint *)and;

/**
 *  Creates a new MASCompositeConstraint with the called attribute and reciever
 */
// 根据调用的属性创建一个新的MASCompositeConstraint
- (MASConstraint *)left;
- (MASConstraint *)top;
- (MASConstraint *)right;
- (MASConstraint *)bottom;
- (MASConstraint *)leading;
- (MASConstraint *)trailing;
- (MASConstraint *)width;
- (MASConstraint *)height;
- (MASConstraint *)centerX;
- (MASConstraint *)centerY;
- (MASConstraint *)baseline;

#if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 80000) || (__TV_OS_VERSION_MIN_REQUIRED >= 9000) || (__MAC_OS_X_VERSION_MIN_REQUIRED >= 101100)

- (MASConstraint *)firstBaseline;
- (MASConstraint *)lastBaseline;

#endif

#if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 80000) || (__TV_OS_VERSION_MIN_REQUIRED >= 9000)

- (MASConstraint *)leftMargin;
- (MASConstraint *)rightMargin;
- (MASConstraint *)topMargin;
- (MASConstraint *)bottomMargin;
- (MASConstraint *)leadingMargin;
- (MASConstraint *)trailingMargin;
- (MASConstraint *)centerXWithinMargins;
- (MASConstraint *)centerYWithinMargins;

#endif


/**
 *  Sets the constraint debug name
 */
//设置约束constraint的debug name
- (MASConstraint * (^)(id key))key;

// NSLayoutConstraint constant Setters
// for use outside of mas_updateConstraints/mas_makeConstraints blocks

/**
 *  Modifies the NSLayoutConstraint constant,
 *  only affects MASConstraints in which the first item's NSLayoutAttribute is one of the following
 *  NSLayoutAttributeTop, NSLayoutAttributeLeft, NSLayoutAttributeBottom, NSLayoutAttributeRight
 */
// 修改NSLayoutConstraint常数,仅仅影响第一个item的NSLayoutAttribute
// 是下面NSLayoutAttributeTop, NSLayoutAttributeLeft, NSLayoutAttributeBottom, 
// NSLayoutAttributeRight之一的MASConstraints
- (void)setInsets:(MASEdgeInsets)insets;

/**
 *  Modifies the NSLayoutConstraint constant,
 *  only affects MASConstraints in which the first item's NSLayoutAttribute is one of the following
 *  NSLayoutAttributeTop, NSLayoutAttributeLeft, NSLayoutAttributeBottom, NSLayoutAttributeRight
 */
// 修改NSLayoutConstraint常数,仅仅影响第一个item的NSLayoutAttribute
// 是下面NSLayoutAttributeTop, NSLayoutAttributeLeft, NSLayoutAttributeBottom, 
// NSLayoutAttributeRight之一的MASConstraints
- (void)setInset:(CGFloat)inset;

/**
 *  Modifies the NSLayoutConstraint constant,
 *  only affects MASConstraints in which the first item's NSLayoutAttribute is one of the following
 *  NSLayoutAttributeWidth, NSLayoutAttributeHeight
 */
// 修改NSLayoutConstraint常数,仅仅影响第一个item的NSLayoutAttribute
// 是下面NSLayoutAttributeWidth, NSLayoutAttributeHeigh之一的MASConstraints
- (void)setSizeOffset:(CGSize)sizeOffset;

/**
 *  Modifies the NSLayoutConstraint constant,
 *  only affects MASConstraints in which the first item's NSLayoutAttribute is one of the following
 *  NSLayoutAttributeCenterX, NSLayoutAttributeCenterY
 */
// 修改NSLayoutConstraint常数,仅仅影响第一个item的NSLayoutAttribute
// 是下面NSLayoutAttributeCenterX, NSLayoutAttributeCenterY之一的MASConstraints
- (void)setCenterOffset:(CGPoint)centerOffset;

/**
 *  Modifies the NSLayoutConstraint constant
 */
//修改NSLayoutConstraint常量
- (void)setOffset:(CGFloat)offset;


// NSLayoutConstraint Installation support

#if TARGET_OS_MAC && !(TARGET_OS_IPHONE || TARGET_OS_TV)
/**
 *  Whether or not to go through the animator proxy when modifying the constraint
 */
// 是否在修改约束时通过动画代理
@property (nonatomic, copy, readonly) MASConstraint *animator;
#endif

/**
 *  Activates an NSLayoutConstraint if it's supported by an OS. 
 *  Invokes install otherwise.
 */
// 如果OS支持就激活一个NSLayoutConstraint,否则就调用install
- (void)activate;

/**
 *  Deactivates previously installed/activated NSLayoutConstraint.
 */
// 销毁前面安装或者激活的NSLayoutConstraint
- (void)deactivate;

/**
 *  Creates a NSLayoutConstraint and adds it to the appropriate view.
 */
//创建一个NSLayoutConstraint并将它添加到合适的view上
- (void)install;

/**
 *  Removes previously installed NSLayoutConstraint
 */
//移除以前安装的NSLayoutConstraint
- (void)uninstall;

@end


/**
 *  //用于MASConstraint方法的便捷自动装箱宏
 *  Convenience auto-boxing macros for MASConstraint methods.
 *  
 *  Defining MAS_SHORTHAND_GLOBALS will turn on auto-boxing for default syntax.
 *  A potential drawback of this is that the unprefixed macros will appear in global scope.
 */
#define mas_equalTo(...)                 equalTo(MASBoxValue((__VA_ARGS__)))
#define mas_greaterThanOrEqualTo(...)    greaterThanOrEqualTo(MASBoxValue((__VA_ARGS__)))
#define mas_lessThanOrEqualTo(...)       lessThanOrEqualTo(MASBoxValue((__VA_ARGS__)))

#define mas_offset(...)                  valueOffset(MASBoxValue((__VA_ARGS__)))


#ifdef MAS_SHORTHAND_GLOBALS

#define equalTo(...)                     mas_equalTo(__VA_ARGS__)
#define greaterThanOrEqualTo(...)        mas_greaterThanOrEqualTo(__VA_ARGS__)
#define lessThanOrEqualTo(...)           mas_lessThanOrEqualTo(__VA_ARGS__)

#define offset(...)                      mas_offset(__VA_ARGS__)

#endif

上面每个属性的意义,我都标注里面了,感兴趣的可以看下,如果有别的需要特别说出的,我会单独列出来。

2. 链式支持

下面就以为例说一下链式支持。

/**
 *  Modifies the NSLayoutConstraint constant,
 *  only affects MASConstraints in which the first item's NSLayoutAttribute is one of the following
 *  NSLayoutAttributeTop, NSLayoutAttributeLeft, NSLayoutAttributeBottom, NSLayoutAttributeRight
 */
- (MASConstraint * (^)(MASEdgeInsets insets))insets;

下面我们看一下实现

#define MASEdgeInsets UIEdgeInsets

- (MASConstraint * (^)(MASEdgeInsets))insets {
    return ^id(MASEdgeInsets insets){
        self.insets = insets;
        return self;
    };
}
- (void)setInsets:(UIEdgeInsets)insets {
    Setter(if(!_path){
        if (insets.top < 0) insets.top = 0;
        if (insets.left < 0) insets.left = 0;
        if (insets.bottom < 0) insets.bottom = 0;
        if (insets.right < 0) insets.right = 0;
        _insets = insets;
    });
}

首先更新一下属性self.insets,然后把自己self返回去。还记得工厂方法里面的maker吗?它就会返回一个MASConstraint对象,这里我们调用上面的block然后就将自己返回去,你就可以一直用点语法install约束,这就是链式编程。

3. NSLayoutConstraint常数设置

这里以下面方法为例进行说明。

/**
 *  Modifies the NSLayoutConstraint constant,
 *  only affects MASConstraints in which the first item's NSLayoutAttribute is one of the following
 *  NSLayoutAttributeTop, NSLayoutAttributeLeft, NSLayoutAttributeBottom, NSLayoutAttributeRight
 */
- (void)setInsets:(MASEdgeInsets)insets;

这是一个抽象方法,在MASConstraint类中没有实现,具体如下所示:

- (void)setInsets:(MASEdgeInsets __unused)insets { MASMethodNotImplemented(); }

但是,它的子类MASCompositeConstraintMASViewConstraint中都进行了重写并实现。

// MASCompositeConstraint
- (void)setInsets:(MASEdgeInsets)insets {
    for (MASConstraint *constraint in self.childConstraints) {
        constraint.insets = insets;
    }
}
// MASViewConstraint
- (void)setInsets:(MASEdgeInsets)insets {
    NSLayoutAttribute layoutAttribute = self.firstViewAttribute.layoutAttribute;
    switch (layoutAttribute) {
        case NSLayoutAttributeLeft:
        case NSLayoutAttributeLeading:
            self.layoutConstant = insets.left;
            break;
        case NSLayoutAttributeTop:
            self.layoutConstant = insets.top;
            break;
        case NSLayoutAttributeBottom:
            self.layoutConstant = -insets.bottom;
            break;
        case NSLayoutAttributeRight:
        case NSLayoutAttributeTrailing:
            self.layoutConstant = -insets.right;
            break;
        default:
            break;
    }
}

它们的实现目标都是用来进行更改约束的。

4. NSLayoutConstraint Installation支持

这里针对iOS就下面四个方法

- (void)activate;
- (void)deactivate;
- (void)install;
- (void)uninstall;

同样这四个方法都是抽象方法,均不在给类中实现,而是在子类MASCompositeConstraintMASViewConstraint中都进行了重写并实现。

- (void)activate { MASMethodNotImplemented(); }
- (void)deactivate { MASMethodNotImplemented(); }
- (void)install { MASMethodNotImplemented(); }
- (void)uninstall { MASMethodNotImplemented(); }

下面看一下在子类中的实现情况。

// MASCompositeConstraint
- (void)activate {
    for (MASConstraint *constraint in self.childConstraints) {
        [constraint activate];
    }
}

- (void)deactivate {
    for (MASConstraint *constraint in self.childConstraints) {
        [constraint deactivate];
    }
}

- (void)install {
    for (MASConstraint *constraint in self.childConstraints) {
        constraint.updateExisting = self.updateExisting;
        [constraint install];
    }
}

- (void)uninstall {
    for (MASConstraint *constraint in self.childConstraints) {
        [constraint uninstall];
    }
}
// MASViewConstraint
- (void)activate {
    [self install];
}

- (void)deactivate {
    [self uninstall];
}

- (void)install {
    if (self.hasBeenInstalled) {
        return;
    }
    
    if ([self supportsActiveProperty] && self.layoutConstraint) {
        self.layoutConstraint.active = YES;
        [self.firstViewAttribute.view.mas_installedConstraints addObject:self];
        return;
    }
    
    MAS_VIEW *firstLayoutItem = self.firstViewAttribute.item;
    NSLayoutAttribute firstLayoutAttribute = self.firstViewAttribute.layoutAttribute;
    MAS_VIEW *secondLayoutItem = self.secondViewAttribute.item;
    NSLayoutAttribute secondLayoutAttribute = self.secondViewAttribute.layoutAttribute;

    // alignment attributes must have a secondViewAttribute
    // therefore we assume that is refering to superview
    // eg make.left.equalTo(@10)
    if (!self.firstViewAttribute.isSizeAttribute && !self.secondViewAttribute) {
        secondLayoutItem = self.firstViewAttribute.view.superview;
        secondLayoutAttribute = firstLayoutAttribute;
    }
    
    MASLayoutConstraint *layoutConstraint
        = [MASLayoutConstraint constraintWithItem:firstLayoutItem
                                        attribute:firstLayoutAttribute
                                        relatedBy:self.layoutRelation
                                           toItem:secondLayoutItem
                                        attribute:secondLayoutAttribute
                                       multiplier:self.layoutMultiplier
                                         constant:self.layoutConstant];
    
    layoutConstraint.priority = self.layoutPriority;
    layoutConstraint.mas_key = self.mas_key;
    
    if (self.secondViewAttribute.view) {
        MAS_VIEW *closestCommonSuperview = [self.firstViewAttribute.view mas_closestCommonSuperview:self.secondViewAttribute.view];
        NSAssert(closestCommonSuperview,
                 @"couldn't find a common superview for %@ and %@",
                 self.firstViewAttribute.view, self.secondViewAttribute.view);
        self.installedView = closestCommonSuperview;
    } else if (self.firstViewAttribute.isSizeAttribute) {
        self.installedView = self.firstViewAttribute.view;
    } else {
        self.installedView = self.firstViewAttribute.view.superview;
    }


    MASLayoutConstraint *existingConstraint = nil;
    if (self.updateExisting) {
        existingConstraint = [self layoutConstraintSimilarTo:layoutConstraint];
    }
    if (existingConstraint) {
        // just update the constant
        existingConstraint.constant = layoutConstraint.constant;
        self.layoutConstraint = existingConstraint;
    } else {
        [self.installedView addConstraint:layoutConstraint];
        self.layoutConstraint = layoutConstraint;
        [firstLayoutItem.mas_installedConstraints addObject:self];
    }
}

- (MASLayoutConstraint *)layoutConstraintSimilarTo:(MASLayoutConstraint *)layoutConstraint {
    // check if any constraints are the same apart from the only mutable property constant

    // go through constraints in reverse as we do not want to match auto-resizing or interface builder constraints
    // and they are likely to be added first.
    for (NSLayoutConstraint *existingConstraint in self.installedView.constraints.reverseObjectEnumerator) {
        if (![existingConstraint isKindOfClass:MASLayoutConstraint.class]) continue;
        if (existingConstraint.firstItem != layoutConstraint.firstItem) continue;
        if (existingConstraint.secondItem != layoutConstraint.secondItem) continue;
        if (existingConstraint.firstAttribute != layoutConstraint.firstAttribute) continue;
        if (existingConstraint.secondAttribute != layoutConstraint.secondAttribute) continue;
        if (existingConstraint.relation != layoutConstraint.relation) continue;
        if (existingConstraint.multiplier != layoutConstraint.multiplier) continue;
        if (existingConstraint.priority != layoutConstraint.priority) continue;

        return (id)existingConstraint;
    }
    return nil;
}

- (void)uninstall {
    if ([self supportsActiveProperty]) {
        self.layoutConstraint.active = NO;
        [self.firstViewAttribute.view.mas_installedConstraints removeObject:self];
        return;
    }
    
    [self.installedView removeConstraint:self.layoutConstraint];
    self.layoutConstraint = nil;
    self.installedView = nil;
    
    [self.firstViewAttribute.view.mas_installedConstraints removeObject:self];
}

MASConstraint分类

下面我们就看一下MASConstraint分类AutoboxingSupport

首先看一下该分类的API文档

1. API

@interface MASConstraint (AutoboxingSupport)

/**
 *  Aliases to corresponding relation methods (for shorthand macros)
 *  Also needed to aid autocompletion
 */
// 对应关系方法的别名(对于缩略宏),还需要帮助自动完成
- (MASConstraint * (^)(id attr))mas_equalTo;
- (MASConstraint * (^)(id attr))mas_greaterThanOrEqualTo;
- (MASConstraint * (^)(id attr))mas_lessThanOrEqualTo;

/**
 *  A dummy method to aid autocompletion
 */
// 一种帮助自动完成的dummy方法
- (MASConstraint * (^)(id offset))mas_offset;

@end

2. 别名方法

下面就以下面方法为例进行说明

- (MASConstraint * (^)(id attr))mas_equalTo;

下面看一下实现

- (MASConstraint * (^)(id))mas_equalTo {
    return ^id(id attribute) {
        return self.equalToWithRelation(attribute, NSLayoutRelationEqual);
    };
}

- (MASConstraint * (^)(id, NSLayoutRelation))equalToWithRelation { MASMethodNotImplemented(); }

可见,这个在本抽象类还是没有实现,在子类MASCompositeConstraintMASViewConstraint中都进行了重写并实现。

//MASCompositeConstraint
- (MASConstraint * (^)(id, NSLayoutRelation))equalToWithRelation {
    return ^id(id attr, NSLayoutRelation relation) {
        for (MASConstraint *constraint in self.childConstraints.copy) {
            constraint.equalToWithRelation(attr, relation);
        }
        return self;
    };
}
//MASViewConstraint 
- (MASConstraint * (^)(id, NSLayoutRelation))equalToWithRelation {
    return ^id(id attribute, NSLayoutRelation relation) {
        if ([attribute isKindOfClass:NSArray.class]) {
            NSAssert(!self.hasLayoutRelation, @"Redefinition of constraint relation");
            NSMutableArray *children = NSMutableArray.new;
            for (id attr in attribute) {
                MASViewConstraint *viewConstraint = [self copy];
                viewConstraint.layoutRelation = relation;
                viewConstraint.secondViewAttribute = attr;
                [children addObject:viewConstraint];
            }
            MASCompositeConstraint *compositeConstraint = [[MASCompositeConstraint alloc] initWithChildren:children];
            compositeConstraint.delegate = self.delegate;
            [self.delegate constraint:self shouldBeReplacedWithConstraint:compositeConstraint];
            return compositeConstraint;
        } else {
            NSAssert(!self.hasLayoutRelation || self.layoutRelation == relation && [attribute isKindOfClass:NSValue.class], @"Redefinition of constraint relation");
            self.layoutRelation = relation;
            self.secondViewAttribute = attribute;
            return self;
        }
    };
}

后记

本篇主要讲述了MASConstraint类解析,感兴趣的给个赞或者关注~~~

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

推荐阅读更多精彩内容