零代碼解決iOS鍵盤遮擋問(wèn)題

這篇文章會(huì)對(duì) IQKeyboardManager 自動(dòng)解決鍵盤遮擋問(wèn)題的方法進(jìn)行分析。

最近在項(xiàng)目中使用了 IQKeyboardManager 來(lái)解決 UITextField 被鍵盤遮擋的問(wèn)題扁凛,這個(gè)框架的使用方法可以說(shuō)精簡(jiǎn)到了極致答毫,只需要將 IQKeyboardManager 加入 Podfile元镀,然后 pod install 就可以了库正。

說(shuō)是架構(gòu)分析雳灵,其實(shí)只是對(duì) IQKeyboardManager 中包含的類以及文件有一個(gè)粗略地了解哗脖,研究一下這個(gè)項(xiàng)目的層級(jí)是什么樣的。

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

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


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

這篇文章會(huì)主要分析 IQKeyboardManager 中解決的問(wèn)題芭逝,會(huì)用小篇幅介紹包含占位符(Placeholder) IQTextView 的實(shí)現(xiàn)塌碌。

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

在具體研究如何解決鍵盤遮擋問(wèn)題之前,我們先分析一下框架中最簡(jiǎn)單的一部分 IQTextView 是如何為 UITextView 添加占位符的旬盯。

@interface IQTextView : UITextView@endIQTextView 繼承自 UITextView台妆,它只是在 UITextView 上添加上了一個(gè) placeHolderLabel翎猛。在初始化時(shí),我們會(huì)為 UITextViewTextDidChangeNotification 注冊(cè)通知:- (void)initialize? {? ? [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshPlaceholder) name:UITextViewTextDidChangeNotification object:self];}在每次 UITextView 中的 text 更改時(shí)接剩,就會(huì)調(diào)用 refreshPlaceholder 方法更新 placeHolderLabel 的 alpha 值來(lái)隱藏或者顯示 label:

-(void)refreshPlaceholder {? ??

if ([[self text] length]) {? ? ??

? [placeHolderLabel setAlpha:0];? ?

?} else {? ? ? ?

?[placeHolderLabel setAlpha:1];? ?

?}? ??

[self setNeedsLayout];? ?

?[self layoutIfNeeded];

}IQKeyboardManager

下面就會(huì)進(jìn)入這篇文章的正題:IQKeyboardManager切厘。如果你對(duì) iOS 開發(fā)比較熟悉,可能會(huì)發(fā)現(xiàn)每當(dāng)一個(gè)類的名字中包含了 manager懊缺,那么這個(gè)類可能可能遵循單例模式疫稿,IQKeyboardManager 也不例外。IQKeyboardManager 的初始化當(dāng) IQKeyboardManager 初始化的時(shí)候鹃两,它做了這么幾件事情:監(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];

注冊(cè)與 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];

}

初始化一個(gè) UITapGestureRecognizer遗座,在點(diǎn)擊 UITextField 對(duì)應(yīng)的 UIWindow 的時(shí)候,收起鍵盤strongSelf.tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapRecognized:)];

- (void)tapRecognized:(UITapGestureRecognizer*)gesture {? ?

?if (gesture.state == UIGestureRecognizerStateEnded)? ? ? ? [self resignFirstResponder];

}

初始化一些默認(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];

設(shè)置不需要解決鍵盤遮擋問(wèn)題的類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];整個(gè)初始化方法大約有幾十行的代碼,在這里就不再展示整個(gè)方法的全部代碼了馋记『牌拢基于通知的解決方案在這里,我們以 UITextField 為例梯醒,分析方法的調(diào)用流程宽堆。在初始化方法中,我們注冊(cè)了很多的通知冤馏,包括鍵盤的出現(xiàn)和隱藏日麸,UITextField 開始編輯與結(jié)束編輯。UIKeyboardWillShowNotification? UIKeyboardWillHideNotification? UIKeyboardDidHideNotification? UITextFieldTextDidBeginEditingNotification? UITextFieldTextDidEndEditingNotification? 在這些通知響應(yīng)時(shí)逮光,會(huì)執(zhí)行以下的方法:| Notification | Selector | |:-:|:-:| | UIKeyboardWillShowNotification | @selector(keyboardWillShow:)| | UIKeyboardWillHideNotification | @selector(keyboardWillHide:) | | UIKeyboardDidHideNotification | @selector(keyboardDidHide:) | |UITextFieldTextDidBeginEditingNotification|@selector(textFieldViewDidBeginEditing:)| |UITextFieldTextDidEndEditingNotification|@selector(textFieldViewDidEndEditing:)|整個(gè)解決方案其實(shí)都是基于 iOS 中的通知系統(tǒng)的代箭;在事件發(fā)生時(shí),調(diào)用對(duì)應(yīng)的方法做出響應(yīng)涕刚。開啟 Debug 模式在閱讀源代碼的過(guò)程中嗡综,我發(fā)現(xiàn) IQKeyboardManager 提供了 enableDebugging 這一屬性,可以通過(guò)開啟它杜漠,來(lái)追蹤方法的調(diào)用极景,我們可以在 Demo 加入下面這行代碼:[IQKeyboardManager sharedManager].enableDebugging = YES;鍵盤的出現(xiàn)然后運(yùn)行工程,在 Demo 中點(diǎn)擊一個(gè) UITextFieldeasiest-integration-demo上面的操作會(huì)打印出如下所示的 Log:IQKeyboardManager: ****** textFieldViewDidBeginEditing: started ******? IQKeyboardManager: adding UIToolbars if required? IQKeyboardManager: Savingbeginning 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 ******? 我們可以通過(guò)分析 - textFieldViewDidBeginEditing: 以及 - keyboardWillShow: 方法來(lái)了解這個(gè)項(xiàng)目的原理驾茴。textFieldViewDidBeginEditing:當(dāng) UITextField 被點(diǎn)擊時(shí)盼樟,方法 - textFieldViewDidBeginEditing: 被調(diào)用,但是注意這里的方法并不是代理方法锈至,它只是一個(gè)跟代理方法同名的方法晨缴,根據(jù) Log,它做了三件事情:為 UITextField 添加 IQToolBar在調(diào)整 frame 前峡捡,保存當(dāng)前 frame击碗,以備之后鍵盤隱藏后的恢復(fù)調(diào)用 - adjustFrame 方法筑悴,將視圖移動(dòng)到合適的位置添加 ToolBar添加 ToolBar 是通過(guò)方法 - addToolbarIfRequired 實(shí)現(xiàn)的,在 - textFieldViewDidBeginEditing: 先通過(guò) - privateIsEnableAutoToolbar 判斷 ToolBar 是否需要添加稍途,再使用相應(yīng)方法 - addToolbarIfRequired 實(shí)現(xiàn)這一目的阁吝。這個(gè)方法會(huì)根據(jù)根視圖上 UITextField 的數(shù)量執(zhí)行對(duì)應(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 一般由三部分組成:切換 UITextField 的箭頭按鈕指示當(dāng)前 UITextField 的 placeholderDone ButtonIQToolBarIte這些 item 都是 IQBarButtonItem 的子類這些 IQBarButtonItem 以及 IQToolBar 都是通過(guò)方法 - 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];}上面是方法簡(jiǎn)化后的實(shí)現(xiàn)代碼械拍,初始化需要的 IQBarButtonItem突勇,然后將這些 IQBarButtonItem 全部加入到 IQToolBar 上,最后設(shè)置 UITextField 的 accessoryView殊者。保存 frame這一步的主要目的是為了在鍵盤隱藏時(shí)恢復(fù)到原來(lái)的狀態(tài)与境,其實(shí)現(xiàn)也非常簡(jiǎn)單:_rootViewController = [_textFieldView topMostController];? _topViewBeginRect = _rootViewController.view.frame;? 獲取 topMostController,在 _topViewBeginRect 中保存 frame猖吴。adjustFrame在上述的任務(wù)都完成之后摔刁,最后就需要調(diào)用 - adjustFrame 方法來(lái)調(diào)整當(dāng)前根試圖控制器的 frame 了:我們只會(huì)研究一般情況下的實(shí)現(xiàn)代碼,因?yàn)檫@個(gè)方法大約有 400 行代碼對(duì)不同情況下的實(shí)現(xiàn)有不同的路徑海蔽,包括有 lastScrollView共屈、含有 superScrollView 等等。而這里會(huì)省略絕大多數(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 的工作分為兩部分:計(jì)算 move 的距離調(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];}不過(guò)拗引,在 - textFieldViewDidBeginEditing: 的調(diào)用棧中,并沒有執(zhí)行 - setRootViewFrame: 來(lái)更新視圖的大小幌衣,因?yàn)辄c(diǎn)擊最上面的 UITextField 時(shí)矾削,不需要移動(dòng)視圖就能保證鍵盤不會(huì)遮擋 UITextField。keyboardWillShow:上面的代碼都是在鍵盤出現(xiàn)之前執(zhí)行的豁护,而這里的 - keyboardWillShow: 方法的目的是為了保證鍵盤出現(xiàn)之后哼凯,依然沒有阻擋 UITextField。因?yàn)槊恳粋€(gè) UITextField 對(duì)應(yīng)的鍵盤大小可能不同楚里,所以断部,這里通過(guò)檢測(cè)鍵盤大小是否改變,來(lái)決定是否調(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í)行了很多代碼都是用來(lái)保存一些關(guān)鍵信息的,比如通知對(duì)象达址、動(dòng)畫曲線蔑祟、動(dòng)畫時(shí)間。最關(guān)鍵的是更新鍵盤的大小沉唠,然后比較鍵盤的大小 CGSizeEqualToSize(_kbSize, oldKBSize) 來(lái)判斷是否執(zhí)行 - adjustFrame 方法做瞪。因?yàn)?- adjustFrame 方法的結(jié)果是依賴于鍵盤大小的,所以這里對(duì) - adjustFrame 是有意義并且必要的。鍵盤的隱藏通過(guò)點(diǎn)擊 IQToolBar 上面的 done 按鈕装蓬,鍵盤就會(huì)隱藏:IQKeyboardManager-hide-keyboard鍵盤隱藏的過(guò)程中會(huì)依次調(diào)用下面的三個(gè)方法:- keyboardWillHide:- textFieldViewDidEndEditing:- keyboardDidHide:IQKeyboardManager: ****** keyboardWillHide: started ******? IQKeyboardManager: Restoringframe to : {{0, 0}, {320, 568}}

IQKeyboardManager: ****** keyboardWillHide: ended ******

IQKeyboardManager: ****** textFieldViewDidEndEditing: started ******

IQKeyboardManager: ****** textFieldViewDidEndEditing: ended ******

IQKeyboardManager: ****** keyboardDidHide: started ******

IQKeyboardManager: ****** keyboardDidHide: ended ******

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

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

并不會(huì)給出該方法的全部代碼牍帚,只會(huì)給出關(guān)鍵代碼梳理它的工作流程。

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

_lastScrollView = nil;

_kbSize = CGSizeZero;

_startingContentInsets = UIEdgeInsetsZero;

_startingScrollIndicatorInsets = UIEdgeInsetsZero;

_startingContentOffset = CGPointZero;

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

- (void)textFieldViewDidEndEditing:(NSNotification*)notification{

[_textFieldView.window removeGestureRecognizer:_tapGesture];

_textFieldView = nil;

}

- (void)keyboardDidHide:(NSNotification*)aNotification {

_topViewBeginRect = CGRectZero;

}

UITextField 和 UITextView 通知機(jī)制

因?yàn)榭蚣艿墓δ苁腔谕ㄖ獙?shí)現(xiàn)的蹂随,所以通知的時(shí)序至關(guān)重要,在 IQKeyboardManagerConstants.h 文件中詳細(xì)地描述了在編輯 UITextField 的過(guò)程中因惭,通知觸發(fā)的先后順序岳锁。

notification-IQKeyboardManage

上圖準(zhǔn)確說(shuō)明了通知發(fā)出的時(shí)機(jī),透明度為 50% 的部分表示該框架沒有監(jiān)聽這個(gè)通知蹦魔。

而 UITextView 的通知機(jī)制與 UITextField 略有不同:

UITextView-Notification-IQKeyboardManage

當(dāng) Begin Editing 這個(gè)事件發(fā)生時(shí)激率,UITextView 的通知機(jī)制會(huì)先發(fā)出 UIKeyboardWillShowNotification 通知,而 UITextField 會(huì)先發(fā)出 UITextFieldTextDidBeginEditingNotification 通知勿决。

而這兩個(gè)通知的方法都調(diào)用了 - adjustFrame 方法來(lái)更新視圖的大小乒躺,最開始我并不清楚到底是為什么?直到我給作者發(fā)了一封郵件低缩,作者告訴我這么做的原因:

Good questions draveness. I'm very happy to answer your questions. There is a file in library IQKeyboardManagerConstants.h. You can find iOS Notification mechanism structure.

You'll find that for UITextField, textField notification gets fire first and then UIKeyboard notification fires.

For UITextView, UIKeyboard notification gets fire first and then UITextView notification get's fire.

So that's why I have to call adjustFrame at both places to fulfill both situations. But now I think I should add some validation and make sure to call it once to improve performance.

Let me know if you have some more questions, I would love to answer them. Thanks again to remind me about this issue.

在不同方法中調(diào)用通知的原因是嘉冒,UITextView 和 UITextField 通知機(jī)制的不同,不過(guò)作者可能會(huì)在未來(lái)的版本中修復(fù)這一問(wèn)題咆繁,來(lái)獲得性能上的提升讳推。

小結(jié)

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

雖然 IQKeyboardManager 很好地解決了這一問(wèn)題、為我們帶來(lái)了良好的體驗(yàn)壤短。不過(guò)设拟,由于其涉及 UI 層級(jí);并且需要考慮非常多的邊界以及特殊條件久脯,框架的代碼不是很容易閱讀纳胧,但是這不妨礙 IQKeyboardManager 成為非常優(yōu)秀的開源項(xiàng)目。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末帘撰,一起剝皮案震驚了整個(gè)濱河市跑慕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖核行,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件牢硅,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡芝雪,警方通過(guò)查閱死者的電腦和手機(jī)减余,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)惩系,“玉大人位岔,你說(shuō)我怎么就攤上這事”つ担” “怎么了抒抬?”我有些...
    開封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)晤柄。 經(jīng)常有香客問(wèn)我擦剑,道長(zhǎng),這世上最難降的妖魔是什么可免? 我笑而不...
    開封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任抓于,我火速辦了婚禮,結(jié)果婚禮上浇借,老公的妹妹穿的比我還像新娘捉撮。我一直安慰自己,他們只是感情好妇垢,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開白布巾遭。 她就那樣靜靜地躺著,像睡著了一般闯估。 火紅的嫁衣襯著肌膚如雪灼舍。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天涨薪,我揣著相機(jī)與錄音骑素,去河邊找鬼。 笑死刚夺,一個(gè)胖子當(dāng)著我的面吹牛献丑,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播侠姑,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼创橄,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了莽红?” 一聲冷哼從身側(cè)響起妥畏,我...
    開封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤邦邦,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后醉蚁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體燃辖,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年馍管,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了郭赐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡确沸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出俘陷,到底是詐尸還是另有隱情罗捎,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布拉盾,位于F島的核電站桨菜,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏捉偏。R本人自食惡果不足惜倒得,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望夭禽。 院中可真熱鬧霞掺,春花似錦、人聲如沸讹躯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)潮梯。三九已至骗灶,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間秉馏,已是汗流浹背耙旦。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留萝究,地道東北人免都。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像糊肤,于是被迫代替她去往敵國(guó)和親琴昆。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

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