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閱讀 227,837評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,196評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,688評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,654評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,456評論 6 406
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,955評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,044評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,195評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,725評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,608評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,802評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,318評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,048評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,422評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,673評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,424評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,762評論 2 372

推薦閱讀更多精彩內容

  • 發現 關注 消息 iOS 第三方庫、插件、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,151評論 4 61
  • 當提及你有什么夢想時候,許多人傾向說想當作家、明星、想有花不完的錢、想旅行環游世界…每一個人可能都有夢想,...
    睿小然閱讀 252評論 0 0
  • 最近呢,天氣嗖的一下就轉涼了,明明昨天還是熱褲+短袖,今天就外套長褲加身,還能不能好好露美腿了?????? ...
    我怎么不發光了閱讀 452評論 0 3