Flutter 可滾動(dòng)組件 之 ListView (十六)

約定:后面如果我們說(shuō)一個(gè)組件是Sliver 則表示它是基于Sliver布局的組件剥哑,同理上炎,說(shuō)一個(gè)組件是 RenderBox,則代表它是基于盒模型布局的組件均践,并不是說(shuō)它就是 RenderBox 類的實(shí)例。

ListView是最常用的可滾動(dòng)組件之一摩幔,它可以沿一個(gè)方向線性排布所有子組件彤委,并且它也支持列表項(xiàng)懶加載(在需要時(shí)才會(huì)創(chuàng)建)。我們看看ListView的默認(rèn)構(gòu)造函數(shù)定義:

ListView({
  ...  
  //可滾動(dòng)widget公共參數(shù)
  Axis scrollDirection = Axis.vertical,
  bool reverse = false,
  ScrollController? controller,
  bool? primary,
  ScrollPhysics? physics,
  EdgeInsetsGeometry? padding,
  
  //ListView各個(gè)構(gòu)造函數(shù)的共同參數(shù)  
  double? itemExtent,
  Widget? prototypeItem, //列表項(xiàng)原型或衡,后面解釋
  bool shrinkWrap = false,
  bool addAutomaticKeepAlives = true,
  bool addRepaintBoundaries = true,
  double? cacheExtent, // 預(yù)渲染區(qū)域長(zhǎng)度
    
  //子widget列表
  List<Widget> children = const <Widget>[],
})

上面參數(shù)分為兩組:第一組是可滾動(dòng)組件的公共參數(shù)焦影,本章第一節(jié)中已經(jīng)介紹過(guò),不再贅述封断;第二組是ListView各個(gè)構(gòu)造函數(shù)(ListView有多個(gè)構(gòu)造函數(shù))的共同參數(shù)斯辰,我們重點(diǎn)來(lái)看看這些參數(shù),:

  • itemExtent:該參數(shù)如果不為null坡疼,則會(huì)強(qiáng)制children的“長(zhǎng)度”為itemExtent的值彬呻;這里的“長(zhǎng)度”是指滾動(dòng)方向上子組件的長(zhǎng)度,也就是說(shuō)如果滾動(dòng)方向是垂直方向,則itemExtent代表子組件的高度闸氮;如果滾動(dòng)方向?yàn)樗椒较蚣艨觯瑒titemExtent就代表子組件的寬度。在ListView中蒲跨,指定itemExtent比讓子組件自己決定自身長(zhǎng)度會(huì)有更好的性能译断,這是因?yàn)橹付╥temExtent后,滾動(dòng)系統(tǒng)可以提前知道列表的長(zhǎng)度或悲,而無(wú)需每次構(gòu)建子組件時(shí)都去再計(jì)算一下孙咪,尤其是在滾動(dòng)位置頻繁變化時(shí)(滾動(dòng)系統(tǒng)需要頻繁去計(jì)算列表高度)。

  • prototypeItem:如果我們知道列表中的所有列表項(xiàng)長(zhǎng)度都相同但不知道具體是多少巡语,這時(shí)我們可以指定一個(gè)列表項(xiàng)翎蹈,該列表項(xiàng)被稱為 prototypeItem(列表項(xiàng)原型)。指定 prototypeItem 后捌臊,可滾動(dòng)組件會(huì)在 layout 時(shí)計(jì)算一次它延主軸方向的長(zhǎng)度杨蛋,這樣也就預(yù)先知道了所有列表項(xiàng)的延主軸方向的長(zhǎng)度,所以和指定 itemExtent 一樣理澎,指定 prototypeItem 會(huì)有更好的性能。注意曙寡,itemExtent 和prototypeItem 互斥糠爬,不能同時(shí)指定它們。

  • shrinkWrap:該屬性表示是否根據(jù)子組件的總長(zhǎng)度來(lái)設(shè)置ListView的長(zhǎng)度举庶,默認(rèn)值為false 执隧。默認(rèn)情況下,ListView會(huì)在滾動(dòng)方向盡可能多的占用空間户侥。當(dāng)ListView在一個(gè)無(wú)邊界(滾動(dòng)方向上)的容器中時(shí)镀琉,shrinkWrap必須為true。

  • addAutomaticKeepAlives:該屬性我們將在介紹 PageView 組件時(shí)詳細(xì)解釋蕊唐。

  • addRepaintBoundaries:該屬性表示是否將列表項(xiàng)(子組件)包裹在RepaintBoundary組件中屋摔。RepaintBoundary 讀者可以先簡(jiǎn)單理解為它是一個(gè)”繪制邊界“,將列表項(xiàng)包裹在RepaintBoundary中可以避免列表項(xiàng)不必要的重繪替梨,但是當(dāng)列表項(xiàng)重繪的開(kāi)銷非常械鍪浴(如一個(gè)顏色塊,或者一個(gè)較短的文本)時(shí)副瀑,不添加RepaintBoundary反而會(huì)更高效(具體原因會(huì)在本書后面 Flutter 繪制原理相關(guān)章節(jié)中介紹)弓熏。如果列表項(xiàng)自身來(lái)維護(hù)是否需要添加繪制邊界組件,則此參數(shù)應(yīng)該指定為 false糠睡。

注意:上面這些參數(shù)并非ListView特有挽鞠,在本章后面介紹的其它可滾動(dòng)組件也可能會(huì)擁有這些參數(shù),它們的含義是相同的。

1. 默認(rèn)構(gòu)造函數(shù)

默認(rèn)構(gòu)造函數(shù)有一個(gè)children參數(shù)信认,它接受一個(gè)Widget列表(List<Widget>)串稀。這種方式適合只有少量的子組件數(shù)量已知且比較少的情況,反之則應(yīng)該使用ListView.builder 按需動(dòng)態(tài)構(gòu)建列表項(xiàng)

注意狮杨,雖然這種方式將所有children一次性傳遞給 ListView母截,但子組件仍然是在需要時(shí)才會(huì)加載(build(如有)、布局橄教、繪制)清寇,也就是說(shuō)通過(guò)默認(rèn)構(gòu)造函數(shù)構(gòu)建的 ListView 也是基于 Sliver 的列表懶加載模型。

示例1

class ListViewDemo extends StatelessWidget {
  ListViewDemo({
    Key? key,
  }) : super(key: key);
  
  final TextStyle textStyle = TextStyle(fontSize: 20, color: Colors.redAccent);

  @override
  Widget build(BuildContext context) {
    return ListView(
      shrinkWrap: true,
      children: [
        Padding(
            padding: EdgeInsets.all(8),
            child: Text("人的一切痛苦护蝶,本質(zhì)上都是對(duì)自己無(wú)能的憤怒华烟。", style: textStyle)),
        Padding(
            padding: EdgeInsets.all(8),
            child: Text("人活在世界上,不可以有偏差持灰;而且多少要費(fèi)點(diǎn)勁兒盔夜,才能把自己保持到理性的軌道上。",
                style: textStyle)),
        Padding(
            padding: EdgeInsets.all(8),
            child: Text("我活在世上堤魁,無(wú)非想要明白些道理喂链,遇見(jiàn)些有趣的事。妥泉。", style: textStyle))
      ],
    );
  }
}
image.png

示例2

class ListViewDemo1 extends StatelessWidget {
  const ListViewDemo1({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ListView(
      children: List.generate(100, (index) {
        // ListTile 小分片
        return ListTile(
          leading: Icon(Icons.people),
          trailing: Icon(Icons.delete),
          title: Text(
            "聯(lián)系人 ${index + 1}",
            style: TextStyle(color: Colors.orange, fontSize: 20),
          ),
          subtitle: Text(
            "聯(lián)系方式: 18826625555",
            style: TextStyle(color: Colors.grey, fontSize: 16),
          ),
        );
      }),
    );
  }
}

image.png

2. ListView.builder

ListView.builder適合列表項(xiàng)比較多或者列表項(xiàng)不確定的情況椭微,下面看一下ListView.builder的核心參數(shù)列表

ListView.builder({
  // ListView公共參數(shù)已省略  
  ...
  required IndexedWidgetBuilder itemBuilder, 
  int itemCount, // item數(shù)量
  ...
})
  • itemBuilder:它是列表項(xiàng)的構(gòu)建器,類型為IndexedWidgetBuilder盲链,返回值為一個(gè)widget蝇率。當(dāng)列表滾動(dòng)到具體的index位置時(shí),會(huì)調(diào)用該構(gòu)建器構(gòu)建列表項(xiàng)刽沾。
    *itemCount:列表項(xiàng)的數(shù)量本慕,如果為null,則為無(wú)限列表侧漓。

示例1

class ListViewBuilderDemo extends StatelessWidget {
  const ListViewBuilderDemo({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: 100,
      itemExtent: 50, // 主軸方向高度
      itemBuilder: (BuildContext ctx, int index) {
        return Text("Item ${index + 1}");
      },
    );
  }
}
image.png

3. ListView.separated

ListView.separated可以在生成的列表項(xiàng)之間添加一個(gè)分割組件锅尘,它比ListView.builder多了一個(gè)separatorBuilder參數(shù),該參數(shù)是一個(gè)分割組件生成器

示例1

class ListViewSeparatedDemo extends StatelessWidget {
  const ListViewSeparatedDemo({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ListView.separated(
        itemBuilder: (BuildContext ctx, int index) {
          return ListTile(
            leading: Icon(Icons.people),
            trailing: Icon(Icons.delete),
            title: Text(
              "聯(lián)系人 ${index + 1}",
              style: TextStyle(fontSize: 20),
            ),
          );
        },
        separatorBuilder: (BuildContext ctx, int index) {
          return Divider(
            height: 20, // Divider 高度火架,不是線的高度
            thickness: 5, // 線的高度
            color: index % 2 == 0 ? Colors.orange : Colors.blue,
            indent: 16, // 左側(cè)間距
            endIndent: 16, // 右側(cè)間距
          );
        },
        itemCount: 100);
  }
}
image.png

4. ListView.custom

我們看下ListView.custom的定義

  const ListView.custom({
    ...
    required this.childrenDelegate,
    ...
  }) 

ListView.custom 主要是傳一個(gè)SliverChildDelegate代理, SliverChildDelegate是abstract(抽象類)鉴象,它有兩個(gè)子類SliverChildBuilderDelegateSliverChildListDelegate

** SliverChildListDelegate**
定義如下:

  SliverChildListDelegate(
    this.children, {
    this.addAutomaticKeepAlives = true,
    this.addRepaintBoundaries = true,
    this.addSemanticIndexes = true,
    this.semanticIndexCallback = _kDefaultSemanticIndexCallback,
    this.semanticIndexOffset = 0,
  })

children 是必傳的何鸡,是不是很眼熟纺弊,ListView默認(rèn)構(gòu)造函數(shù)里也是傳一個(gè)children,實(shí)際上ListView默認(rèn)構(gòu)造函數(shù)中是通過(guò)children創(chuàng)建一個(gè)SliverChildListDelegate的

ListView構(gòu)造函數(shù)處理children源碼如下:

       childrenDelegate = SliverChildListDelegate(
         children,
         addAutomaticKeepAlives: addAutomaticKeepAlives,
         addRepaintBoundaries: addRepaintBoundaries,
         addSemanticIndexes: addSemanticIndexes,
       ),

** SliverChildBuilderDelegate**
定義如下:

  const SliverChildBuilderDelegate(
    this.builder, {
    this.findChildIndexCallback,
    this.childCount,
    this.addAutomaticKeepAlives = true,
    this.addRepaintBoundaries = true,
    this.addSemanticIndexes = true,
    this.semanticIndexCallback = _kDefaultSemanticIndexCallback,
    this.semanticIndexOffset = 0,
  })

builder是必傳的骡男,是個(gè)NullableIndexedWidgetBuilder類型淆游,和IndexedWidgetBuilder類似,ListView.builder源碼中是通過(guò)builder創(chuàng)建個(gè)SliverChildBuilderDelegate的

ListView.builder 處理 itemBuilder 源碼如下

       childrenDelegate = SliverChildBuilderDelegate(
         itemBuilder,
         childCount: itemCount,
         addAutomaticKeepAlives: addAutomaticKeepAlives,
         addRepaintBoundaries: addRepaintBoundaries,
         addSemanticIndexes: addSemanticIndexes,
       ),

示例1 - SliverChildListDelegate

class ListViewCustomDemo1 extends StatelessWidget {
  const ListViewCustomDemo1({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ListView.custom(
      itemExtent: 50, // 高度
      childrenDelegate: SliverChildListDelegate(
        List.generate(100, (index) {
          return ListTile(
            title: Text("商品Item ${index + 1}",
                style: TextStyle(color: Colors.red, fontSize: 18)),
            trailing: Icon(
              Icons.favorite,
              color: Colors.white,
            ),
          );
        }),
      ),
    );
  }
}
image.png

示例2 - SliverChildBuilderDelegate

class ListViewCustomDemo2 extends StatelessWidget {
  const ListViewCustomDemo2({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ListView.custom(
      itemExtent: 100,
      childrenDelegate:
          SliverChildBuilderDelegate((BuildContext ctx, int index) {
        return Container(
          color: Color.fromARGB(Random().nextInt(256), Random().nextInt(256),
              Random().nextInt(256), Random().nextInt(256)),
        );
      }, childCount: 100),
    );
  }
}
image.png

5. 固定高度列表

默認(rèn)情況下,列表中的Item的高度是隨內(nèi)容自適應(yīng)的犹菱。
但給列表指定 itemExtent 或 prototypeItem 會(huì)有更高的性能拾稳,所以當(dāng)我們知道列表項(xiàng)的高度都相同時(shí),強(qiáng)烈建議指定 itemExtent 或 prototypeItem

示例1

class ListViewFixedExtentDemo1 extends StatelessWidget {
  const ListViewFixedExtentDemo1({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemExtent: 56,
      // prototypeItem: ListTile(title: Text("Item")),
      itemBuilder: (BuildContext ctx, int index) {
        return ListTile(
          title: Text("Item $index"),
        );
      },
    );
  }
}

自定義個(gè)LayoutLogPrint組件腊脱,在布局時(shí)可以打印當(dāng)前上下文中父組件給子組件的約束信息

完整代碼如下

class ListViewFixedExtentDemo2 extends StatelessWidget {
  const ListViewFixedExtentDemo2({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      prototypeItem: ListTile(title: Text("1")),
      // itemExtent: 56,
      itemBuilder: (context, index) {
        //LayoutLogPrint是一個(gè)自定義組件访得,在布局時(shí)可以打印當(dāng)前上下文中父組件給子組件的約束信息
        return LayoutLogPrint(
          tag: index,
          child: ListTile(title: Text("$index")),
        );
      },
    );
  }
}

class LayoutLogPrint<T> extends StatelessWidget {
  final Widget child;
  final T? tag;
  const LayoutLogPrint({Key? key, required this.child, this.tag})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(builder: (_, constraints) {
      // assert在編譯release版本時(shí)會(huì)被去除
      assert(() {
        print('${tag ?? key ?? child}: $constraints');
        return true;
      }());
      return child;
    });
  }
}

因?yàn)榱斜眄?xiàng)都是一個(gè) ListTile,高度相同陕凹,但是我們不知道 ListTile 的高度是多少悍抑,所以指定了prototypeItem ,運(yùn)行后杜耙,控制臺(tái)打铀崖狻:

flutter: 0: BoxConstraints(w=375.0, h=56.0)
flutter: 1: BoxConstraints(w=375.0, h=56.0)
flutter: 2: BoxConstraints(w=375.0, h=56.0)
flutter: 3: BoxConstraints(w=375.0, h=56.0)
...

可見(jiàn) ListTile 的高度是 56 ,指定itemExtent為56也是可以的,建議優(yōu)先指定原型佑女,這樣的話在列表項(xiàng)布局修改后记靡,仍然可以正常工作(前提是每個(gè)列表項(xiàng)的高度相同)

如果本例中不指定 itemExtent 或 prototypeItem ,我們看看控制臺(tái)日志信息

flutter: 0: BoxConstraints(w=375.0, 0.0<=h<=Infinity)
flutter: 1: BoxConstraints(w=375.0, 0.0<=h<=Infinity)
flutter: 2: BoxConstraints(w=375.0, 0.0<=h<=Infinity)
flutter: 3: BoxConstraints(w=375.0, 0.0<=h<=Infinity)
...

可以發(fā)現(xiàn)团驱,列表不知道列表項(xiàng)的具體高度摸吠,高度約束變?yōu)?0.0 到 Infinity。

6.列表的原理

ListView 內(nèi)部組合了 Scrollable店茶、Viewport 和 Sliver蜕便,需要注意:

    1. ListView 中的列表項(xiàng)組件都是 RenderBox,并不是 Sliver贩幻, 這個(gè)一定要注意。
    1. 一個(gè) ListView 中只有一個(gè)Sliver两嘴,對(duì)列表項(xiàng)進(jìn)行按需加載的邏輯是 Sliver 中實(shí)現(xiàn)的丛楚。
    1. ListView 的 Sliver 默認(rèn)是 SliverList,如果指定了 itemExtent 憔辫,則會(huì)使用 SliverFixedExtentList趣些;如果 prototypeItem 屬性不為空,則會(huì)使用 SliverPrototypeExtentList贰您,無(wú)論是是哪個(gè)坏平,都實(shí)現(xiàn)了子組件的按需加載模型。

我們解釋下ListView的Sliver
ListView 是繼承于BoxScrollView锦亦,BoxScrollView繼承于ScrollView舶替,ScrollView繼承于StatelessWidget,因而ScrollView是我們需要讀的最深層級(jí)杠园,在ScrollView的方法中顾瞪,是通過(guò)buildSlivers來(lái)獲取slivers的,而buildSlivers方法在ScrollView中是抽象方法,因而它的子類需要實(shí)現(xiàn)〕滦眩現(xiàn)在我們需要看下BoxScrollView中關(guān)于buildSlivers的實(shí)現(xiàn)惕橙,在BoxScrollView的 buildSlivers方法中是通過(guò)buildChildLayout來(lái)獲取Sliver,而buildChildLayout在BoxScrollView中也是抽象方法钉跷,因而我們?nèi)タ碆oxScrollView子類ListView中buildChildLayout的實(shí)現(xiàn)弥鹦,ListView中buildChildLayout源碼如下

  Widget buildChildLayout(BuildContext context) {
    if (itemExtent != null) {
      return SliverFixedExtentList(
        delegate: childrenDelegate,
        itemExtent: itemExtent!,
      );
    } else if (prototypeItem != null) {
      return SliverPrototypeExtentList(
        delegate: childrenDelegate,
        prototypeItem: prototypeItem!,
      );
    }
    return SliverList(delegate: childrenDelegate);
  }

默認(rèn)情況下 ListView的Sliver是SliverList,在itemExtent不為空時(shí)爷辙,是SliverFixedExtentList彬坏,在prototypeItem不為空時(shí)是SliverPrototypeExtentList

7 實(shí)例:無(wú)限加載列表

class _MSHomePageContentState extends State<MSHomePageContent> {
  static const loadingTag = "##loading##";
  var _words = <String>[loadingTag];

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

  @override
  Widget build(BuildContext context) {
    return ListView.separated(
        itemBuilder: (BuildContext ctx, int index) {
          if (_words[index] == loadingTag) {
            if (_words.length <= 100) {
              _retrieveData();
              // 加載時(shí)顯示loading
              return Container(
                padding: EdgeInsets.all(16),
                alignment: Alignment.center,
                child: SizedBox(
                  width: 24,
                  height: 24,
                  child: CircularProgressIndicator(strokeWidth: 2.0),
                ),
              );
            } else {
              // 已經(jīng)加載了100條數(shù)據(jù),不再獲取數(shù)據(jù)犬钢。
              return Container(
                alignment: Alignment.center,
                padding: EdgeInsets.all(8),
                child: Text("沒(méi)有更多", style: TextStyle(color: Colors.grey)),
              );
            }
          }
          // 顯示單詞列表
          return ListTile(title: Text(_words[index]));
        },
        separatorBuilder: (BuildContext ctx, int index) {
          return Divider(
              color: Colors.amber, thickness: 3, indent: 16, endIndent: 16);
        },
        itemCount: _words.length);
  }

  _retrieveData() {
    Future.delayed(Duration(seconds: 3)).then((value) {
      // 每次生成20對(duì)單詞
      List<String> newData =
          generateWordPairs().take(20).map((e) => e.asSnakeCase).toList();
      _words.insertAll(_words.length - 1, newData);

      setState(() {});

      // List<WordPair> newData = generateWordPairs().take(10).toList();
      // List<String> data = newData.map((e) => e.asPascalCase).toList();
      // _words.addAll(data);
    });
  }
}


image.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末苍鲜,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子玷犹,更是在濱河造成了極大的恐慌混滔,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,723評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件歹颓,死亡現(xiàn)場(chǎng)離奇詭異坯屿,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)巍扛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門领跛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人撤奸,你說(shuō)我怎么就攤上這事吠昭。” “怎么了胧瓜?”我有些...
    開(kāi)封第一講書人閱讀 152,998評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵矢棚,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我府喳,道長(zhǎng)蒲肋,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 55,323評(píng)論 1 279
  • 正文 為了忘掉前任钝满,我火速辦了婚禮兜粘,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘弯蚜。我一直安慰自己孔轴,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布熟吏。 她就那樣靜靜地躺著距糖,像睡著了一般玄窝。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上悍引,一...
    開(kāi)封第一講書人閱讀 49,079評(píng)論 1 285
  • 那天恩脂,我揣著相機(jī)與錄音,去河邊找鬼趣斤。 笑死俩块,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的浓领。 我是一名探鬼主播玉凯,決...
    沈念sama閱讀 38,389評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼联贩!你這毒婦竟也來(lái)了漫仆?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 37,019評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤泪幌,失蹤者是張志新(化名)和其女友劉穎盲厌,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體祸泪,經(jīng)...
    沈念sama閱讀 43,519評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡吗浩,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了没隘。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片懂扼。...
    茶點(diǎn)故事閱讀 38,100評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖右蒲,靈堂內(nèi)的尸體忽然破棺而出阀湿,到底是詐尸還是另有隱情,我是刑警寧澤瑰妄,帶...
    沈念sama閱讀 33,738評(píng)論 4 324
  • 正文 年R本政府宣布炕倘,位于F島的核電站,受9級(jí)特大地震影響翰撑,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜啊央,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評(píng)論 3 307
  • 文/蒙蒙 一眶诈、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧瓜饥,春花似錦逝撬、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,289評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)溯警。三九已至,卻和暖如春狡相,著一層夾襖步出監(jiān)牢的瞬間梯轻,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,517評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工尽棕, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留喳挑,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,547評(píng)論 2 354
  • 正文 我出身青樓滔悉,卻偏偏與公主長(zhǎng)得像伊诵,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子回官,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評(píng)論 2 345

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