iOS实现滑动手势解锁

近期增加了object-c的具体应用,包括手势绘制,验证,更新,以及处理了一些手势绘制过程中Bug。详情见object-c实现。

  • 一、swift实现

使用swift实现iOS手势锁屏,虽然在iOS客户端很少使用到滑动手势,但是有时候为了和安卓应用保持用户交互的一致性,所以有的时候还是很有必要的。
iOS客户端解锁建议使用touch ID。

swift与object-c的CGContextRef不一样,在swift中统一使用CGContext进行管理和使用。

本示例采用9*button进行绘制,关闭button交互事件,通过touchesBegan系列方法对滑动路径进行跟踪和绘制(imageView)。

以下为全部代码:

import UIKit

  class TouchPasswordViewController: UIViewController {

    let screenWidth : CGFloat = UIScreen.main.bounds.size.width;
    let screenHeight : CGFloat = UIScreen.main.bounds.size.height;

    var btnArray : NSMutableArray = NSMutableArray.init(); //btn数组
    var selectToArray : NSMutableArray = NSMutableArray.init();//选中的btn数组
    var startPoint : CGPoint = CGPoint.init();//起点
    var endPoint : CGPoint = CGPoint.init();//终点
    var imageView : UIImageView = UIImageView.init();//绘制的背景



    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.backgroundColor = UIColor.white;

        imageView = UIImageView.init(frame: CGRect.init(x: 0, y: 0, width: screenWidth, height: screenHeight));
        self.view.addSubview(imageView);

        for i in 0...2 {
            for j in 0...2 {
                let btn : UIButton = UIButton.init(type: UIButtonType.custom);
                btn.frame = CGRect.init(x: screenWidth / 12 + screenWidth / 3 * CGFloat(j), y: screenHeight / 3 + screenWidth / 3 * CGFloat(i), width: screenWidth / 6, height: screenWidth / 6);

                btn.setImage(UIImage.init(named: "尼罗河-4"), for: UIControlState.normal);
                btn.setImage(UIImage.init(named: "尼罗河"), for: UIControlState.selected);
                btn.isUserInteractionEnabled = false;//取消button的交互事件,否则touch会被截断。
                btnArray.add(btn);
                imageView.addSubview(btn);


            }
        }

    }


    func drawLine() -> (UIImage){
        var img : UIImage = UIImage.init();
        let color : UIColor = UIColor.init(red: 1, green: 0, blue: 0, alpha: 1);

        //绘制线条路径
        UIGraphicsBeginImageContext(imageView.frame.size);
        let context = UIGraphicsGetCurrentContext();
        context?.setLineWidth(5);
        context?.setStrokeColor(color.cgColor);
        context?.move(to: startPoint);

        for b in selectToArray {
            let btn : UIButton = b as! UIButton;
            let btnPit = btn.center;

            context?.addLine(to: btnPit);
            context?.move(to: btnPit);
        }

        context?.addLine(to: endPoint);
        context?.strokePath();

        img = UIGraphicsGetImageFromCurrentImageContext()!;
        UIGraphicsEndImageContext();

        return img;
    }


    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        let touch : UITouch = touches.first!;
        for b in btnArray {
            let btn : UIButton = b as! UIButton;
            let btnPit : CGPoint = touch.location(in: btn);
            if btn.point(inside: btnPit, with: nil) {//判断当前touch是否btn范围内,在则存入selectArray 并改变button状态
                selectToArray.add(btn);
                btn.isHighlighted = true;
                startPoint = btn.center;
            }
        }
    }


    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        let touch : UITouch = touches.first!;
        endPoint = touch.location(in: imageView);

        for b in btnArray {
            let btn : UIButton = b as! UIButton;
            let po : CGPoint = touch.location(in: btn);

            if btn.point(inside: po, with: nil) {
                var isAdd : Bool = true;

                for b in selectToArray {
                    let selectBtn : UIButton = b as! UIButton;
                    if selectBtn == btn {
                        isAdd = false;
                        break;
                    }
                }

                if isAdd {
                    selectToArray.add(btn);
                    btn.isHighlighted = true;
                }
            }

        }
        imageView.image = self.drawLine();
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        imageView.image = nil;
        selectToArray.removeAllObjects();

        for b in btnArray {
            let btn : UIButton = b as! UIButton;
            btn.isHighlighted = false;

        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    }
  • 二、object-c实现

object-c实现与swift逻辑一致,只是加入在实际使用过程中遇到的问题,使其更有参考性和实际应用价值。
注:代码中有部分资源是中英文适配使用的。如:NSLocalizedString

在object-c中考虑到屏幕适配会导致button图片拉伸,所以使用UIView代替UIButton。自定义了一个UIView.
1、RoundRectView.h

#import <UIKit/UIKit.h>

@interface RoundRectView : UIView
@property (nonatomic, strong) UIView *selectView;

@end

2、RoundRectView.m

#import "RoundRectView.h"
#import "SysConfig.h"

@interface RoundRectView ()
{
    CGFloat _width;
}

@end

@implementation RoundRectView

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        _width = frame.size.width / 4.0;
        [self initUI];
    }
    return self;
}

- (void)initUI{
    self.backgroundColor = [UIColor whiteColor];
    self.layer.masksToBounds = YES;
    self.layer.cornerRadius = self.frame.size.width/ 2.0;
    self.layer.borderWidth = 2.0;
    self.layer.borderColor = [UIColor hexString:@"#3fb8c8"].CGColor;

    self.selectView = [[UIView alloc] initWithFrame:CGRectMake((self.frame.size.width - _width) / 2, (self.frame.size.width - _width) / 2, _width, _width)];
    self.selectView.backgroundColor = [UIColor hexString:@"#3fb8c8"];
    self.selectView.layer.masksToBounds = YES;
    self.selectView.layer.cornerRadius = _width / 2.0;
    self.selectView.hidden = YES;
    [self addSubview:self.selectView];  
}
@end

3、TouchUpViewController.h

#import <UIKit/UIKit.h>
#import "LXBaseViewController.h"

typedef enum : NSUInteger {
    TouchUnlockCreatePwd,//绘制
    TouchUnlockValidatePwd,//验证
    TouchUnlockUpdatePwd,//修改手势
} UnlockType;

@interface TouchUpViewController : LXBaseViewController

- (instancetype)initWithUnlockType:(UnlockType)type;

@end

4、TouchUpViewController.m

#import "TouchUpViewController.h"
#import "RoundRectView.h"
#import "SysConfig.h"
#import "AppDelegate.h"
#import "LXNetworkRequest.h"
#import "LXNetworkRequest+LogWithEmail.h"

#define APPDELEGATEREAL (AppDelegate *)[UIApplication sharedApplication].delegate
#define TouchUnlockPwdKey  @"touchUnlockPwdKey"

@interface TouchUpViewController ()
{
    NSMutableArray *_nomarlArray,*_selectArray;
    CGFloat _width,_height;
    UIImageView *_imageView;
    CGPoint _startPoint,_endPoint;
    NSMutableString *_password;
    NSString *_oldPassword;
    UnlockType _unlockType;
    NSInteger _errorCount;

    UIImageView *_headerImageView;
    UILabel *_nickNameLabel,*_tipLabel;
    UIButton *_loginBtn;

    BOOL isUpdatePwd;

    NSInteger _steps;//1 验证密码 2:创建第一遍   3:创建第二遍
}
@end

@implementation TouchUpViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.title = NSLocalizedString(@"Draw Pattern", nil);
    self.view.backgroundColor = [UIColor whiteColor];
    [self initUI];
}

- (void)comeBack:(id)sender
{
    [self.navigationController popViewControllerAnimated:YES];
}

- (instancetype)initWithUnlockType:(UnlockType)type{

    self = [super init];
    if (self) {
        _unlockType = type;
    }
    return self;
}

- (void)initUI{

    NSUserDefaults *def = [NSUserDefaults standardUserDefaults];
    NSString *savePwd = [def objectForKey:TouchUnlockPwdKey];

    _width = [UIScreen mainScreen].bounds.size.width;
    _height = [UIScreen mainScreen].bounds.size.height;

    _password = [NSMutableString string];
    _nomarlArray = [NSMutableArray array];
    _selectArray = [NSMutableArray array];

    _imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, _width, _height)];
    [self.view addSubview:_imageView];


    CGFloat leftSpace = fitScreenWidth(40);
    CGFloat wd = (_width - leftSpace * 2) /8.0;

    NSInteger index = 1;
    for (int i = 0; i < 3; i ++) {
        for (int j = 0; j < 3; j ++) {

            CGRect rect = CGRectMake(leftSpace + wd * 3 * j, _height / 3.0 + wd * 3 * i, wd * 2, wd * 2);
            RoundRectView *ve = [[RoundRectView alloc] initWithFrame:rect];

            ve.tag = index ++;

            [_nomarlArray addObject:ve];
            [_imageView addSubview:ve];
        }
    }


    //    -   -  -  - -  header - - - - - - -  - -
    _headerImageView = [[UIImageView alloc] initWithFrame:CGRectMake((_width - fitScreenWidth(50)) / 2, fitScreenWidth(60), fitScreenWidth(50), fitScreenWidth(50))];
    _headerImageView.backgroundColor = [UIColor whiteColor];
    [self.view addSubview:_headerImageView];

    _nickNameLabel = [[UILabel alloc] initWithFrame:CGRectMake((_width - fitScreenWidth(100)) / 2, CGRectGetMaxY(_headerImageView.frame), fitScreenWidth(100), fitScreenWidth(25))];
    _nickNameLabel.font = [UIFont systemFontOfSize:fitScreenWidth(12.0)];
    _nickNameLabel.hidden = YES;
    _nickNameLabel.textAlignment = NSTextAlignmentCenter;
    [self.view addSubview:_nickNameLabel];

    _tipLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, CGRectGetMaxY(_nickNameLabel.frame), _width - 20 * 2, fitScreenWidth(25))];
    _tipLabel.font = [UIFont systemFontOfSize:fitScreenWidth(13.0)];
    _tipLabel.textAlignment = NSTextAlignmentCenter;
    _tipLabel.textColor = [UIColor lightGrayColor];
    [self.view addSubview:_tipLabel];


    _loginBtn = [[UIButton alloc] initWithFrame:CGRectMake((_width - fitScreenWidth(150)) / 2 , _height - fitScreenWidth(55), fitScreenWidth(150), 30)];
    _loginBtn.titleLabel.font = [UIFont systemFontOfSize:fitScreenWidth(13.0)];

    [_loginBtn setTitle:NSLocalizedString(@"Use login password", nil) forState:UIControlStateNormal];
    [_loginBtn setTitleColor:[UIColor hexString:@"#3fb8c8"] forState:UIControlStateNormal];
    [_loginBtn setHidden:YES];
    [_loginBtn addTarget:self action:@selector(loginWithPwd) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:_loginBtn];


    UIBarButtonItem *resetBtn = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"Reset", nil) style:UIBarButtonItemStylePlain target:self action:@selector(resetBtnClick)];
    self.navigationItem.rightBarButtonItem = resetBtn;

    if (_unlockType == TouchUnlockCreatePwd) {
        //绘制
        _steps = 2;
        _tipLabel.text = NSLocalizedString(@"Draw Your Pattern", nil);
    }
    else if (_unlockType == TouchUnlockUpdatePwd){
        //更新密码不验证原密码 直接新增 !savePwd || savePwd.length == 0
        _unlockType = TouchUnlockCreatePwd;
        _tipLabel.text = NSLocalizedString(@"Draw new pattern", nil);
        _steps = 2;
    }
    else if (_unlockType == TouchUnlockValidatePwd){
        //验证密码
        _steps = 1;
        _errorCount = 5;
        [_loginBtn setHidden:NO];
        _tipLabel.text = NSLocalizedString(@"Draw Your Pattern", nil);
        _headerImageView.layer.masksToBounds = YES;
        _headerImageView.layer.cornerRadius = fitScreenWidth(50) / 2;
        [_headerImageView setNewImageUrl:APPDELEGATE.userModel.avatar placeHolder:[UIImage imageNamed:@"login_content_Avatar@2x"]];

        _nickNameLabel.hidden = NO;
        _nickNameLabel.text = APPDELEGATE.userModel.nickname;
    }

    if ([savePwd isEqualToString:@"TouchPwdError"]) {
        //密码失效,直接弹出提示框
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [self alertPwdError];
        });
    }
}

- (void)changeUI:(UnlockType)type{
    //切换头部视图
}

- (void)changeTip:(NSInteger)index{
    //改变警告文字  1:最少四个点,请重新绘制  2:与上次绘制不一致,请重新绘制 3:密码错误还可以输入5次
    _tipLabel.textColor = [UIColor redColor];
    NSString *text = nil;
    switch (index) {
        case 1:
        {
            text = NSLocalizedString(@"At least 4 points required", nil);
        }
            break;

        case 2:
        {
            text = NSLocalizedString(@"Not match. Please draw it again", nil);

        }
            break;

        case 3:
        {
            text = _errorCount == 10000 ? [NSString stringWithFormat:NSLocalizedString(@"Invalid password. Please draw it again", nil)] : [NSLocalizedString(@"Invalid password.*** attempt(s) left", nil) stringByReplacingOccurrencesOfString:@"***" withString:[NSString stringWithFormat:@"%ld",_errorCount -- > 0 ? _errorCount : 0]];
        }
            break;


        default:
            break;
    }

    _tipLabel.text = text;

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

        if (_unlockType == TouchUnlockCreatePwd) {
            if (_steps == 2) {
                [self changeTipForNormal:1];
            }
            else if (_steps == 3){
                [self changeTipForNormal:3];
            }
            return;
        }
        [self changeTipForNormal:1];
    });
}

- (void)changeTipForNormal:(NSInteger)index{
    _tipLabel.textColor = [UIColor lightGrayColor];
    NSString *text = @"";
    switch (index) {
        case 1:
            text = NSLocalizedString(@"Draw Your Pattern", nil);
            break;
        case 2:
            text = @"请输入原手势密码";
            break;
        case 3:
            text = NSLocalizedString(@"Draw pattern again", nil);
            break;
        case 4:
            text = NSLocalizedString(@"Draw Your Pattern", nil);
            break;

        default:
            break;
    }
    _tipLabel.text = text;
}


- (UIImage *)drawline{

    if (_selectArray.count == 0) {
        return nil;
    }
    RoundRectView *ve = _selectArray.firstObject;
    CGPoint vePoint = ve.center;
    _startPoint = vePoint;

    UIImage *img = [[UIImage alloc] init];
    UIColor *color = [UIColor hexString:@"#3fb8c8"];

    UIGraphicsBeginImageContext(_imageView.frame.size);
    CGContextRef context = UIGraphicsGetCurrentContext();
//    CGContextSetAllowsAntialiasing(context,true);
//    CGContextSetShouldAntialias(context, true);

    CGContextSetLineWidth(context, 2);
    CGContextSetStrokeColorWithColor(context, color.CGColor);
    CGContextMoveToPoint(context, _startPoint.x, _startPoint.y);


    if (_selectArray.count == 0) {
        return nil;
    }

    for (RoundRectView *ve in _selectArray) {
        CGPoint po = ve.center;
        CGContextAddLineToPoint(context, po.x, po.y);
        CGContextMoveToPoint(context, po.x, po.y);
    }

    CGContextAddLineToPoint(context, _endPoint.x, _endPoint.y);
    CGContextStrokePath(context);

    img = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return img;
}


- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{

    UITouch *touch = [touches anyObject];
    if (touch) {
        for (RoundRectView *ve in _nomarlArray) {
            CGPoint point = [touch locationInView:ve];

            if ([ve pointInside:point withEvent:nil]) {
                [_selectArray addObject:ve];
                [self savePassWord:ve.tag];
                ve.selectView.hidden = NO;
                _startPoint = ve.center;
            }
        }
    }
}


- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    UITouch *touch = [touches anyObject];
    if (touch) {
        _endPoint = [touch locationInView:_imageView];

        for (RoundRectView *ve in _nomarlArray) {
            CGPoint point = [touch locationInView:ve];

            if ([ve pointInside:point withEvent:nil]) {

                BOOL isAdd = YES;
                for (RoundRectView *vv in _selectArray) {
                    if (vv == ve) {
                        isAdd = NO;
                        break;
                    }
                }

                if (isAdd) {
                    [_selectArray addObject:ve];
                    [self savePassWord:ve.tag];
                    ve.selectView.hidden = NO;
                }
            }
        }
    }
    _imageView.image = [self drawline];
    _imageView.layer.contentsScale = [[UIScreen mainScreen] scale];

}


- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{

    UITouch *touch = [touches anyObject];
    if (touch) {
        for (RoundRectView *ve in _nomarlArray) {
            CGPoint po = [touch locationInView:ve];
            if (![ve pointInside:po withEvent:nil]) {
                RoundRectView *seVe = _selectArray.lastObject;
                _endPoint = seVe.center;
                _imageView.image = [self drawline];
            }
        }
    }
    [self cheakPassword];

    _password = [NSMutableString string];

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

        _imageView.image = nil;
        [_selectArray removeAllObjects];

        for (RoundRectView *ve in _nomarlArray) {
            ve.selectView.hidden = YES;
        }
    });
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}


- (void)savePassWord:(NSInteger)tag{
    [_password appendFormat:@"%ld",tag];
}


- (void)cheakPassword{

    if (_password.length < 4) {
        [self changeTip:1];
        return; //密码长度不够
    }

    if (_unlockType == TouchUnlockCreatePwd) {

        if (_steps == 2) {
            _oldPassword = _password;
            [self changeTipForNormal:3];
            _steps = 3;
            return;
        }

        if (_steps == 3) {
            if (![_password isEqualToString:_oldPassword]) {
                [self changeTip:2];
                return; //前后不一致
            }

            if ([_oldPassword isEqualToString:_password]) {
                //两次密码一致 存本地
                NSUserDefaults *def = [NSUserDefaults standardUserDefaults];
                [def setObject:_password forKey:TouchUnlockPwdKey];
                [MessageCenter openAlertViewWithMessage:NSLocalizedString(@"Success", nil) duringtime:1];
                [self.navigationController popViewControllerAnimated:YES];
            }
        }
    }

    else if (_unlockType == TouchUnlockValidatePwd || _unlockType == TouchUnlockUpdatePwd){
        //获取保存的密码
        NSUserDefaults *def = [NSUserDefaults standardUserDefaults];
        NSString *savePwd = [def objectForKey:TouchUnlockPwdKey];

        if (![savePwd isEqualToString:_password] && _steps == 1) {
            //原密码错误
            _steps = 1;
            [self changeTip:3];

            if (_errorCount <= 0) {
                //错误次数太多
                [self alertPwdError];
                return;
            }

            return;
        }
        //登陆成功
        if (_unlockType == TouchUnlockValidatePwd) {

            _errorCount = 5;
//            [self dismissViewControllerAnimated:YES completion:nil];

            if (![APPDELEGATEREAL lockScreenWindow].hidden) {
                [APPDELEGATEREAL lockScreenWindow].hidden = YES;
            }
            return;
        }

        if (_steps == 1) {
            [self changeTipForNormal:1];
            _steps = 2;
            return;
        }

        if (_steps == 2) {
            _oldPassword = _password;
            [self changeTipForNormal:3];
            _steps = 3;
            return;
        }

        if (_steps == 3) {
            if (![_password isEqualToString:_oldPassword]) {
                 [self changeTip:2];
                return;
            }

            if ([_oldPassword isEqualToString:_password]) {
                //两次密码一致 存本地
                NSUserDefaults *def = [NSUserDefaults standardUserDefaults];
                [def setObject:_password forKey:TouchUnlockPwdKey];

                NSLog(@"密码更新成功:%@",_password);
                [MessageCenter openAlertViewWithMessage:NSLocalizedString(@"Success", nil) duringtime:1];
                dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                    [self.navigationController popViewControllerAnimated:YES];
                });
            }
        }

    }

}


- (void)alertPwdError{
    //手势密码失效
    [[NSUserDefaults standardUserDefaults] setObject:@"TouchPwdError" forKey:TouchUnlockPwdKey];

    UIAlertController *alert = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Pattern is expired", nil) message:NSLocalizedString(@"Please login with password", nil) preferredStyle:UIAlertControllerStyleAlert];

    NSMutableAttributedString *alertControllerMessageStr = [[NSMutableAttributedString alloc] initWithString:NSLocalizedString(@"Please login with password", nil)];
    [alertControllerMessageStr addAttribute:NSForegroundColorAttributeName value:[UIColor hexString:@"#999999"] range:NSMakeRange(0, alertControllerMessageStr.length)];
    [alertControllerMessageStr addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:12] range:NSMakeRange(0, alertControllerMessageStr.length)];
    [alert setValue:alertControllerMessageStr forKey:@"attributedMessage"];

    UIAlertAction *toAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Login again", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        [self loginWithPwd];
    }];
    [alert addAction:toAction];
    [self presentViewController:alert animated:YES completion:nil];
}


- (void)loginWithPwd{
    LX_LoginAndForgetViewController *loginVc = [[LX_LoginAndForgetViewController alloc] init];
    loginVc.isTouchUnlockIn = YES;
    [self presentViewController:loginVc animated:YES completion:nil];
}

//重设
- (void)resetBtnClick{
    _oldPassword = nil;
    _steps = 2;
    [self changeTipForNormal:1];
}

@end

5、AppDelegate中新增UIwindow属性用于遮罩

//didFinishLaunchingWithOptions方法加入
self.lockScreenWindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
 self.lockScreenWindow.windowLevel= UIWindowLevelAlert+1;//最高级等级窗口
 self.lockScreenWindow.backgroundColor = [UIColor whiteColor];
 TouchUpViewController *lockvc  =[[TouchUpViewController alloc]initWithUnlockType:TouchUnlockValidatePwd];
 self.lockScreenWindow.rootViewController = lockvc;
 self.lockScreenWindow.hidden = YES;

在合适的时候对lockScreenWindow.hidden属性进行操作。

通过上述两个类,初步建立了手势密码的逻辑体系。

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

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 11,945评论 4 60
  • 当提及你有什么梦想时候,许多人倾向说想当作家、明星、想有花不完的钱、想旅行环游世界…每一个人可能都有梦想,...
    睿小然阅读 243评论 0 0
  • 最近呢,天气嗖的一下就转凉了,明明昨天还是热裤+短袖,今天就外套长裤加身,还能不能好好露美腿了🤣🤣🤣 ...
    我怎么不发光了阅读 437评论 0 3