iOS 原生二維碼[掃碼]與[生成]詳解

前言

二維碼現(xiàn)在很常見, App中有許多都配置了該功能, 網(wǎng)上也有很多對(duì)iOS二維碼的講解, 但是對(duì)配置掃碼范圍這個(gè)問題好像都沒怎么講清晰. 作者今天就寫一下二維碼.

一 二維碼介紹

二維碼

三個(gè)回形大方塊, 是為了給相機(jī)定位的; 黑白塊, 黑塊代表1, 白塊代表0, 八個(gè)一組, 組成二進(jìn)制信息. 科普:二維碼是什么原理? 這個(gè)小視頻, 簡單介紹了下二維碼.

原理圖

二 iOS 掃碼二維碼

  • 一.工程中General -> Linked Frameworks and Libraries -> 引入 AVFoundation.framework

  • 二. 代碼部分解析

  1. 頭文件
//引入頭文件
#import <AVFoundation/AVFoundation.h>
// 作者自定義的View視圖, 繼承UIView
#import "ShadowView.h"

#define kWidth [UIScreen mainScreen].bounds.size.width
#define kHeight [UIScreen mainScreen].bounds.size.height
#define customShowSize CGSizeMake(200, 200);
  1. 定義屬性
// ScanCodeViewController是作者創(chuàng)建的VC , 用Navi推出, 寫入?yún)f(xié)議 (UIImagePickerControllerDelegate, UINavigationControllerDelegate 是為了 可以直接掃碼圖庫中的二維碼, 在Navi右上角創(chuàng)建button)
@interface ScanCodeViewController ()<AVCaptureMetadataOutputObjectsDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate>

/** 輸入數(shù)據(jù)源 */
@property (nonatomic, strong) AVCaptureDeviceInput *input;
/** 輸出數(shù)據(jù)源 */
@property (nonatomic, strong) AVCaptureMetadataOutput *output;
/** 輸入輸出的中間橋梁 負(fù)責(zé)把捕獲的音視頻數(shù)據(jù)輸出到輸出設(shè)備中 */
@property (nonatomic, strong) AVCaptureSession *session;
/** 相機(jī)拍攝預(yù)覽圖層 */
@property (nonatomic, strong) AVCaptureVideoPreviewLayer *layerView;
/** 預(yù)覽圖層尺寸 */
@property (nonatomic, assign) CGSize layerViewSize;
/** 有效掃碼范圍 */
@property (nonatomic, assign) CGSize showSize;
/** 作者自定義的View視圖 */
@property (nonatomic, strong) ShadowView *shadowView;

@end

  1. 創(chuàng)建二維碼掃碼

-(void)creatScanQR{
  
/** 創(chuàng)建輸入數(shù)據(jù)源 */
        AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];  //獲取攝像設(shè)備
        self.input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];  //創(chuàng)建輸出流

/** 創(chuàng)建輸出數(shù)據(jù)源 */
        self.output = [[AVCaptureMetadataOutput alloc] init];
        [self.output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];  //設(shè)置代理 在主線程里刷新

/** Session設(shè)置 */
        self.session = [[AVCaptureSession alloc] init];
        [self.session setSessionPreset:AVCaptureSessionPresetHigh];   //高質(zhì)量采集
        [self.session addInput:self.input];
        [self.session addOutput:self.output];
        //設(shè)置掃碼支持的編碼格式
        self.output.metadataObjectTypes = @[AVMetadataObjectTypeQRCode,
                                        AVMetadataObjectTypeEAN13Code,
                                        AVMetadataObjectTypeEAN8Code,
                                        AVMetadataObjectTypeCode128Code];
/** 掃碼視圖 */
         //掃描框的位置和大小
        self.layerView = [AVCaptureVideoPreviewLayer layerWithSession:self.session];
        self.layerView.videoGravity = AVLayerVideoGravityResizeAspectFill;
        self.layerView.frame = CGRectMake(0, 64, self.view.frame.size.width, self.view.frame.size.height - 64);
        // 將掃描框大小定義為屬行, 下面會(huì)有調(diào)用
        self.layerViewSize = CGSizeMake(_layerView.frame.size.width, _layerView.frame.size.height);

}

#pragma mark - 實(shí)現(xiàn)代理方法, 完成二維碼掃描
-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection{
  
    if (metadataObjects.count > 0) {
       
         // 停止動(dòng)畫, 看完全篇記得打開注釋, 不然掃描條會(huì)一直有動(dòng)畫效果
        //[self.shadowView stopTimer];

        //停止掃描
        [self.session stopRunning];
        
        AVMetadataMachineReadableCodeObject * metadataObject = [metadataObjects objectAtIndex : 0 ];
        //輸出掃描字符串
        NSLog(@"%@",metadataObject.stringValue);
        UIAlertView * alert = [[UIAlertView alloc]initWithTitle:@"提示" message:[NSString stringWithFormat:@"%@", metadataObject.stringValue] delegate:nil cancelButtonTitle:@"確定" otherButtonTitles:nil, nil];
        [alert show];
    }
}


  1. 調(diào)用方法
- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor whiteColor];
    
    //調(diào)用
    [self creatScanQR];
    //添加拍攝圖層
    [self.view.layer addSublayer:self.layerView];
    //開始二維碼
    [self.session startRunning];
    
    // Do any additional setup after loading the view.
}

至此 二維碼掃碼完成 , 你會(huì)發(fā)現(xiàn) 整個(gè)屏幕都可以掃碼二維碼, 與微信的二維碼掃碼 差的太多. 下面開始個(gè)性化設(shè)置

  1. 自定義陰影視圖層
#import <UIKit/UIKit.h>

@interface ShadowView : UIView

@property (nonatomic, assign) CGSize showSize;
- (void)stopTimer;

@end
#import "ShadowView.h"

@interface ShadowView ()

@property (nonatomic, strong) UIImageView *lineView;
@property (nonatomic, strong) NSTimer *timer;

@end

@implementation ShadowView

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        
        self.backgroundColor = [UIColor clearColor];
        // 圖片下方附上
        self.lineView  = [[UIImageView alloc] init];
        self.lineView.image = [UIImage imageNamed:@"line"];
        [self addSubview:self.lineView];

    }
    return self;
}

-(void)playAnimation{

    [UIView animateWithDuration:2.4 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
        
        self.lineView .frame = CGRectMake((self.frame.size.width - self.showSize.width) / 2, (self.frame.size.height + self.showSize.height) / 2, self.showSize.width, 2);
        
    } completion:^(BOOL finished) {
        self.lineView .frame = CGRectMake((self.frame.size.width - self.showSize.width) / 2, (self.frame.size.height - self.showSize.height) / 2, self.showSize.width, 2);
    }];
}

- (void)stopTimer
{
    [_timer invalidate];
    _timer = nil;    
}

-(void)layoutSubviews{
    
    [super layoutSubviews];
    
    self.lineView .frame = CGRectMake((self.frame.size.width - self.showSize.width) / 2, (self.frame.size.height - self.showSize.height) / 2, self.showSize.width, 2);
    
    
    if (!_timer) {
        
        [self playAnimation];
        
        /* 自動(dòng)播放 */
        self.timer = [NSTimer scheduledTimerWithTimeInterval:2.5 target:self selector:@selector(playAnimation) userInfo:nil repeats:YES];
        
    }
    
}

-(void)drawRect:(CGRect)rect{
    
    [super drawRect:rect];
    
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    
    // 整體顏色
    CGContextSetRGBFillColor(ctx, 0.15, 0.15, 0.15, 0.6);
    CGContextFillRect(ctx, rect);   //draw the transparent layer
        
    //中間清空矩形框
    CGRect clearDrawRect = CGRectMake((rect.size.width - self.showSize.width) / 2, (rect.size.height - self.showSize.height) / 2, self.showSize.width, self.showSize.height);
    CGContextClearRect(ctx, clearDrawRect);
   
    //邊框
    CGContextStrokeRect(ctx, clearDrawRect);
    CGContextSetRGBStrokeColor(ctx, 1, 1, 1, 1);  //顏色
    CGContextSetLineWidth(ctx, 0.5);             //線寬
    CGContextAddRect(ctx, clearDrawRect);       //矩形
    CGContextStrokePath(ctx);
    
    [self addCornerLineWithContext:ctx rect:clearDrawRect];
    
}

- (void)addCornerLineWithContext:(CGContextRef)ctx rect:(CGRect)rect{
    
    float cornerWidth = 4.0;
    
    float cornerLong = 16.0;
    
    //畫四個(gè)邊角 線寬
    CGContextSetLineWidth(ctx, cornerWidth);
    
    //顏色
    CGContextSetRGBStrokeColor(ctx, 83 /255.0, 239/255.0, 111/255.0, 1);//綠色
    
    //左上角
    CGPoint poinsTopLeftA[] = {CGPointMake(rect.origin.x + cornerWidth/2, rect.origin.y),
                               CGPointMake(rect.origin.x + cornerWidth/2, rect.origin.y + cornerLong)};
    
    CGPoint poinsTopLeftB[] = {CGPointMake(rect.origin.x, rect.origin.y + cornerWidth/2),
                               CGPointMake(rect.origin.x + cornerLong, rect.origin.y + cornerWidth/2)};
    
    [self addLine:poinsTopLeftA pointB:poinsTopLeftB ctx:ctx];
    
    
    //左下角
    CGPoint poinsBottomLeftA[] = {CGPointMake(rect.origin.x + cornerWidth/2, rect.origin.y + rect.size.height - cornerLong),
                                  CGPointMake(rect.origin.x + cornerWidth/2, rect.origin.y + rect.size.height)};
    
    CGPoint poinsBottomLeftB[] = {CGPointMake(rect.origin.x, rect.origin.y + rect.size.height - cornerWidth/2),
                                  CGPointMake(rect.origin.x + cornerLong, rect.origin.y + rect.size.height - cornerWidth/2)};
    
    [self addLine:poinsBottomLeftA pointB:poinsBottomLeftB ctx:ctx];
    
    
    //右上角
    CGPoint poinsTopRightA[] = {CGPointMake(rect.origin.x+ rect.size.width - cornerLong, rect.origin.y + cornerWidth/2),
                                CGPointMake(rect.origin.x + rect.size.width, rect.origin.y + cornerWidth/2 )};
    
    CGPoint poinsTopRightB[] = {CGPointMake(rect.origin.x+ rect.size.width - cornerWidth/2, rect.origin.y),
                                CGPointMake(rect.origin.x + rect.size.width- cornerWidth/2, rect.origin.y + cornerLong)};
    
    [self addLine:poinsTopRightA pointB:poinsTopRightB ctx:ctx];
    
    //右下角
    CGPoint poinsBottomRightA[] = {CGPointMake(rect.origin.x+ rect.size.width - cornerWidth/2, rect.origin.y+rect.size.height - cornerLong),
                                   CGPointMake(rect.origin.x- cornerWidth/2 + rect.size.width, rect.origin.y +rect.size.height )};
    
    CGPoint poinsBottomRightB[] = {CGPointMake(rect.origin.x+ rect.size.width - cornerLong, rect.origin.y + rect.size.height - cornerWidth/2),
                                   CGPointMake(rect.origin.x + rect.size.width, rect.origin.y + rect.size.height - cornerWidth/2 )};
    
    [self addLine:poinsBottomRightA pointB:poinsBottomRightB ctx:ctx];
    
    
    CGContextStrokePath(ctx);
}

- (void)addLine:(CGPoint[])pointA pointB:(CGPoint[])pointB ctx:(CGContextRef)ctx {
    
    CGContextAddLines(ctx, pointA, 2);
    CGContextAddLines(ctx, pointB, 2);
}


@end

line.png

注意 : 如果你對(duì)應(yīng)寫demo了, 并且真機(jī)測試的系統(tǒng)在ios7 以上, 會(huì)發(fā)現(xiàn)也許掃描線的初始位置會(huì)出現(xiàn)問題. 給個(gè)小提示 layoutSubviews 被執(zhí)行了兩次. 留個(gè)小尾巴. 讓大家思考.

傳送門 : 上述邊角畫圖方法, 作者引用 Raul7777 并附上鏈接 , 作者進(jìn)行了一下小改進(jìn) , 并添加注釋. 如果對(duì)你有幫助, 請(qǐng)給他點(diǎn)個(gè) Star

補(bǔ)充 : 掃描線動(dòng)畫, 用NSTimer, 偶爾手機(jī)處理卡頓下, 就會(huì)被坑. 作者看到有用 CABasicAnimation 寫的, 覺得挺好. 所以 提供下, 該方法


-(void)addAnimationAboutScan{
    
    self.lineView.hidden = NO;
    CABasicAnimation *animation = [ShadowView moveYTime:2.5 fromY:[NSNumber numberWithFloat:0] toY:[NSNumber numberWithFloat:(self.showSize.height-1)] rep:OPEN_MAX];
    [self.lineView.layer addAnimation:animation forKey:@"LineAnimation"];       
}

+ (CABasicAnimation *)moveYTime:(float)time fromY:(NSNumber *)fromY toY:(NSNumber *)toY rep:(int)rep{

    CABasicAnimation *animationMove = [CABasicAnimation animationWithKeyPath:@"transform.translation.y"];
    [animationMove setFromValue:fromY];
    [animationMove setToValue:toY];
    animationMove.duration = time;
    animationMove.delegate = self;
    animationMove.repeatCount  = rep;
    animationMove.fillMode = kCAFillModeForwards;
    animationMove.removedOnCompletion = NO;
    animationMove.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    return animationMove;
}

- (void)removeAnimationAboutScan{

    [self.lineView.layer removeAnimationForKey:@"LineAnimation"];
    self.lineView.hidden = YES;
}

  1. 回到ScanCodeViewController 配置掃碼范圍

重點(diǎn): 這是作者最想講的 . 附上官方介紹
rectOfInterest Property
A rectangle of interest for limiting the search area for visual metadata.
Discussion
The value of this property is a CGRect value that determines the object’s rectangle of interest for each frame of video.
The rectangle's origin is top left and is relative to the coordinate space of the device providing the metadata.
Specifying a rectangle of interest may improve detection performance for certain types of metadata. Metadata objects whose bounds do not intersect with the rectOfInterest will not be returned.
The default value of this property is a rectangle of (0.0, 0.0, 1.0, 1.0).

說明 :
看到矩形的原點(diǎn)是左上角, 但是真正測試 你會(huì)發(fā)現(xiàn)卻是在右上角, 因?yàn)閽叽a默認(rèn)是 橫屏, 所以原右上角變成左上角, 原寬變成高, 原高變成寬. 取值是按照 攝像頭分辨率 來取的比例 而不是屏幕的寬高比例.

屏幕寬高比例:
iPhone4 : [320 480] ; iPhone5: [320 568 ] ; iPhone 6 : [375 667] ; iPhone 6plus : [414 736].

作者設(shè)置 AVCaptureSessionPresetHigh 所以機(jī)型分辨率均為 1920×1080. 所以除了iPhone4 基本上 屏幕寬高比 符合 分辨率的比例. 會(huì)有些許誤差, 但影響不大. 如需支持包含iPhone4的所以機(jī)型 需要將 屏幕寬高與分辨率統(tǒng)一. 方法如下. 這樣便將 ShadowView 中間清空的矩形框有效掃碼范圍 對(duì)應(yīng)上了.

/** 配置掃碼范圍 */
-(void)allowScanRect{

   
    /** 掃描是默認(rèn)是橫屏, 原點(diǎn)在[右上角]
     *  rectOfInterest = CGRectMake(0, 0, 1, 1);
     *  AVCaptureSessionPresetHigh = 1920×1080   攝像頭分辨率
     *  需要轉(zhuǎn)換坐標(biāo) 將屏幕與 分辨率統(tǒng)一
     */
    
    //剪切出需要的大小位置
    CGRect shearRect = CGRectMake((self.layerViewSize.width - self.showSize.width) / 2,
                                  (self.layerViewSize.height - self.showSize.height) / 2,
                                  self.showSize.height,
                                  self.showSize.height);
    
    
    CGFloat deviceProportion = 1920.0 / 1080.0;
    CGFloat screenProportion = self.layerViewSize.height / self.layerViewSize.width;
    
    //分辨率比> 屏幕比 ( 相當(dāng)于屏幕的高不夠)
    if (deviceProportion > screenProportion) {
        //換算出 分辨率比 對(duì)應(yīng)的 屏幕高
        CGFloat finalHeight = self.layerViewSize.width * deviceProportion;
        // 得到 偏差值
        CGFloat addNum = (finalHeight - self.layerViewSize.height) / 2;

                                              // (對(duì)應(yīng)的實(shí)際位置 + 偏差值)  /  換算后的屏幕高
        self.output.rectOfInterest = CGRectMake((shearRect.origin.y + addNum) / finalHeight,
                                                 shearRect.origin.x / self.layerViewSize.width,
                                                 shearRect.size.height/ finalHeight,
                                                 shearRect.size.width/ self.layerViewSize.width);
        
    }else{
        
        CGFloat finalWidth = self.layerViewSize.height / deviceProportion;
        
        CGFloat addNum = (finalWidth - self.layerViewSize.width) / 2;
        
        self.output.rectOfInterest = CGRectMake(shearRect.origin.y / self.layerViewSize.height,
                                                (shearRect.origin.x + addNum) / finalWidth,
                                                shearRect.size.height / self.layerViewSize.height,
                                                shearRect.size.width / finalWidth);
    }

}
  1. 讀取相冊(cè)中二維碼

**注意事項(xiàng) **: ios8 以上系統(tǒng)才開放讀取相冊(cè)二維碼功能(CIDetectorTypeQRCode), 所以如iPhone4 該功能實(shí)現(xiàn)不了, 需要有判斷.


#pragma mark - 相冊(cè)中讀取二維碼
/* navi按鈕實(shí)現(xiàn) */
-(void)takeQRCodeFromPic:(UIBarButtonItem *)leftBar{
    
    
    
    if ([[[UIDevice currentDevice] systemVersion] doubleValue] < 8) {
        
        UIAlertView * alert = [[UIAlertView alloc]initWithTitle:@"提示" message:@"請(qǐng)更新系統(tǒng)至8.0以上!" delegate:nil cancelButtonTitle:@"確定" otherButtonTitles:nil, nil];
        [alert show];
        
    }else{
        
        if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]){
            
            UIImagePickerController *pickerC = [[UIImagePickerController alloc] init];
            pickerC.delegate = self;
            
            pickerC.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;  //來自相冊(cè)
            
            [self presentViewController:pickerC animated:YES completion:NULL];
            
        }else{
            
            UIAlertView * alert = [[UIAlertView alloc]initWithTitle:@"提示" message:@"設(shè)備不支持訪問相冊(cè),請(qǐng)?jiān)谠O(shè)置->隱私->照片中進(jìn)行設(shè)置!" delegate:nil cancelButtonTitle:@"確定" otherButtonTitles:nil, nil];
            [alert show];
        }
        
    }
    
    
}

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
    //1.獲取選擇的圖片
    UIImage *image = info[UIImagePickerControllerEditedImage];
    
    if (!image) {
        image = info[UIImagePickerControllerOriginalImage];
    }
    //2.初始化一個(gè)監(jiān)測器
    CIDetector*detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:nil options:@{ CIDetectorAccuracy : CIDetectorAccuracyHigh }];
    
    [picker dismissViewControllerAnimated:YES completion:^{
        
        //監(jiān)測到的結(jié)果數(shù)組  放置識(shí)別完之后的數(shù)據(jù)
        NSArray *features = [detector featuresInImage:[CIImage imageWithCGImage:image.CGImage]];
        //判斷是否有數(shù)據(jù)(即是否是二維碼)
        if (features.count >=1) {
            /**結(jié)果對(duì)象 */
            CIQRCodeFeature *feature = [features objectAtIndex:0];
            NSString *scannedResult = feature.messageString;
            
            UIAlertView * alertView = [[UIAlertView alloc]initWithTitle:@"提示" message:scannedResult delegate:nil cancelButtonTitle:@"確定" otherButtonTitles:nil, nil];
            [alertView show];
            
        }
        else{
            UIAlertView * alertView = [[UIAlertView alloc]initWithTitle:@"提示" message:@"該圖片沒有包含二維碼!" delegate:nil cancelButtonTitle:@"確定" otherButtonTitles:nil, nil];
            [alertView show];
            
        }
    }];
}

  1. 重寫調(diào)用
- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor whiteColor];
    
    //顯示范圍
     self.showSize = customShowSize;
    //調(diào)用
    [self creatScanQR];
    //添加拍攝圖層
    [self.view.layer addSublayer:self.layerView];
    //開始二維碼
    [self.session startRunning];
    //設(shè)置可用掃碼范圍
    [self allowScanRect];

   //添加上層陰影視圖
    self.shadowView = [[ShadowView alloc] initWithFrame:CGRectMake(0, 64, kWidth, kHeight - 64)];
    [self.view addSubview:self.shadowView];
    self.shadowView.showSize = self.showSize;
    
    
    //添加掃碼相冊(cè)按鈕
     self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"相冊(cè)中選" style:UIBarButtonItemStylePlain target:self action:@selector(takeQRCodeFromPic:)];
    
    // Do any additional setup after loading the view.
}

  1. 權(quán)限問題

權(quán)限問題 使用相機(jī)需要獲取相應(yīng)權(quán)限, 如用戶未開啟, 可以設(shè)置提醒, 留個(gè)小尾巴, 讀者自行設(shè)置.

三 iOS 二維碼生成

天聽云道的 [ iOS ] 生成二維碼 系統(tǒng)方法 這篇文章寫了, 挺簡單, 生成的是高清二維碼, 但是 在ios7系統(tǒng)上, 還是不清晰, 也就是說如果 你的程序支持到ios7 該方法有些問題.

船長_的 iOS的生成二維碼(彩色+陰影) 這篇文章寫了, 支持ios7 系統(tǒng), 高清二維碼.

所以對(duì)二維碼生成問題 作者就不贅述了. 對(duì)iOS中二維碼的講解完成.

四 三方二維碼鏈接

補(bǔ)充下三方傳送門 : https://github.com/MxABC/LBXScan
https://github.com/TheLevelUp/ZXingObjC

** 以上 ! **

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,363評(píng)論 6 532
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,497評(píng)論 3 416
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,305評(píng)論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,962評(píng)論 1 311
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,727評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,193評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,257評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,411評(píng)論 0 288
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,945評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,777評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,978評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,519評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,216評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,642評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,878評(píng)論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,657評(píng)論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,960評(píng)論 2 373

推薦閱讀更多精彩內(nèi)容