Flutter入门五:【我的】+【通讯录】

Flutter入门 学习大纲

  1. 状态栏颜色
  2. 【我的】页面
  3. 【通讯录】页面

1. 状态栏颜色

iOS顶部状态栏白色黑色Flutter中,可以通过设置主题色的深浅,自动修改顶部状态栏颜色:

  • primaryColor: Colors.blue主题色设置为深色时,状态栏白色:
    image.png
  • primaryColor: Colors.white主题色设置为浅色时,状态栏黑色:
    image.png

导航栏背景标题颜色分割线、通过页面appBar属性可以设置。

appBar: AppBar(
    backgroundColor: widget._themeColor, // 导航栏背景色
    centerTitle: true, // (安卓)导航栏标题居中
    title: Text( "朋友圈", 
                style: TextStyle(color: Colors.black), //标题颜色),
    elevation: 0.0 )// 去除分割线
  • main.dart完整代码:
import 'package:flutter/material.dart';
import 'package:wechat_demo/pages/root_page.dart';

void main() => runApp(App());

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Wechat Demo', // 安卓需要,后台切换app时展示的名称(iOS中名称与APP名称一致)
      debugShowCheckedModeBanner: false, // 隐藏debug角标
      home: RootPage(),
      theme: ThemeData(
        primaryColor: Colors.white, // 主题色
        highlightColor: Color.fromRGBO(0, 0, 0, 0), // 去除高亮色
        splashColor: Color.fromRGBO(0, 0, 0, 0), // 去除水波纹
      ),
    );
  }
}

2.【我的】页面

  • 布局分析:


    image.png
  • 布局方式不唯一,以下仅供参考
  1. 顶部固定悬浮相机,背后使用ListView展示内容,选用Stack
  2. 头部有左右和上下多种布局,可使用RowStack结合展示,利用主轴对齐方式aligment对齐方式,实现布局要求。

【相关知识点】

  1. 隐藏状态栏间距
MediaQuery.removePadding(
   removeTop: true, // 移除顶部内边距
   context: context, // 指定上下文
   child: XXX),
  1. 圆角头像:
// 头像
Container( 
   width: 55, height: 55,
   // 圆角 (需要宽高)
   decoration: BoxDecoration(
       borderRadius: BorderRadius.circular(8.0), // 设置圆角
       image: DecorationImage(image:  AssetImage("images/HT.png"), fit: >BoxFit.fill))), // 图片填充              
  1. 屏幕相关属性:
  • 屏幕宽度MediaQuery.of(context).size.width;
  • 状态栏高度MediaQuery.of(context).padding.top;
  • 文件位置调整:(按模块分类文件夹

    image.png

  • const 全局常量函数声明

import 'package:flutter/material.dart';

// 微信主题色
Color Wechat_themeColor = Color.fromRGBO(220, 220, 220, 1.0);

// 屏幕宽度(必须传入MaterialApp的contrext)
double ScreenWidth(BuildContext context) => MediaQuery.of(context).size.width;

// 状态栏高度
double StatusBarHeight(BuildContext context) => MediaQuery.of(context).padding.top;
  • mine我的页面代码(主要是UI布局,响应事件滚动顶部背景白色未处理):
import 'package:flutter/material.dart';
import 'package:wechat_demo/const.dart';
import 'package:wechat_demo/pages/discover/discover_cell.dart';

class MinePage extends StatefulWidget {
  @override
  _MinePageState createState() => _MinePageState();
}

class _MinePageState extends State<MinePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        backgroundColor: Wechat_themeColor,
        body: Stack(
          children: <Widget>[
            Container(
              child: MediaQuery.removePadding(
                removeTop: true,
                context: context,
                child: ListView(
                  children: [
                    headerView(), // 头部
                    SizedBox(height: 8),
                    DiscoverCell(imageName: "images/微信支付.png", title: "支付"),
                    SizedBox(height: 8),
                    DiscoverCell(imageName: "images/微信收藏.png", title: "收藏"),
                    sepectorLine(),
                    DiscoverCell(imageName: "images/微信相册.png", title: "相册"),
                    sepectorLine(),
                    DiscoverCell(imageName: "images/微信卡包.png", title: "卡包"),
                    sepectorLine(),
                    DiscoverCell(imageName: "images/微信表情.png", title: "表情"),
                    SizedBox(height: 8),
                    DiscoverCell(imageName: "images/微信设置.png", title: "设置")
                  ],
                ),
              ),
            ),
            Container(
              margin: EdgeInsets.only(top: StatusBarHeight(context)),
              padding: EdgeInsets.only(right: 16),
              // 状态栏间距
              height: 25,
              child: Row(
                mainAxisAlignment: MainAxisAlignment.end,
                children: [Image(image: AssetImage("images/相机.png"))],
              ),
            )
          ],
        ));
  }

  // 头部视图
  Widget headerView() {
    return Container(
        padding: EdgeInsets.only(
            top: StatusBarHeight(context) + 35,
            left: 20,
            right: 10,
            bottom: 30),
        color: Colors.white,
        child: Container(
          child: Row(
            children: <Widget>[
              // 头像
              Container(
                  width: 55,
                  height: 55,
                  // 圆角 (需要宽高)
                  decoration: BoxDecoration(
                      borderRadius: BorderRadius.circular(8.0), // 设置圆角
                      image: DecorationImage(  // 这是图片,fill填充
                          image: AssetImage("images/HT.png"), fit: BoxFit.fill))),
              // 昵称等
              Container(
                margin: EdgeInsets.only(left: 20),
                child: Container(
                  width: ScreenWidth(context) - 85 - 20,
                  child: Column(
                    children: [
                      Container(
                        height: 20,
                        child: Container(alignment: Alignment.centerLeft, child: Text("H", style: TextStyle(color: Colors.black, fontSize: 20, fontWeight: FontWeight.bold))),
                      ),
                      Container(
                        margin: EdgeInsets.only(top: 10),
                        height: 20,
                        child: Row(
                          mainAxisAlignment: MainAxisAlignment.spaceBetween,
                            children: [
                              Container(
                                child: Text("微信号: wechat_mark", style: TextStyle(color: Colors.grey,)),
                              ),// 微信号
                              Row(
                                  children: [
                                    Image(image: AssetImage("images/微信二维码.png"), width: 16, height: 16,),
                                    SizedBox(width: 8),
                                    Image(image: AssetImage("images/icon_right.png"), width: 14, height: 14,)
                                  ]
                              )
                            ],
                        ),
                      )
                    ],
                  ),
                ),
              )
            ],
          ),
        ));
  }

  // 分割线
  Widget sepectorLine() {
    return Container(
        height: 1,
        child: Row(children: [
          Container(width: 40, color: Colors.white),
          Container()
        ]));
  }
}

3.【通讯录】页面

image.png
  • 页面分析:

页面分为导航栏滚动内容索引栏。(滚动视图索引栏使用Stack布局)

一、 导航栏:

  1. 设置背景颜色字体颜色,隐藏分割线
  2. 添加新增朋友按钮(通过AppBaractions属性添加手势Widget

二、滚动内容

  1. 【布局】每个数据都是一个cell视图,都包含组头(灰色字母头部)和好友信息(头像名称分割线)。组头cell数据决定是否创建。
    组头好友信息使用Column布局,好友信息内部头像名称+分割线使用Row布局,根据屏幕宽度计算宽度名称分割线使用Column布局,指定高度

2.【数据】_headDatas记录顶部4个固定数据(新的朋友、群聊、标签、公众号),_listDatas记录其余好友数据,根据首字母进行 排序
initState()时,使用_groupOffsets(Map结构)记录每个索引offset偏移值

  1. 【交互】 使用ScrollController滚动对象记录当前的listViewIndexBar索引栏选中索引时,通过indexBarCallBack回调函数的index参数,在_groupOffsets(Map结构)中获取到指定高度,通过_scrollController.animateTo滚动到listView指定高度。

三、索引栏

  1. 【布局】 有索引栏选中气泡两大部件,使用Row布局。
    分为选中(背景透明、字体黑色、无气泡)和未选中(背景灰色、字体白色、展示气泡)两种状态。
  2. 【数据】INDEX_WORDS包含搜索星标A~Z 28组数据。
  3. 【交互】选中未选中会在自身布局上发生变化。也会通过indexBarCallBack函数,传递int类型的索引Index值,告知外部(外部listView会联动响应
  4. 【优化点】
    index默认值-1,避免每次进入页面时,listView滚动值index索引不一致。
    滚动时,index值未变化不会触发indexBarCallBack回调

四、缺陷

  1. 每次进入页面,数据均刷新了,未保存状态
  2. listView的偏移值过大时(剩余内容高度不足listView满屏),不应滚动
  • 文件夹:
    新建friends文件夹,新增cell数据ModelIndexBar索引部件文件。将friends_page.dart主页面移到friends文件夹:

    image.png

  • cell文件代码(friends_cell.dart):

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:wechat_demo/const.dart';

class FriendCell extends StatelessWidget {

  final String imageAssets; // 本地图片
  final String imageUrl;  // 网络图片链接
  final String name;  // 名称
  final String groupTitle;

  FriendCell({this.imageAssets, this.imageUrl, @required this.name, this.groupTitle}); // 首字母

  @override
  Widget build(BuildContext context) {
    // 字母段写在cell上,根据内容动态展示
    return Container(
      child: Column(
        children: [
          // 字母头部
          groupTitle != null ? Container(
            height: 30,
            padding: EdgeInsets.only(left: 10),
            alignment: Alignment.centerLeft,
            child: Text(groupTitle, style: TextStyle(color: Colors.grey)),
          ) : Container(),
          // 图片和名称
          Container(
            color: Colors.white,
            height: 54,
            child: Row(
              children: [
                // 头像
                Container(
                    width: 34,height: 34,
                    margin: EdgeInsets.all(10),
                    decoration: BoxDecoration(borderRadius: BorderRadius.circular(6.0),
                        image: DecorationImage(image: imageAssets != null ? AssetImage(imageAssets) : NetworkImage(imageUrl))
                    )),
                //昵称+分割线
                Container(
                  width: ScreenWidth(context) - 54,
                  child: Column(
                    children: [
                      Container(
                          height: 53.5,
                          alignment: Alignment.centerLeft,
                          child: Text(name, style: TextStyle(fontSize: 18),)
                      ), // 昵称
                      Container(height: 0.5, color: Wechat_themeColor), // 分割线
                    ],
                  ),
                )
              ],
            ),
          )
        ],
      ),
    );
  }
}
  • data数据代码(friends_data.dart):
class Friends {
  final String imageUrl;
  final String name;
  final String indexLetter;
  final String message;
  final String time;

  Friends({this.imageUrl, this.name, this.indexLetter, this.message, this.time});
}

List <Friends>datas = [
  Friends(
    imageUrl: 'https://randomuser.me/api/portraits/women/57.jpg',
    name: 'Lina',
    indexLetter: 'L',
    message: 'hello hank !😁',
    time: '下午 3:45',
  ),
  Friends(
    imageUrl: 'https://randomuser.me/api/portraits/women/70.jpg',
    name: '菲儿',
    indexLetter: 'F',
    message: '忙完了吗?',
    time: '下午 3:25',
  ),
  Friends(
    imageUrl: 'https://randomuser.me/api/portraits/women/60.jpg',
    name: '安莉',
    indexLetter: 'A',
    message: '我在看看,稍等。',
    time: '下午 2:45',
  ),
  Friends(
    imageUrl: 'https://randomuser.me/api/portraits/men/91.jpg',
    name: '阿贵',
    indexLetter: 'A',
    message: '我没弄明白...',
    time: '昨天',
  ),
  Friends(
    imageUrl: 'https://randomuser.me/api/portraits/women/22.jpg',
    name: '贝拉',
    indexLetter: 'B',
    message: '这个时候刷圈?',
    time: '下午 3:45',
  ),
  Friends(
    imageUrl: 'https://randomuser.me/api/portraits/women/57.jpg',
    name: 'Lina',
    indexLetter: 'L',
    message: 'hello hank !😁',
    time: '下午 3:45',
  ),
  Friends(
    imageUrl: 'https://randomuser.me/api/portraits/women/18.jpg',
    name: 'Nancy',
    indexLetter: 'N',
    message: '麻烦通过一下😁',
    time: '下午 4:05',
  ),
  Friends(
    imageUrl: 'https://randomuser.me/api/portraits/men/47.jpg',
    name: '扣扣',
    indexLetter: 'K',
    message: '你好啊😁',
    time: '下午 2:45',
  ),
  Friends(
    imageUrl: 'https://randomuser.me/api/portraits/men/3.jpg',
    name: 'Jack',
    indexLetter: 'J',
    message: '好久不见 ',
    time: '下午 4:15',
  ),
  Friends(
    imageUrl: 'https://randomuser.me/api/portraits/women/5.jpg',
    name: 'Emma',
    indexLetter: 'E',
    message: '在忙什么呢 ',
    time: '下午 3:55',
  ),
  Friends(
    imageUrl: 'https://randomuser.me/api/portraits/women/44.jpg',
    name: 'Abby',
    indexLetter: 'A',
    message: ' 最近还好吗😁',
    time: '下午 1:45',
  ),
  Friends(
    imageUrl: 'https://randomuser.me/api/portraits/men/65.jpg',
    name: 'Betty',
    indexLetter: 'B',
    message: '什么时候有空呢😁',
    time: '上午 8:45',
  ),
  Friends(
    imageUrl: 'https://randomuser.me/api/portraits/men/83.jpg',
    name: 'Tony',
    indexLetter: 'T',
    message: '一起出去玩吧😁',
    time: '上午 7:15',
  ),
  Friends(
    imageUrl: 'https://randomuser.me/api/portraits/men/36.jpg',
    name: 'Jerry',
    indexLetter: 'J',
    message: 'How are you?😁',
    time: '上午 9:10',
  ),
  Friends(
    imageUrl: 'https://randomuser.me/api/portraits/men/66.jpg',
    name: 'Colin',
    indexLetter: 'C',
    message: '谢谢你',
    time: '下午 3:40',
  ),
  Friends(
    imageUrl: 'https://randomuser.me/api/portraits/women/58.jpg',
    name: 'Haha',
    indexLetter: 'H',
    message: '最近去健身了么😁',
    time: '下午 5:40',
  ),
  Friends(
    imageUrl: 'https://randomuser.me/api/portraits/women/60.jpg',
    name: 'Ketty',
    indexLetter: 'K',
    message: '你喜欢哪个明星呀😁',
    time: '下午 3:45',
  ),
  Friends(
    imageUrl: 'https://randomuser.me/api/portraits/women/57.jpg',
    name: 'Lina',
    indexLetter: 'L',
    message: 'hello hank !😁',
    time: '下午 3:45',
  ),
  Friends(
    imageUrl: 'https://randomuser.me/api/portraits/women/57.jpg',
    name: 'Lina',
    indexLetter: 'L',
    message: 'hello hank !😁',
    time: '下午 3:45',
  )
];
  • 索引栏文件代码(index_bar.dart):
import 'package:flutter/material.dart';

import '../../const.dart';

class IndexBar extends StatefulWidget {

  // indexBar高度
  final double indexBarHeight;

  // 函数传递给外界(回调)
  final void Function(int index) indexBarCallBack;

  const IndexBar({Key key, this.indexBarHeight = 480, this.indexBarCallBack}) : super(key: key);

  @override
  _IndexBarState createState() => _IndexBarState();
}

class _IndexBarState extends State<IndexBar> {

  // 总高度
  final double indexBarHeight = 400;
  // 当前选中的Index索引
  int _currentIndex = -1;
  // 背景颜色
  Color _bgColor = Color.fromRGBO(1, 1, 1, 0);
  // 文字颜色
  Color _indexColor = Colors.black;

  // 垂直拖拽(按下)
  void onVerticalDragDown(DragDownDetails details) {
    if (getCurrentIndex(context, details.globalPosition) != _currentIndex) {
      _currentIndex = getCurrentIndex(context, details.globalPosition);
      widget.indexBarCallBack(_currentIndex);
    }
    setIndexBarColor(true);
    setState(() {});
  }
  // 垂直拖拽(拖拽中)
  void onVerticalDragUpdate(DragUpdateDetails details) {
    // 传递参数(delegate)
    if (getCurrentIndex(context, details.globalPosition) != _currentIndex) {
      _currentIndex = getCurrentIndex(context, details.globalPosition);
      widget.indexBarCallBack(_currentIndex);
      setState(() {});
    }
  }
  // 垂直拖拽(拖拽结束)
  void onVerticalDragEnd(DragEndDetails details) {
    _currentIndex = -1; // 每次回归-1
    setIndexBarColor(false);
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      height: widget.indexBarHeight,
      child: Row(
        // mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          _currentIndex != -1 ? Container(
            // 控制气泡位置
            alignment: Alignment(0, getBubble()),
            height: widget.indexBarHeight,
            width: 100,
            child: Stack(
              // 对齐(x: 中心左移20%, y: 居中)
                alignment: Alignment(-0.2,0),
                children: [
                  Image(image: AssetImage("images/气泡.png"), width: 60),
                  Text(INDEX_WORDS[_currentIndex] , style: TextStyle(color: Colors.white,fontSize: 35))
                ]
            ),
          ) : Container(),
          Container(
            width: 30,
            color: _bgColor,
            child: GestureDetector(
              child: Column(children: getIndexBarItems()),
              onVerticalDragDown: onVerticalDragDown,
              onVerticalDragUpdate: onVerticalDragUpdate,
              onVerticalDragEnd: onVerticalDragEnd,
            ),
          )
        ],
      ),
    );
  }

  // 索引元素
  List<Widget> getIndexBarItems() {
    List<Widget> list = [];
    for (int i = 0; i < INDEX_WORDS.length; i++) {
      list.add(Expanded(
          child: Text(INDEX_WORDS[i], style: TextStyle(color: _indexColor))));
    }
    return list;
  }

  // 设置IndexBar颜色
  void setIndexBarColor(bool isSelected) {
    _bgColor =
        isSelected ? Color.fromRGBO(1, 1, 1, 0.5) : Color.fromRGBO(0, 0, 0, 0);
    _indexColor = isSelected ? Colors.white : Colors.black;
  }

  // 获取当前选中的Index
  int getCurrentIndex(BuildContext context, Offset offset) {
    // 相对坐标
    // print(offset.dy);

    // 绝对坐标
    RenderBox box = context.findRenderObject();
    final moveY = box.globalToLocal(offset).dy;
    // ~/ 整除
    final index = moveY ~/ (widget.indexBarHeight / INDEX_WORDS.length);
    return index.clamp(0, INDEX_WORDS.length - 1); // 设置区间边界
  }

  // 获取气泡的垂直位置
  double getBubble() {
    if (_currentIndex < 1 ) { return -1.1; }
    return 2.2 / (INDEX_WORDS.length - 1) * _currentIndex - 1.1;
  }
}

const INDEX_WORDS = [
  '🔍',
  '☆',
  'A',
  'B',
  'C',
  'D',
  'E',
  'F',
  'G',
  'H',
  'I',
  'J',
  'K',
  'L',
  'M',
  'N',
  'O',
  'P',
  'Q',
  'R',
  'S',
  'T',
  'U',
  'V',
  'W',
  'X',
  'Y',
  'Z'
];
  • 好友主页面代码friends_page.dart:
import 'dart:async';
import 'dart:ffi';

import 'package:flutter/material.dart';
import 'package:wechat_demo/const.dart';
import 'package:wechat_demo/pages/discover/discover_cell.dart';
import 'package:wechat_demo/pages/discover/discover_child_page.dart';
import 'package:wechat_demo/pages/friends/index_bar.dart';
import 'friends_cell.dart';
import 'friends_data.dart';

class FriendsPage extends StatefulWidget {
  @override
  _FriendsPageState createState() => _FriendsPageState();
}

class _FriendsPageState extends State<FriendsPage> {
  // 滚动控制器对象(初始化后,ListView使用,其他地方通过对象调用方法)
  ScrollController _scrollController = ScrollController();

  // 数据
  final List<Friends> _listDatas = [];

  // 索引对应偏移值
  final Map _groupOffsets = {
    INDEX_WORDS[0]: 0.0,
    INDEX_WORDS[1]: 0.0,
  };

  @override
  void initState() {
    super.initState();

    // 多创建一倍数据(使用..是强制返回自身,可链式操作)
    _listDatas..addAll(datas)..addAll(datas);
    // 排序
    _listDatas.sort((Friends a, Friends b) {
      return a.indexLetter.compareTo(b.indexLetter);
    });

    // 索引对应偏移值
    var offset = _headDatas.length * 54.0;
    for (int i = 0; i < _listDatas.length; i++) {
      // 首位
      if (i == 0) {
        _groupOffsets.addAll({_listDatas[i].indexLetter: offset});
        offset += 84;
      }
      // 字母相同
      else if (_listDatas[i].indexLetter == _listDatas[i - 1].indexLetter) {
        offset += 54;
      }
      // 字母不同
      else {
        _groupOffsets.addAll({_listDatas[i].indexLetter: offset});
        offset += 84;
      }
    }
  }

  final List<Friends> _headDatas = [
    Friends(imageUrl: "images/新的朋友.png", name: "新的朋友"),
    Friends(imageUrl: "images/群聊.png", name: "群聊"),
    Friends(imageUrl: "images/标签.png", name: "标签"),
    Friends(imageUrl: "images/公众号.png", name: "公众号"),
  ];

  // 点击新增朋友
  void tapAddFriends() {
    // 跳转新页面
    Navigator.of(context).push(MaterialPageRoute(
        builder: (BuildContext context) => DiscoverChildPage(title: "新增朋友")));
  }

  // 滚动到GroupOffset位置
  void moveToGrounpOffset(int index) {
    if (_groupOffsets[INDEX_WORDS[index]] != null) {
      _scrollController.animateTo(_groupOffsets[INDEX_WORDS[index]],
          duration: Duration(milliseconds: 300), curve: Curves.easeIn);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Wechat_themeColor,
        centerTitle: true,
        // 安卓的导航栏标题未居中,可以设置居中
        title: Text("通讯录"),
        elevation: 0.0,
        // 去除分割线
        // 导航栏按钮
        actions: <Widget>[
          GestureDetector(
            child: Container(
              margin: EdgeInsets.only(right: 10),
              width: 20,
              height: 20,
              child: Image(image: AssetImage("images/icon_friends_add.png")),
            ),
            onTap: tapAddFriends,
          )
        ],
      ),
      body: Container(
        color: Wechat_themeColor,
        child: Stack(
          children: [
            ListView.builder(
                controller: _scrollController,
                itemCount: _headDatas.length + _listDatas.length,
                itemBuilder: cellForRow),
            Positioned(
                right: 0,
                // 正确top应该 (屏幕高度 - 导航栏高度 - 底部Bar高度 - 480) / 2
                top: (ScreenHeight(context) - 480) / 4 ,
                child: IndexBar(
                  indexBarHeight: 480, // 外部可指定indexBar高度
                  indexBarCallBack: moveToGrounpOffset,
                )),
          ],
        ),
      ),
    );
  }

  Widget cellForRow(BuildContext context, int index) {
    if (index < _headDatas.length) {
      return FriendCell(
          imageAssets: _headDatas[index].imageUrl,
          name: _headDatas[index].name);
    }
    // 记录是否展示字母头部(当前首字母与上一个不同,就展示)
    final bool _haveGroup = index > _headDatas.length
        ? _listDatas[index - _headDatas.length].indexLetter !=
            _listDatas[index - _headDatas.length - 1].indexLetter
        : true;
    return FriendCell(
        imageUrl: _listDatas[index - _headDatas.length].imageUrl,
        name: _listDatas[index - _headDatas.length].name,
        groupTitle: _haveGroup
            ? _listDatas[index - _headDatas.length].indexLetter
            : null);
  }
}
friends.gif
  • 建议阅读时,代码粘贴到Andriod Studio应用中,[ command + option + -] 折叠所有代码观看

本系列为基础入门篇一步步入门,适合初学者练手。主要是UI布局基础思想的熟悉。一次性优化点处理完,对初学者不太友好

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

推荐阅读更多精彩内容