IQKeyboardManager("零行代碼"解決鍵盤遮擋問題) 源碼分析

項(xiàng)目中鍵盤遮擋輸入框的問題我想一直都是讓人頭疼的問題 但是有了強(qiáng)大的IQKeyboardManager 這個(gè)框架 這個(gè)問題就不再是問題了

好了 以下就是本人對這個(gè)框架的一些理解

一 使用方法

這個(gè)框架的使用方法也是極其的簡單
只需要將 IQKeyboardManager 加入 Podfile,然后 pod install 就可以了。

pod 'IQKeyboardManager'
// iOS delegate內(nèi)應(yīng)用入口

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    //關(guān)閉設(shè)置為NO, 默認(rèn)值為NO.

    [IQKeyboardManager sharedManager ].enable = YES;

}

如果產(chǎn)品需要當(dāng)鍵盤彈起時(shí)盟戏,點(diǎn)擊背景收起鍵盤,也是一行代碼解決馏鹤。

[IQKeyboardManager sharedManager].shouldResignOnTouchOutside = YES;

而當(dāng)產(chǎn)品需要支持內(nèi)聯(lián)編輯(Inline Editing), 這就需要隱藏鍵盤上的工具條(默認(rèn)打開)

[IQKeyboardManager sharedManager].enableAutoToolbar = NO;

如果當(dāng)某一個(gè)輸入框特定不需要鍵盤上的工具條時(shí)搀缠,一行代碼

textField.inputAccessoryView = [[UIView alloc] init];

如果因?yàn)椴恢脑蛐枰谀硞€(gè)頁面禁止自動(dòng)鍵盤處理事件相應(yīng),也很簡單铝宵。

- (void) viewWillAppear: (BOOL)animated {
         //打開鍵盤事件相應(yīng)
          [IQKeyboardManager sharedManager].enable = YES;
}
- (void) viewWillDisappear: (BOOL)animated {
         //關(guān)閉鍵盤事件相應(yīng)
          [IQKeyboardManager sharedManager].enable = NO;
}

二 源碼分析

我們先看一下 IQKeyBoardManager中類的層級關(guān)系

image.png

整個(gè)項(xiàng)目中最核心的部分就是 IQKeyboardManager 這個(gè)類谦纱,它負(fù)責(zé)管理鍵盤出現(xiàn)或者隱藏時(shí)視圖移動(dòng)的距離看成,是整個(gè)框架中最核心的部分。

在這個(gè)框架中還有一些用于支持 IQKeyboardManager 的分類跨嘉,以及顯示在鍵盤上面的 IQToolBar:

image.png

使用紅色標(biāo)記的部分就是 IQToolBar川慌,左側(cè)的按鈕可以在不同的 UITextField 之間切換,中間的文字是 UITextField.placeholderText偿荷,右邊的 Done 應(yīng)該就不需要解釋了窘游。

這篇文章會主要分析 IQKeyboardManager 中解決的問題,會用小篇幅介紹包含占位符(Placeholder) IQTextView 的實(shí)現(xiàn)跳纳。

(1). IQTextView的實(shí)現(xiàn)

在具體研究如何解決鍵盤遮擋問題之前忍饰,我們先分析一下框架中最簡單的一部分 IQTextView 是如何為 UITextView 添加占位符的。

@interface IQTextView : UITextView

@end

IQTextView 繼承自 UITextView寺庄,它只是在 UITextView 上添加上了一個(gè) placeHolderLabel艾蓝。

在初始化時(shí),我們會為 UITextViewTextDidChangeNotification 注冊通知:

- (void)initialize   {
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshPlaceholder) name:UITextViewTextDidChangeNotification object:self];
}

在每次 UITextView 中的 text 更改時(shí)斗塘,就會調(diào)用 refreshPlaceholder 方法更新 placeHolderLabel 的 alpha 值來隱藏或者顯示 label:

-(void)refreshPlaceholder {
    if ([[self text] length]) {
        [placeHolderLabel setAlpha:0];
    } else {
        [placeHolderLabel setAlpha:1];
    }
    
    [self setNeedsLayout];
    [self layoutIfNeeded];
}

IQKeyboardManager

下面就會進(jìn)入這篇文章的正題:IQKeyboardManager赢织。

如果你對 iOS 開發(fā)比較熟悉,可能會發(fā)現(xiàn)每當(dāng)一個(gè)類的名字中包含了 manager馍盟,那么這個(gè)類可能可能遵循單例模式于置,IQKeyboardManager 也不例外

IQKeyboardManager 的初始化

當(dāng) IQKeyboardManager 初始化的時(shí)候,它做了這么幾件事情:

1 監(jiān)聽有關(guān)鍵盤的通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidHide:) name:UIKeyboardDidHideNotification object:nil];
2 注冊與 UITextField 以及 UITextView 有關(guān)的通知
[self registerTextFieldViewClass:[UITextField class]
 didBeginEditingNotificationName:UITextFieldTextDidBeginEditingNotification
   didEndEditingNotificationName:UITextFieldTextDidEndEditingNotification];

[self registerTextFieldViewClass:[UITextView class]
 didBeginEditingNotificationName:UITextViewTextDidBeginEditingNotification
   didEndEditingNotificationName:UITextViewTextDidEndEditingNotification];
 調(diào)用的方法將通知綁定到了 textFieldViewDidBeginEditing: 和 textFieldViewDidEndEditing: 方法上
- (void)registerTextFieldViewClass:(nonnull Class)aClass
  didBeginEditingNotificationName:(nonnull NSString *)didBeginEditingNotificationName
    didEndEditingNotificationName:(nonnull NSString *)didEndEditingNotificationName {
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textFieldViewDidBeginEditing:) name:didBeginEditingNotificationName object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textFieldViewDidEndEditing:) name:didEndEditingNotificationName object:nil];
}
3 初始化一個(gè) UITapGestureRecognizer贞岭,在點(diǎn)擊 UITextField 對應(yīng)的 UIWindow 的時(shí)候八毯,收起鍵盤
strongSelf.tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapRecognized:)];




- (void)tapRecognized:(UITapGestureRecognizer*)gesture {
    if (gesture.state == UIGestureRecognizerStateEnded)
        [self resignFirstResponder];
}
4 初始化一些默認(rèn)屬性搓侄,例如鍵盤距離、覆寫鍵盤的樣式等
strongSelf.animationDuration = 0.25;
strongSelf.animationCurve = UIViewAnimationCurveEaseInOut;
[self setKeyboardDistanceFromTextField:10.0];
[self setShouldPlayInputClicks:YES];
[self setShouldResignOnTouchOutside:NO];
[self setOverrideKeyboardAppearance:NO];
[self setKeyboardAppearance:UIKeyboardAppearanceDefault];
[self setEnableAutoToolbar:YES];
[self setPreventShowingBottomBlankSpace:YES];
[self setShouldShowTextFieldPlaceholder:YES];
[self setToolbarManageBehaviour:IQAutoToolbarBySubviews];
[self setLayoutIfNeededOnUpdate:NO];
5 設(shè)置不需要解決鍵盤遮擋問題的類
strongSelf.disabledDistanceHandlingClasses = [[NSMutableSet alloc] initWithObjects:[UITableViewController class], nil];
strongSelf.enabledDistanceHandlingClasses = [[NSMutableSet alloc] init];

strongSelf.disabledToolbarClasses = [[NSMutableSet alloc] init];
strongSelf.enabledToolbarClasses = [[NSMutableSet alloc] init];

strongSelf.toolbarPreviousNextAllowedClasses = [[NSMutableSet alloc] initWithObjects:[UITableView class],[UICollectionView class],[IQPreviousNextView class], nil];

strongSelf.disabledTouchResignedClasses = [[NSMutableSet alloc] init];
strongSelf.enabledTouchResignedClasses = [[NSMutableSet alloc] init];

基于通知的解決方案

在這里话速,我們以 UITextField 為例讶踪,分析方法的調(diào)用流程

在初始化方法中,我們注冊了很多的通知泊交,包括鍵盤的出現(xiàn)和隱藏乳讥,UITextField 開始編輯與結(jié)束編輯。

在這些通知響應(yīng)時(shí)廓俭,會執(zhí)行以下的方法

通知對應(yīng)的方法
UIKeyboardWillShowNotification ------>  @selector(keyboardWillShow:)

UIKeyboardWillHideNotification ------> @selector(keyboardWillHide:)

UIKeyboardDidHideNotification ------> @selector(keyboardDidHide:)

UITextFieldTextDidBeginEditingNotification ------> @selector(textFieldViewDidBeginEditing:)

UITextFieldTextDidEndEditingNotification ------> @selector(textFieldViewDidEndEditing:)

整個(gè)解決方案其實(shí)都是基于 iOS 中的通知系統(tǒng)的云石;在事件發(fā)生時(shí),調(diào)用對應(yīng)的方法做出響應(yīng)研乒。

開啟 Debug 模式

在閱讀源代碼的過程中留晚,我發(fā)現(xiàn) IQKeyboardManager 提供了 enableDebugging 這一屬性,可以通過開啟它告嘲,來追蹤方法的調(diào)用,我們可以在 Demo 加入下面這行代碼

[IQKeyboardManager sharedManager].enableDebugging = YES;

運(yùn)行demo

image.png

點(diǎn)擊圖中的textField 上邊的操作會打印出如下所示的log

IQKeyboardManager: ****** textFieldViewDidBeginEditing: started ******
IQKeyboardManager: adding UIToolbars if required
IQKeyboardManager: Saving <UINavigationController 0x7f905b01b000> beginning Frame: {{0, 0}, {320, 568}}
IQKeyboardManager: ****** adjustFrame started ******
IQKeyboardManager: Need to move: -451.00
IQKeyboardManager: ****** adjustFrame ended ******
IQKeyboardManager: ****** textFieldViewDidBeginEditing: ended ******
IQKeyboardManager: ****** keyboardWillShow: started ******
IQKeyboardManager: ****** adjustFrame started ******
IQKeyboardManager: Need to move: -154.00
IQKeyboardManager: ****** adjustFrame ended ******
IQKeyboardManager: ****** keyboardWillShow: ended ******

我們可以通過分析 - textFieldViewDidBeginEditing: 以及 - keyboardWillShow: 方法來了解這個(gè)項(xiàng)目的原理奖地。

textFieldViewDidBeginEditing:

當(dāng) UITextField 被點(diǎn)擊時(shí)橄唬,方法 - textFieldViewDidBeginEditing: 被調(diào)用,但是注意這里的方法并不是代理方法参歹,它只是一個(gè)跟代理方法同名的方法仰楚,根據(jù) Log,它做了三件事情:

1為 UITextField 添加 IQToolBar
2在調(diào)整 frame 前犬庇,保存當(dāng)前 frame僧界,以備之后鍵盤隱藏后的恢復(fù)
3調(diào)用 - adjustFrame 方法,將視圖移動(dòng)到合適的位置

添加 ToolBar

添加 ToolBar 是通過方法 - addToolbarIfRequired實(shí)現(xiàn)的臭挽,在 - textFieldViewDidBeginEditing: 先通過 - privateIsEnableAutoToolbar判斷 ToolBar 是否需要添加捂襟,再使用相應(yīng)方法 - addToolbarIfRequired實(shí)現(xiàn)這一目的。

這個(gè)方法會根據(jù)根視圖上 UITextField 的數(shù)量執(zhí)行對應(yīng)的代碼欢峰,下面為一般情況下執(zhí)行的代碼:

- (void)addToolbarIfRequired {
    NSArray *siblings = [self responderViews];
    for (UITextField *textField in siblings) {
        [textField addPreviousNextDoneOnKeyboardWithTarget:self previousAction:@selector(previousAction:) nextAction:@selector(nextAction:) doneAction:@selector(doneAction:) shouldShowPlaceholder:_shouldShowTextFieldPlaceholder];
        textField.inputAccessoryView.tag = kIQPreviousNextButtonToolbarTag;

        IQToolbar *toolbar = (IQToolbar*)[textField inputAccessoryView];
        toolbar.tintColor = [UIColor blackColor];
        [toolbar setTitle:textField.drawingPlaceholderText];
        [textField setEnablePrevious:NO next:YES];
    }

在鍵盤上的 IQToolBar 一般由三部分組成:
1 切換 UITextField 的箭頭按鈕
2 指示當(dāng)前 UITextField 的 placeholder
3 Done Button

image.png

這些 item 都是 IQBarButtonItem 的子類

這些 IQBarButtonItem 以及IQToolBar 都是通過方法 - addPreviousNextDoneOnKeyboardWithTarget:previousAction:nextAction:doneAction:或者類似方法添加的:

- (void)addPreviousNextDoneOnKeyboardWithTarget:(id)target previousAction:(SEL)previousAction nextAction:(SEL)nextAction doneAction:(SEL)doneAction titleText:(NSString*)titleText {
    IQBarButtonItem *prev = [[IQBarButtonItem alloc] initWithImage:imageLeftArrow style:UIBarButtonItemStylePlain target:target action:previousAction];
    IQBarButtonItem *next = [[IQBarButtonItem alloc] initWithImage:imageRightArrow style:UIBarButtonItemStylePlain target:target action:nextAction];
    IQTitleBarButtonItem *title = [[IQTitleBarButtonItem alloc] initWithTitle:self.shouldHideTitle?nil:titleText];
    IQBarButtonItem *doneButton =[[IQBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:target action:doneAction];

    IQToolbar *toolbar = [[IQToolbar alloc] init];
    toolbar.barStyle = UIBarStyleDefault;
    toolbar.items = @[prev, next, title, doneButton];
    toolbar.titleInvocation = self.titleInvocation;
    [(UITextField*)self setInputAccessoryView:toolbar];
}

上面是方法簡化后的實(shí)現(xiàn)代碼葬荷,初始化需要的 IQBarButtonItem,然后將這些 IQBarButtonItem 全部加入到 IQToolBar上纽帖,最后設(shè)置 UITextField accessoryView

保存 frame

這一步的主要目的是為了在鍵盤隱藏時(shí)恢復(fù)到原來的狀態(tài)宠漩,其實(shí)現(xiàn)也非常簡單:

_rootViewController = [_textFieldView topMostController];
_topViewBeginRect = _rootViewController.view.frame;

獲取 topMostController,在 _topViewBeginRect 中保存 frame懊直。

adjustFrame

在上述的任務(wù)都完成之后扒吁,最后就需要調(diào)用 - adjustFrame方法來調(diào)整當(dāng)前根試圖控制器的frame了:

我們只會研究一般情況下的實(shí)現(xiàn)代碼,因?yàn)檫@個(gè)方法大約有 400 行代碼對不同情況下的實(shí)現(xiàn)有不同的路徑室囊,包括有 lastScrollView雕崩、含有 superScrollView 等等魁索。

而這里會省略絕大多數(shù)情況下的實(shí)現(xiàn)代碼。

我們只會研究一般情況下的實(shí)現(xiàn)代碼晨逝,因?yàn)檫@個(gè)方法大約有 400 行代碼對不同情況下的實(shí)現(xiàn)有不同的路徑蛾默,包括有 lastScrollView、含有 superScrollView 等等捉貌。
而這里會省略絕大多數(shù)情況下的實(shí)現(xiàn)代碼支鸡。

- (void)adjustFrame {
    UIWindow *keyWindow = [self keyWindow];
    UIViewController *rootController = [_textFieldView topMostController];    
    CGRect textFieldViewRect = [[_textFieldView superview] convertRect:_textFieldView.frame toView:keyWindow];
    CGRect rootViewRect = [[rootController view] frame];
    CGSize kbSize = _kbSize;
    kbSize.height += keyboardDistanceFromTextField;
    CGFloat topLayoutGuide = CGRectGetHeight(statusBarFrame);
    CGFloat move = MIN(CGRectGetMinY(textFieldViewRect)-(topLayoutGuide+5), CGRectGetMaxY(textFieldViewRect)-(CGRectGetHeight(keyWindow.frame)-kbSize.height));
    
    if (move >= 0) {
        rootViewRect.origin.y -= move;
        [self setRootViewFrame:rootViewRect];
    } else {
        CGFloat disturbDistance = CGRectGetMinY(rootViewRect)-CGRectGetMinY(_topViewBeginRect);
        if (disturbDistance < 0) {
            rootViewRect.origin.y -= MAX(move, disturbDistance);
            [self setRootViewFrame:rootViewRect];
        }
    }
}

方法 - adjustFrame的工作分為兩部分
1 計(jì)算 move的距離

2 調(diào)用 - setRootViewFrame:方法設(shè)置 rootView 的大小

- (void)setRootViewFrame:(CGRect)frame {
    UIViewController *controller = [_textFieldView topMostController];    
    frame.size = controller.view.frame.size;

    [UIView animateWithDuration:_animationDuration delay:0 options:(_animationCurve|UIViewAnimationOptionBeginFromCurrentState) animations:^{
        [controller.view setFrame:frame];
    } completion:NULL];
}

不過,在 - textFieldViewDidBeginEditing: 的調(diào)用棧中趁窃,并沒有執(zhí)行 - setRootViewFrame: 來更新視圖的大小牧挣,因?yàn)辄c(diǎn)擊最上面的 UITextField 時(shí),不需要移動(dòng)視圖就能保證鍵盤不會遮擋 UITextField醒陆。

keyboardWillShow:

上面的代碼都是在鍵盤出現(xiàn)之前執(zhí)行的瀑构,而這里的 - keyboardWillShow:方法的目的是為了保證鍵盤出現(xiàn)之后,依然沒有阻擋 UITextField刨摩。

因?yàn)槊恳粋€(gè) UITextField對應(yīng)的鍵盤大小可能不同寺晌,所以,這里通過檢測鍵盤大小是否改變澡刹,來決定是否調(diào)用 - adjustFrame 方法更新視圖的大小呻征。

- (void)keyboardWillShow:(NSNotification*)aNotification {
    _kbShowNotification = aNotification;
    
    _animationCurve = [[aNotification userInfo][UIKeyboardAnimationCurveUserInfoKey] integerValue];
    _animationCurve = _animationCurve<<16;
    CGFloat duration = [[aNotification userInfo][UIKeyboardAnimationDurationUserInfoKey] floatValue];
    if (duration != 0.0)    _animationDuration = duration;
    
    CGSize oldKBSize = _kbSize;
    CGRect kbFrame = [[aNotification userInfo][UIKeyboardFrameEndUserInfoKey] CGRectValue];
    CGRect screenSize = [[UIScreen mainScreen] bounds];
    CGRect intersectRect = CGRectIntersection(kbFrame, screenSize);

    if (CGRectIsNull(intersectRect)) {
        _kbSize = CGSizeMake(screenSize.size.width, 0);
    } else {
        _kbSize = intersectRect.size;
    }
 
    if (!CGSizeEqualToSize(_kbSize, oldKBSize)) {
        [self adjustFrame];
    }
}

- adjustFrame方法調(diào)用之前,執(zhí)行了很多代碼都是用來保存一些關(guān)鍵信息的罢浇,比如通知對象陆赋、動(dòng)畫曲線、動(dòng)畫時(shí)間嚷闭。

最關(guān)鍵的是更新鍵盤的大小攒岛,然后比較鍵盤的大小 CGSizeEqualToSize(_kbSize, oldKBSize) 來判斷是否執(zhí)行 - adjustFrame 方法。

因?yàn)?- adjustFrame 方法的結(jié)果是依賴于鍵盤大小的胞锰,所以這里對 - adjustFrame 是有意義并且必要的灾锯。

鍵盤的隱藏

通過點(diǎn)擊 IQToolBar 上面的done按鈕,鍵盤就會隱藏

image.png

鍵盤隱藏的過程中會依次調(diào)用下面的三個(gè)方法:

  • - keyboardWillHide
  • - textFieldViewDidEndEditing:
  • - keyboardDidHide:
IQKeyboardManager: ****** keyboardWillHide: started ******
IQKeyboardManager: Restoring <UINavigationController 0x7fbaa4009e00> frame to : {{0, 0}, {320, 568}}
IQKeyboardManager: ****** keyboardWillHide: ended ******
IQKeyboardManager: ****** textFieldViewDidEndEditing: started ******
IQKeyboardManager: ****** textFieldViewDidEndEditing: ended ******
IQKeyboardManager: ****** keyboardDidHide: started ******
IQKeyboardManager: ****** keyboardDidHide: ended ******

鍵盤在收起時(shí)嗅榕,需要將視圖恢復(fù)至原來的位置挠进,而這也就是 - keyboardWillHide:方法要完成的事情:

[strongSelf.rootViewController.view setFrame:strongSelf.topViewBeginRect]

在重新設(shè)置視圖的大小以及位置之后,會對之前保存的屬性進(jìn)行清理:

_lastScrollView = nil;
_kbSize = CGSizeZero;
_startingContentInsets = UIEdgeInsetsZero;
_startingScrollIndicatorInsets = UIEdgeInsetsZero;
_startingContentOffset = CGPointZero;

而之后調(diào)用的兩個(gè)方法 - textFieldViewDidEndEditing:以及- keyboardDidHide:也只做了很多簡單的清理工作誊册,包括添加到 window上的手勢领突,并重置保存的UITextField 和視圖的大小。

- (void)textFieldViewDidEndEditing:(NSNotification*)notification{
    [_textFieldView.window removeGestureRecognizer:_tapGesture];
    _textFieldView = nil;
}

- (void)keyboardDidHide:(NSNotification*)aNotification {
    _topViewBeginRect = CGRectZero;
}

小結(jié)

IQKeyboardManager 使用通知機(jī)制來解決鍵盤遮擋輸入框的問題案怯,因?yàn)槭褂昧朔诸惒⑶以?code>IQKeyboardManager 的 + load 方法中激活了框架的使用君旦,所以達(dá)到了零行代碼解決這一問題的效果。

雖然 IQKeyboardManager很好地解決了這一問題、為我們帶來了良好的體驗(yàn)金砍。不過局蚀,由于其涉及 UI 層級;并且需要考慮非常多的邊界以及特殊條件恕稠,框架的代碼不是很容易閱讀琅绅,但是這不妨礙IQKeyboardManager 成為非常優(yōu)秀的開源項(xiàng)目

<部分借鑒網(wǎng)絡(luò)>

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市鹅巍,隨后出現(xiàn)的幾起案子千扶,更是在濱河造成了極大的恐慌,老刑警劉巖骆捧,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件澎羞,死亡現(xiàn)場離奇詭異,居然都是意外死亡敛苇,警方通過查閱死者的電腦和手機(jī)妆绞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來枫攀,“玉大人括饶,你說我怎么就攤上這事±凑牵” “怎么了巷帝?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長扫夜。 經(jīng)常有香客問我,道長驰徊,這世上最難降的妖魔是什么笤闯? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮棍厂,結(jié)果婚禮上颗味,老公的妹妹穿的比我還像新娘。我一直安慰自己牺弹,他們只是感情好浦马,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著张漂,像睡著了一般晶默。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上航攒,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天磺陡,我揣著相機(jī)與錄音,去河邊找鬼。 笑死币他,一個(gè)胖子當(dāng)著我的面吹牛坞靶,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蝴悉,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼彰阴,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了拍冠?” 一聲冷哼從身側(cè)響起尿这,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎倦微,沒想到半個(gè)月后妻味,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡欣福,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年责球,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拓劝。...
    茶點(diǎn)故事閱讀 40,102評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡雏逾,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出郑临,到底是詐尸還是另有隱情栖博,我是刑警寧澤,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布厢洞,位于F島的核電站仇让,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏躺翻。R本人自食惡果不足惜丧叽,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望公你。 院中可真熱鬧踊淳,春花似錦、人聲如沸陕靠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽剪芥。三九已至垄开,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間税肪,已是汗流浹背说榆。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工虚吟, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人签财。 一個(gè)月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓串慰,卻偏偏與公主長得像,于是被迫代替她去往敵國和親唱蒸。 傳聞我的和親對象是個(gè)殘疾皇子邦鲫,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評論 2 355

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