浅谈UIAlertView与UIAlertController

苹果在iOS8.0后推出了UIAlertController以代替UIAlertView,导致的后果就是UIAlertView在iOS9.0之后被deprecated了,也就是iOS8.0之后只能用UIAlertController,iOS8.0之前只能用UIAlertView。所以如果想同时兼容iOS7和iOS8,就判断一下系统的版本,demo代码如下:

http://www.2cto.com/kf/201604/504142.html#)

if([[[UIDevice currentDevice] systemVersion] floatValue] >=8.0) {   
// for iOS8

     UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"是否结束行程?" message:nil preferredStyle:UIAlertControllerStyleAlert];

     UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {

            [self.navigationController dismissViewController Animated:alertController completion:nil];    
     }];

     UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
         [self upload];
     }];

    [alertController addAction:cancelAction];        
    [alertController addAction:okAction];
    [self.navigationController presentViewController:alertController animated:YES completion:nil];
}else{
// for iOS7     

     self.uploadAlertView = [[UIAlertView alloc]  initWithTitle:@"是否结束行程?"   message:nil delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
   
    [self.uploadAlertView show];
}

if([[[UIDevice currentDevice] systemVersion] floatValue] >=8.0) {   
// for iOS8      
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"是否结束行程?" message:nil preferredStyle:UIAlertControllerStyleAlert];

    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {

        [self.navigationController dismissViewControllerAnimated:alertController completion:nil];    
    }];  

    UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        [self upload];
    }];

    [alertController addAction:cancelAction];

    [alertController addAction:okAction];

    [self.navigationController presentViewController:alertController animated:YES completion:nil];
}else{

// for iOS7
    self.uploadAlertView = [[UIAlertView alloc] initWithTitle:@"是否结束行程?" message:nil delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
    [self.uploadAlertView show];
}

if([[[UIDevice currentDevice] systemVersion] floatValue] >8.0) {    
// for iOS8 

 UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"是否结束行程?" message:nil preferredStyle:UIAlertControllerStyleAlert];

    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消"style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {

        [self.navigationController dismissViewControllerAnimated:alertController completion:nil];
    }];

    UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action{          
        [self upload];        
    }];

    [alertController addAction:cancelAction];
    [alertController addAction:okAction];
    [self.navigationController presentViewController:alertController animated:YES completion:nil];
}else{
// for iOS7
     self.uploadAlertView = [[UIAlertView alloc] initWithTitle:@"是否结束行程?" message:nil delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];      
     [self.uploadAlertView show];
}

if([[[UIDevice currentDevice] systemVersion] floatValue] >=8.0) {     
// for iOS8
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"是否结束行程?"message:nil preferredStyle:UIAlertControllerStyleAlert];

    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {

        [self.navigationController dismissViewControllerAnimated:alertController completion:nil];    
    }];

    
    UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"确定"style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        [self upload];
    }];
    [alertController addAction:cancelAction];       
    [alertController addAction:okAction];
    [self.navigationController presentViewController:alertController animated:YES completion:nil];
 }else{  
// for iOS7
    self.uploadAlertView = [[UIAlertView alloc] initWithTitle:@"是否结束行程?" message:nil delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];

     [self.uploadAlertView show];
}

if([[[UIDevice currentDevice] systemVersion] floatValue] >=8.0) {  
// for iOS8     

    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"是否结束行程?" message:nil preferredStyle:UIAlertControllerStyleAlert];

    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
        self.navigationController dismissViewControllerAnimated:alertController completion:nil];
    }];

    UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"确定"style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { self upload];}];
    [alertController addAction:cancelAction];
    [alertController addAction:okAction];
    [self.navigationController presentViewController:alertController animated:YES completion:nil];
}else{
// for iOS7
    
    self.uploadAlertView = [[UIAlertView alloc] initWithTitle:@"是否结束行程?" message:nil delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
    [self.uploadAlertView show];
}

当然苹果其实没有真正的把UIAlertView给deprecate掉,UIAlertView 在iOS8以后 可能会发生异常Bug而已。而且你也不知道它哪天真的就会把它给禁用了。所以最好还是做一下兼容判断处理。
iOS 8的新特性之一就是让接口更有适应性、更灵活,因此许多视图控制器的实现方式发生了巨大的变化。全新的UIPresentationController在实现视图控制器间的过渡动画效果和自适应设备尺寸变化效果(比如说旋转)中发挥了重要的作用,它有效地节省了程序员们的工作量(天地良心啊)。还有,某些旧的UIKit控件也同样发生了许多变化,比如说Alert Views、Action Sheets、Popovers以及Search Bar Controllers。本文将会对Alert Views和Action Sheets发生的改变进行一个大致的介绍,我们会采用Objective-C和swift两种语言同时进行代码说明。
UIAlertView
随着苹果上次iOS 5的发布,对话框视图样式出现在了我们面前,直到现在它都没有发生过很大的变化。下面的代码片段展示了如何初始化和显示一个带有“取消”和“好的”按钮的对话框视图。
Objective-C版本:

UIAlertView *alertview=[[UIAlertView alloc] initWithTitle:@"标题" message:@ "这个是UIAlertView的默认样式" delegate:selfcancelButtonTitle:@ "取消" otherButtonTitles:@"好的",nil];

[alertviewshow];

swift版本和Objective-C版本不同,在swift中,alertView的初始化只允许创建拥有一个取消按钮的对话框视图。或许您可以看到带有otherButtonTitles的init方法,但是很遗憾,这个方法是没有办法通过编译的。

varalertView=UIAlertView(title:"标题",message:"这个是UIAlertView的默认样式",delegate:self,cancelButtonTitle:"取消");

alertView.show()

要能够创建和上面Objective-C版本相同的对话框视图,我们可以采取曲线救国的方法,虽然麻烦了些,但是我们为了目的可以不择手段的,是吧?

 varalertView=UIAlertView()
 alertView.delegate=self
alertView.title="标题"
alertView.message="这个是UIAlertView的默认样式"
alertView.addButtonWithTitle("取消")
alertView.addButtonWithTitle("好的")
alertView.show()

您也可以通过更改UIAlertView的alertViewStyle属性来实现输入文字、密码甚至登录框的效果。

1416966945708911.png

UIAlertView文本对话框
1416966955321003.png

UIAlertView密码对话框
1416966961499607.png

UIAlertView登录对话框
UIAlertViewDelegate协议拥有响应对话框视图的按钮动作的回调方法。还有当文本框内容改变时,调用alertViewShouldEnableOtherButton:方法可以让按钮动态地可用或者不可用。
要说明一点,苹果官方现在并不提倡在iOS 8中使用UIAlertView,取而代之的是UIAlertController。下面我们就来介绍UIAlertController的使用方法。
UIAlertController
在iOS 8中,UIAlertController在功能上是和UIAlertView以及UIActionSheet相同的,UIAlertController以一种模块化替换的方式来代替这两货的功能和作用。是使用对话框(alert)还是使用上拉菜单(action sheet),就取决于在创建控制器时,您是如何设置首选样式的。
一个简单的对话框例子
您可以比较一下两种不同的创建对话框的代码,创建基础UIAlertController的代码和创建UIAlertView的代码非常相似:
Objective-C版本:

UIAlertController *alertController[UIAlertController  alertControllerWithTitle:@"标题" message:@"这个UIAlertController的默认样式" preferredStyle:UIAlertControllerStyleAlert];

swift版本:

varalertController=UIAlertController(title:"标题",message:"这个是UIAlertController的默认样式",preferredStyle:UIAlertControllerStyle.Alert)

同创建UIAlertView相比,我们无需指定代理,也无需在初始化过程中指定按钮。不过要特别注意第三个参数,要确定您选择的是对话框样式还是上拉菜单样式。
通过创建UIAlertAction的实例,您可以将动作按钮添加到控制器上。UIAlertAction由标题字符串、样式以及当用户选中该动作时运行的代码块组成。通过UIAlertActionStyle,您可以选择如下三种动作样式:常规(default)、取消(cancel)以及警示(destruective)。为了实现原来我们在创建UIAlertView时创建的按钮效果,我们只需创建这两个动作按钮并将它们添加到控制器上即可。
Objective-C版本:

UIAlertAction*cancelAction=[UIAlertActionactionWithTitle:@"取消" style:UIAlertActionStyleCancelhandler:nil];
UIAlertAction*okAction=[UIAlertActionactionWithTitle:@"好的" style:UIAlertActionStyleDefaulthandler:nil];
[alertControlleraddAction:cancelAction];
[alertControlleraddAction:okAction];

swift版本:

varcancelAction=UIAlertAction(title:"取消",style:UIAlertActionStyle.Cancel,handler:nil)

varokAction=UIAlertAction(title:"好的",style:UIAlertActionStyle.Default,handler:nil) alertController.addAction(cancelAction) alertController.addAction(okAction)

最后,我们只需显示这个对话框视图控制器即可:
Objective-C版本:

[self presentViewController:alertController animated:YEScompletion:nil];

swift版本:

self.presentViewController(alertController,animated:true,completion:nil)

1416967052393203.png

默认样式
按钮显示的次序取决于它们添加到对话框控制器上的次序。一般来说,根据苹果官方制定的《iOS 用户界面指南》,在拥有两个按钮的对话框中,您应当将取消按钮放在左边。要注意,取消按钮是唯一的,如果您添加了第二个取消按钮,那么你就会得到如下的一个运行时异常:
* Terminating app due to uncaught exception ‘NSInternalInconsistencyException’, reason: ‘UIAlertController can only have one action with a style of UIAlertActionStyleCancel’
异常信息简洁明了,我们在此就不赘述了。
“警示”样式
什么是“警示”样式呢?我们先不着急回答这个问题,先来看一下下面关于“警示”样式的简单示例。在这个示例中,我们将前面的示例中的“好的”按钮替换为了“重置”按钮。
Objective-C版本:

    UIAlertAction*resetAction=[UIAlertActionactionWithTitle:@"重置" style:UIAlertActionStyleDestructivehandler:nil];

    [alertControlleraddAction:resetAction];

swift版本:

varresetAction=UIAlertAction(title:"重置" ,style:UIAlertActionStyle.Destructive,handler:nil)

alertController.addAction(resetAction)

1416967112867112.png

“警示”样式
可以看出,我们新增的那个“重置”按钮变成了红色。根据苹果官方的定义,“警示”样式的按钮是用在可能会改变或删除数据的操作上。因此用了红色的醒目标识来警示用户。
文本对话框
UIAlertController极大的灵活性意味着您不必拘泥于内置样式。以前我们只能在默认视图、文本框视图、密码框视图、登录和密码输入框视图中选择,现在我们可以向对话框中添加任意数目的UITextField对象,并且可以使用所有的UITextField特性。当您向对话框控制器中添加文本框时,您需要指定一个用来配置文本框的代码块。
举个栗子吧,要重新建立原来的登录和密码样式对话框,我们可以向其中添加两个文本框,然后用合适的占位符来配置它们,最后将密码输入框设置使用安全文本输入。
Objective-C版本:

UIAlertController *alertController [UIAlertController  alertControllerWithTitle:@"文本对话框"message:@"登录和密码对话框示例" preferredStyle:UIAlertControllerStyleAlert];

[alertControlleraddTextFieldWithConfigurationHandler:^(UITextField*textField){
    textField.placeholder=@"登录";
 }];

[alertControlleraddTextFieldWithConfigurationHandler:^(UITextField*textField){
    textField.placeholder=@"密码";
   textField.secureTextEntry=YES;
}];

swift版本:

alertController.addTextFieldWithConfigurationHandler{ (textField:UITextField!)->Voidin
    textField.placeholder="登录"
}

alertController.addTextFieldWithConfigurationHandler{ (textField:UITextField!)->Voidin
    textField.placeholder="密码"
    textField.secureTextEntry=true
}

在“好的”按钮按下时,我们让程序读取文本框中的值。
Objective-C版本:

UIAlertAction  *okAction=[UIAlertActionaction WithTitle:@"好的" style:UIAlertActionStyleDefaulthandler:^(UIAlertAction*action){
   UITextField *login=alertController.textFields.firstObject;
   UITextField*password=alertController.textFields.lastObject;
...
}];

swift版本:

varokAction=UIAlertAction(title:"好的", style:UIAlertActionStyle.Default){
    (action:UIAlertAction!)->Voidin
    varlogin=alertController.textFields?.firstasUITextField
    varpassword=alertController.textFields?.lastasUITextField
}

如果我们想要实现UIAlertView中的委托方法alertViewShouldEnableOtherButton:方法的话可能会有一些复杂。假定我们要让“登录”文本框中至少有3个字符才能激活“好的”按钮。很遗憾的是,在UIAlertController中并没有相应的委托方法,因此我们需要向“登录”文本框中添加一个Observer。Observer模式定义对象间的一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。我们可以在构造代码块中添加如下的代码片段来实现。
Objective-C版本:

[alertControlleraddTextFieldWithConfigurationHandler:^(UITextField*textField){

...

    [[NSNotificationCenterdefaultCenter]addObserver:selfselector:@selector(alertTextFieldDidChange:)name:UITextFieldTextDidChangeNotificationobject:textField];

}];

swift版本:

alertController.addTextFieldWithConfigurationHandler{
    (textField:UITextField!)->Voidin
    ...

    NSNotificationCenter.defaultCenter().addObserver(self,selector:Selector("alertTextFieldDidChange:"),name:UITextFieldTextDidChangeNotification,object:textField)

}

当视图控制器释放的时候我们需要移除这个Observer,我们通过在每个按钮动作的handler代码块(还有其他任何可能释放视图控制器的地方)中添加合适的代码来实现它。比如说在okAction这个按钮动作中:
Objective-C版本:

UIAlertAction *okAction=[UIAlertActionaction WithTitle:@"好的"    style:UIAlertActionStyleDefaulthandler:^(UIAlertAction*action){
...     
    [[NSNotificationCenterdefaultCenter]removeObserver:selfname:UITextFieldTextDidChangeNotificationobject:nil];
}];

swift版本:

varokAction=UIAlertAction(title:"好的",style:UIAlertActionStyle.Default){
(action:UIAlertAction!)->Voidin
...
NSNotificationCenter.defaultCenter().removeObserver(self,name:UITextFieldTextDidChangeNotification,object:nil)
}

在显示对话框之前,我们要冻结“好的”按钮
Objective-C版本:

okAction.enabled=NO;

swift版本:

okAction.enabled=false

接下来,在通知观察者(notification observer)中,我们需要在激活按钮状态前检查“登录”文本框的内容。
Objective-C版本:

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

    UIAlertController  *alertController(UIAlertController*)self.presentedViewController;

    if(alertController){
         UITextField*login=alertController.textFields.firstObject;
        UIAlertAction*okAction=alertController.actions.lastObject;
        okAction.enabled=login.text.length>2;
    }
}

swift版本:

funcalertTextFieldDidChange(notification:NSNotification){
    varalertController=self.presentedViewControllerasUIAlertController?

    if(alertController!=nil){
        varlogin=alertController!.textFields?.firstasUITextField
        varokAction=alertController!.actions.lastasUIAlertAction
       okAction.enabled=countElements(login.text)>2
     }
}

1416967618423000.png

UIAlertController的登录和密码对话框示例
好了,现在对话框的“好的”按钮被冻结了,除非在“登录”文本框中输入3个以上的字符:
上拉菜单
当需要给用户展示一系列选择的时候(选择恐惧症患者杀手),上拉菜单就能够派上大用场了。和对话框不同,上拉菜单的展示形式和设备大小有关。在iPhone上(紧缩宽度),上拉菜单从屏幕底部升起。在iPad上(常规宽度),上拉菜单以弹出框的形式展现。
创建上拉菜单的方式和创建对话框的方式非常类似,唯一的区别是它们的形式。
Objective-C版本:

UIAlertControlle *alertController=[UIAlertController alertControllerWithTitle:@"保存或删除数据" message:@"删除数据将不可恢复"preferredStyle:UIAlertControllerStyleActionSheet];

swift版本:

varalertController=UIAlertController(title:"保存或删除数据",message:"删除数据将不可恢复",preferredStyle:UIAlertControllerStyle.ActionSheet)

添加按钮动作的方式和对话框相同。
Objective-C版本:

UIAlertAction *cancelAction=[UIAlertActionaction WithTitle:@"取消" style:UIAlertActionStyleCancelhandler:nil];

UIAlertAction *deleteAction=[UIAlertActionaction WithTitle:@"删除"style:UIAlertActionStyleDestructivehandler:nil];
UIAlertAction *archiveAction=[UIAlertActionactionWithTitle:@"保存" style:UIAlertActionStyleDefaulthandler:nil];
[alertControlleraddAction:cancelAction];
[alertControlleraddAction:deleteAction];
[alertControlleraddAction:archiveAction];

swift版本:

varcancelAction=UIAlertAction(title:"取消",style:UIAlertActionStyle.Cancel,handler:nil)
vardeleteAction=UIAlertAction(title:"删除",style:UIAlertActionStyle.Destructive,handler:nil)
vararchiveAction=UIAlertAction(title:"保存" ,style:UIAlertActionStyle.Default,handler:nil)
alertController.addAction(cancelAction)
alertController.addAction(deleteAction)
alertController.addAction(archiveAction)

您不能在上拉菜单中添加文本框,如果您强行作死添加了文本框,那么就会荣幸地得到一个运行时异常:

  • Terminating app due to uncaught exception ‘NSInternalInconsistencyException’, reason: ‘Text fields can only be added to an alert controller of style UIAlertControllerStyleAlert’
    同样,简单的异常说明,我们也不多说了。
    接下来我们就可以在iPhone或者其他紧缩宽度的设备上展示了,不出我们所料,运行得很成功。
    Objective-C版本:

      [self presentViewController:alertController animated:YEScompletion:nil];
    

swift版本:

self.presentViewController(alertController,animated:true,completion:nil)
1416967563883898.png

iPhone上的上拉菜单效果
如果上拉菜单中有“取消”按钮的话,那么它永远都会出现在菜单的底部,不管添加的次序是如何(就是这么任性)。其他的按钮将会按照添加的次序从上往下依次显示。《iOS 用户界面指南》要求所有的“毁坏”样式按钮都必须排名第一(红榜嘛,很好理解的,对不对?)。
别激动得太早,我们现在还有一个很严重的问题,这个问题隐藏得比较深。当我们使用iPad或其他常规宽度的设备时,就会得到一个运行时异常:
Terminating app due to uncaught exception ‘NSGenericException’, reason: ‘UIPopoverPresentationController (<_uialertcontrolleractionsheetregularpresentationcontroller: 0x7fc619588110="">) should have a non-nil sourceView or barButtonItem set before the presentation occurs.’
就如我们之前所说,在常规宽度的设备上,上拉菜单是以弹出框的形式展现。弹出框必须要有一个能够作为源视图或者栏按钮项目的描点(anchor point)。由于在本例中我们是使用了常规的UIButton来触发上拉菜单的,因此我们就将其作为描点。
在iOS 8中我们不再需要小心翼翼地计算出弹出框的大小,UIAlertController将会根据设备大小自适应弹出框的大小。并且在iPhone或者紧缩宽度的设备中它将会返回nil值。配置该弹出框的代码如下:
Objective-C版本:

UIPopoverPresentationController*popover=alertController.popoverPresentationController;

if(popover){
 popover.sourceView=sender;
 popover.sourceRect=sender.bounds;
 popover.permittedArrowDirections=UIPopoverArrowDirectionAny;
 }

swift版本:

varpopover=alertController.popoverPresentationController

if(popover!=nil){
    popover?.sourceView=sender
    popover?.sourceRect=sender.bounds
    popover?.permittedArrowDirections=UIPopoverArrowDirection.Any
}

1416967530355906.png

iPad上的上拉菜单效果
UIPopoverPresentationController类同样也是在iOS 8中新出现的类,用来替换UIPopoverController的。这个时候上拉菜单是以一个固定在源按钮上的弹出框的形式显示的。
要注意UIAlertController在使用弹出框的时候自动移除了取消按钮。用户通过点击弹出框的外围部分来实现取消操作,因此取消按钮便不再必需。
释放对话框控制器
通常情况下,当用户选中一个动作后对话框控制器将会自行释放。不过您仍然可以在需要的时候以编程方式释放它,就像释放其他视图控制器一样。您应当在应用程序转至后台运行时移除对话框或者上拉菜单。假定我们正在监听UIApplicationDidEnterBackgroundNotification通知消息,我们可以在observer中释放任何显示出来的视图控制器。(参考在viewDidLoad方法中设立observer的示例代码)。
Objective-C版本:

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

    [[NSNotificationCenterdefaultCenter]removeObserver:selfname:UITextFieldTextDidChangeNotificationobject:nil];

    [self.presentedViewControllerdismissViewControllerAnimated:NOcompletion:nil];
}

swift版本:

funcdidEnterackground(notification:NSNotification){

 NSNotificationCenter.defaultCenter().removeObserver(self,name:UITextFieldTextDidChangeNotification,object:nil)

self.presentedViewController?.dismissViewControllerAnimated(false,completion:nil)

}

注意,要保证运行安全我们同样要确保移除所有的文本框observer。
我们来总结一下
这篇文章比较长,但是希望能够对您有所帮助。原先的UIAlertView和UIActionSheet类仍然可以在iOS 8中工作得很好,所以没有必要急于更换代码(要知道本文用到的许多函数尽在iOS 8中支持)。本文的代码可以在我的Github主页上找到,包括了AlertController - ObjC以及AlertController - swift。

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

推荐阅读更多精彩内容