Flutter小試牛刀-ListView

從今天開始入坑Flutter,先從一個(gè)小小的ListView開始吧!

官方Codelabs:https://codelabs.flutter-io.cn/#codelabs

此處省略環(huán)境配置...

首先打開我們熟悉的Android Studio,創(chuàng)建Flutter工程

沒錯(cuò)就是他

成功創(chuàng)建后,找到 lib/main.dart這個(gè)文件,把里邊的內(nèi)容刪除掉,替換成一下內(nèi)容:

import 'package:flutter/material.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Welcome to Flutter',
      home: new Scaffold(
        appBar: new AppBar(
          title: const Text('Welcome to Flutter'),
        ),
        body: const Center(
          child: const Text('Hello World'),
        ),
      ),
    );
  }
}

在pubspec.yaml 中,將 english_words(3.1.0或更高版本)添加到依賴項(xiàng)列表

dependencies:
  flutter:
    sdk: flutter

  cupertino_icons: ^0.1.0
  english_words: ^3.1.0   # 新增了這一行

在Android Studio 的編輯器視圖中查看 pubspec 時(shí),單擊右上角的 Packages get,這會(huì)將依賴包安裝到您的項(xiàng)目
在 lib/main.dart 中引入

import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';  // 新增了這一行

接下來,我們使用 English words 包生成文本來替換字符串"Hello World":
我們需要進(jìn)行如下更改:

import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final wordPair = new WordPair.random(); // 新增了這一行
    return new MaterialApp(
      title: 'Welcome to Flutter',
      home: new Scaffold(
        appBar: new AppBar(
          title: new Text('Welcome to Flutter'),
        ),
        body: new Center(    // 這里把之前的 "const" 換成了 "new".
          //child: const Text('Hello World'),   // 我們不用這樣的方式生成文字了
          child: new Text(wordPair.asPascalCase),  // 這是新的文字生成方式
        ),
      ),
    );
  }
}

如果應(yīng)用程序正在運(yùn)行,請(qǐng)使用熱重載按鈕 (

) 更新正在運(yùn)行的應(yīng)用程序。每次單擊熱重載或保存項(xiàng)目時(shí),都會(huì)在正在運(yùn)行的應(yīng)用程序中隨機(jī)選擇不同的單詞對(duì)。 這是因?yàn)閱卧~對(duì)是在 build 方法內(nèi)部生成的。每次 MaterialApp 需要渲染時(shí)或者在 Flutter Inspector 中切換平臺(tái)時(shí) build 都會(huì)運(yùn)行.

接下來添加一個(gè) Stateful widget
Statelesswidgets 是不可變的,這意味著它們的屬性不能改變——所有的值都是 final。
Statefulwidgets 持有的狀態(tài)可能在 widget 生命周期中發(fā)生變化,實(shí)現(xiàn)一個(gè) stateful widget 至少需要兩個(gè)類:
1)一個(gè) StatefulWidget 類;
2)一個(gè) State 類,
StatefulWidget 類本身是不變的,但是 State 類在 widget 生命周期中始終存在。在這一步,你將添加一個(gè) stateful widget(有狀態(tài)的控件)—— RandomWords,它會(huì)創(chuàng)建自己的狀態(tài)類 —— RandomWordsState,然后你需要將 RandomWords 內(nèi)嵌到已有的無狀態(tài)的 MyApp widget。

創(chuàng)建一個(gè)最簡(jiǎn)的 state 類,這個(gè)類可以在任意地方創(chuàng)建而不一定非要在 MyApp 里,我們的示例代碼是放在 MyApp 類的最下面了:

class RandomWordsState extends State<RandomWords> {
  // TODO Add build method
}

注意一下 State<RandomWords> 的聲明。這表明我們?cè)谑褂脤iT用于 RandomWords 的 State 泛型類。應(yīng)用的大部分邏輯和狀態(tài)都在這里 —— 它會(huì)維護(hù) RandomWords 控件的狀態(tài)。這個(gè)類會(huì)保存代碼生成的單詞對(duì),這個(gè)單詞對(duì)列表會(huì)隨著用戶滑動(dòng)而無限增長(zhǎng),另外還會(huì)保存用戶喜愛的單詞對(duì)(第二部分),也即當(dāng)用戶點(diǎn)擊愛心圖標(biāo)的時(shí)候會(huì)從喜愛的列表中添加或者移除當(dāng)前單詞對(duì)。

RandomWordsState 依賴 RandomWords,我們接下來會(huì)創(chuàng)建這個(gè)類。

添加有狀態(tài)的 RandomWords widget 到 main.dart,RandomWords widget 除了創(chuàng)建 State 類之外幾乎沒有其他任何東西:

class RandomWords extends StatefulWidget {
  @override
  RandomWordsState createState() => new RandomWordsState();
}

在添加狀態(tài)類后,IDE 會(huì)提示該類缺少 build 方法。接下來,您將添加一個(gè)基本的 build 方法,該方法通過將生成單詞對(duì)的代碼從 MyApp 移動(dòng)到 RandomWordsState 來生成單詞對(duì)。
將 build 方法添加到 RandomWordState 中,如下所示:


class RandomWordsState extends State<RandomWords> {
  @override                                  // 新增代碼片段 - 開始 ... 
  Widget build(BuildContext context) {
    final WordPair wordPair = new WordPair.random();
    return new Text(wordPair.asPascalCase);
  }                                          // ... 新增的代碼片段 - 結(jié)束
}

如下所示,刪除 MyApp 里生成文字的代碼:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final WordPair wordPair = new WordPair.random();  // 刪掉本行
    return new MaterialApp(
      title: 'Welcome to Flutter',
      home: new Scaffold(
        appBar: new AppBar(
          title: new Text('Welcome to Flutter'),
        ),
        body: new Center(
          //child: new Text(wordPair.asPascalCase), // 修改本行內(nèi)容 
          child: new RandomWords(),                 // 修改成本行代碼
        ),
      ),
    );
  }
}

熱重載(Hot reload)當(dāng)前的工程,應(yīng)用應(yīng)該像之前一樣運(yùn)行,每次熱重載或保存應(yīng)用程序時(shí)都會(huì)顯示一個(gè)單詞對(duì)。

接下來我們來創(chuàng)建一個(gè)無限滾動(dòng)的 ListView
向 RandomWordsState 類中添加一個(gè) _suggestions 列表以保存建議的單詞對(duì),同時(shí),添加一個(gè) biggerFont 變量來增大字體大小

提示:在 Dart 語言中使用下劃線前綴標(biāo)識(shí)符,會(huì)強(qiáng)制其變成私有。

class RandomWordsState extends State<RandomWords> {
  // 添加如下兩行
  final List<WordPair> _suggestions = <WordPair>[];
  final TextStyle _biggerFont = const TextStyle(fontSize: 18.0); 
  ...
}

接下來,我們將向 RandomWordsState 類添加一個(gè) _buildSuggestions() 函數(shù),此方法構(gòu)建顯示建議單詞對(duì)的 ListView。

ListView 類提供了一個(gè) builder 屬性,itemBuilder 值是一個(gè)匿名回調(diào)函數(shù), 接受兩個(gè)參數(shù)- BuildContext 和行迭代器 i。迭代器從 0 開始, 每調(diào)用一次該函數(shù),i 就會(huì)自增 1,對(duì)于每個(gè)建議的單詞對(duì)都會(huì)執(zhí)行一次。該模型允許建議的單詞對(duì)列表在用戶滾動(dòng)時(shí)無限增長(zhǎng)。

向 RandomWordsState 類添加 _buildSuggestions() 函數(shù),內(nèi)容如下:

Widget _buildSuggestions() {
    return new ListView.builder(
      padding: const EdgeInsets.all(16.0),

      // 對(duì)于每個(gè)建議的單詞對(duì)都會(huì)調(diào)用一次 itemBuilder,
      // 然后將單詞對(duì)添加到 ListTile 行中
      // 在偶數(shù)行,該函數(shù)會(huì)為單詞對(duì)添加一個(gè) ListTile row.
      // 在奇數(shù)行,該函數(shù)會(huì)添加一個(gè)分割線的 widget,來分隔相鄰的詞對(duì)。
      // 注意,在小屏幕上,分割線看起來可能比較吃力。

      itemBuilder: (BuildContext _context, int i) {
        // 在每一列之前,添加一個(gè)1像素高的分隔線widget
        if (i.isOdd) {
          return new Divider();
        }

        // 語法 "i ~/ 2" 表示i除以2,但返回值是整形(向下取整)
        // 比如 i 為:1, 2, 3, 4, 5 時(shí),結(jié)果為 0, 1, 1, 2, 2,
        // 這可以計(jì)算出 ListView 中減去分隔線后的實(shí)際單詞對(duì)數(shù)量
        final int index = i ~/ 2;
        // 如果是建議列表中最后一個(gè)單詞對(duì)
        if (index >= _suggestions.length) {
        // ...接著再生成10個(gè)單詞對(duì),然后添加到建議列表
          _suggestions.addAll(generateWordPairs().take(10));
        }
        return _buildRow(_suggestions[index]);
      }
    );
  }

對(duì)于每一個(gè)單詞對(duì),_buildSuggestions 函數(shù)都會(huì)調(diào)用一次 _buildRow。 這個(gè)函數(shù)在 ListTile 中顯示每個(gè)新詞對(duì),這使您在下一步中可以生成更漂亮的顯示行。

在 RandomWordsState 中添加 _buildRow 函數(shù) :

Widget _buildRow(WordPair pair) {
    return new ListTile(
      title: new Text(
        pair.asPascalCase,
        style: _biggerFont,
      ),
    );
  }

更新 RandomWordsStatebuild 方法以使用 _buildSuggestions(),而不是直接調(diào)用單詞生成庫,代碼更改后如下:(使用 Scaffold 類實(shí)現(xiàn)基礎(chǔ)的 Material Design 布局)

@override
  Widget build(BuildContext context) {
    //final wordPair = new WordPair.random(); // 刪掉 ... 
    //return new Text(wordPair.asPascalCase); // ... 這兩行

    return new Scaffold (                   // 代碼從這里... 
      appBar: new AppBar(
        title: new Text('Startup Name Generator'),
      ),
      body: _buildSuggestions(),
    );                                      // ... 添加到這里
  }

將 build() 方法添加到 MyApp 類中,如下所示:

 @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Startup Name Generator',
      home: new RandomWords(),
    );
  }

重新啟動(dòng)你的項(xiàng)目工程應(yīng)用,你應(yīng)該看到一個(gè)單詞對(duì)列表。盡可能地向下滾動(dòng),你將繼續(xù)看到新的單詞對(duì)。


向列表里添加圖標(biāo)
添加一個(gè) _saved Set(集合)到 RandomWordsState,這個(gè)集合存儲(chǔ)用戶喜歡(收藏)的單詞對(duì)。 在這里,Set 比 List 更合適,因?yàn)?Set 中不允許重復(fù)的值。

class RandomWordsState extends State<RandomWords> {
  final List<WordPair> _suggestions = <WordPair>[];
  final Set<WordPair> _saved = new Set<WordPair>();   // 新增本行
  final TextStyle _biggerFont = const TextStyle(fontSize: 18.0);
  ...
}

在 _buildRow 方法中添加 alreadySaved 來檢查確保單詞對(duì)還沒有添加到收藏夾中。

Widget _buildRow(WordPair pair) {
  final bool alreadySaved = _saved.contains(pair);  // 新增本行
  ...
}

同時(shí)在 _buildRow() 中, 添加一個(gè)心形 ??圖標(biāo)到 ListTiles以啟用收藏功能。接下來,你就可以給心形 ??圖標(biāo)添加交互能力了。

向列表添加圖標(biāo),如下所示:

Widget _buildRow(WordPair pair) {
  final bool alreadySaved = _saved.contains(pair);
  return new ListTile(
    title: new Text(
      pair.asPascalCase,
      style: _biggerFont,
    ),
    trailing: new Icon(   // 新增代碼開始 ...
      alreadySaved ? Icons.favorite : Icons.favorite_border,
      color: alreadySaved ? Colors.red : null,
    ),                    // ... 新增代碼結(jié)束
  );
}

熱重載應(yīng)用,你現(xiàn)在可以在每一行看到心形 ??圖標(biāo)?,但它們還沒有交互。

在這部分,我們將為剛剛的心形 ??圖標(biāo)增加交互,當(dāng)用戶點(diǎn)擊列表中的條目,切換其"收藏"狀態(tài),并將該詞對(duì)添加到或移除出"收藏夾"。

為了做到這個(gè),我們?cè)?_buildRow 中讓心形 ??圖標(biāo)變得可以點(diǎn)擊。如果單詞條目已經(jīng)添加到收藏夾中, 再次點(diǎn)擊它將其從收藏夾中刪除。當(dāng)心形 ??圖標(biāo)被點(diǎn)擊時(shí),函數(shù)調(diào)用 setState() 通知框架狀態(tài)已經(jīng)改變。

增加 onTap 方法,如下所示:

Widget _buildRow(WordPair pair) {
  final alreadySaved = _saved.contains(pair);
  return new ListTile(
    title: new Text(
      pair.asPascalCase,
      style: _biggerFont,
    ),
    trailing: new Icon(
      alreadySaved ? Icons.favorite : Icons.favorite_border,
      color: alreadySaved ? Colors.red : null,
    ),
    onTap: () {      // 增加如下 9 行代碼...
      setState(() {
        if (alreadySaved) {
          _saved.remove(pair);
        } else { 
          _saved.add(pair); 
        } 
      });
    },               // ... 一直到這里
  );
}

提示: 在 Flutter 的響應(yīng)式風(fēng)格的框架中,調(diào)用 setState() 會(huì)為 State 對(duì)象觸發(fā) build() 方法,從而導(dǎo)致對(duì) UI 的更新
熱重載應(yīng)用,你就可以點(diǎn)擊任何一行測(cè)試收藏或取消收藏功能,你的點(diǎn)擊同時(shí)自帶 Material Design 里的水波動(dòng)畫特效。

導(dǎo)航到新頁面

在這一步中,您將添加一個(gè)顯示收藏夾內(nèi)容的新頁面(在 Flutter 中稱為路由[route])。您將學(xué)習(xí)如何在主路由和新路由之間導(dǎo)航(切換頁面)。

在 Flutter 中,導(dǎo)航器管理應(yīng)用程序的路由棧。將路由推入(push)到導(dǎo)航器的棧中,將會(huì)顯示更新為該路由頁面。 從導(dǎo)航器的棧中彈出(pop)路由,將顯示返回到前一個(gè)路由。

接下來,我們?cè)?RandomWordsState 的 build 方法中為 AppBar 添加一個(gè)列表圖標(biāo)。當(dāng)用戶點(diǎn)擊列表圖標(biāo)時(shí),包含收藏夾的新路由頁面入棧顯示。

將該圖標(biāo)及其相應(yīng)的操作添加到 build 方法中:

class RandomWordsState extends State<RandomWords> {
  ...
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Startup Name Generator'),
        actions: <Widget>[      // 新增代碼開始 ...
          new IconButton(icon: const Icon(Icons.list), onPressed: _pushSaved),
        ],                      // ... 代碼新增結(jié)束
      ),
      body: _buildSuggestions(),
    );
  }
  ...
}

提示: 某些 widget 屬性需要單個(gè) widget(child),而其它一些屬性,如 action,需要一組widgets(children),用方括號(hào) [] 表示。

在 RandomWordsState 這個(gè)類里添加 _pushSaved() 方法:

class RandomWordsState extends State<RandomWords> {
  ...
  // 新增代碼開始
  void _pushSaved() {
  }
  // 新增代碼結(jié)束 
}

熱重載應(yīng)用,列表圖標(biāo)(

)將會(huì)出現(xiàn)在導(dǎo)航欄中。現(xiàn)在點(diǎn)擊它不會(huì)有任何反應(yīng),因?yàn)?_pushSaved 函數(shù)還是空的。

接下來,(當(dāng)用戶點(diǎn)擊導(dǎo)航欄中的列表圖標(biāo)時(shí))我們會(huì)建立一個(gè)路由并將其推入到導(dǎo)航管理器棧中。此操作會(huì)切換頁面以顯示新路由,新頁面的內(nèi)容會(huì)在 MaterialPageRoute 的 builder 屬性中構(gòu)建,builder 是一個(gè)匿名函數(shù)。

添加 Navigator.push 調(diào)用,這會(huì)使路由入棧(以后路由入棧均指推入到導(dǎo)航管理器的棧)

void _pushSaved() {
  Navigator.of(context).push(
  );
}

接下來,添加 MaterialPageRoute 及其 builder。 現(xiàn)在,添加生成 ListTile 行的代碼,ListTile 的 divideTiles() 方法在每個(gè) ListTile 之間添加 1 像素的分割線。 該 divided 變量持有最終的列表項(xiàng),并通過 toList()方法非常方便的轉(zhuǎn)換成列表顯示。

添加如下所示的代碼:

void _pushSaved() {
  Navigator.of(context).push(
    new MaterialPageRoute<void>(   // 新增如下20行代碼 ...
      builder: (BuildContext context) {
        final Iterable<ListTile> tiles = _saved.map(
          (WordPair pair) {
            return new ListTile(
              title: new Text(
                pair.asPascalCase,
                style: _biggerFont,
              ),
            );
          },
        );
        final List<Widget> divided = ListTile
          .divideTiles(
            context: context,
            tiles: tiles,
          )
          .toList();
      },
    ),                           // ... 新增代碼結(jié)束
  );
}

builder 返回一個(gè) Scaffold,其中包含名為"Saved Suggestions"的新路由的應(yīng)用欄。新路由的body 由包含 ListTiles 行的 ListView 組成;每行之間通過一個(gè)分隔線分隔。

添加水平分隔符,如下代碼所示:

void _pushSaved() {
  Navigator.of(context).push(
    new MaterialPageRoute<void>(
      builder: (BuildContext context) {
        final Iterable<ListTile> tiles = _saved.map(
          (WordPair pair) {
            return new ListTile(
              title: new Text(
                pair.asPascalCase,
                style: _biggerFont,
              ),
            );
          },
        );
        final List<Widget> divided = ListTile
          .divideTiles(
            context: context,
            tiles: tiles,
          )
              .toList();

        return new Scaffold(         // 新增 6 行代碼開始 ...
          appBar: new AppBar(
            title: const Text('Saved Suggestions'),
          ),
          body: new ListView(children: divided),
        );                           // ... 新增代碼段結(jié)束.
      },
    ),
  );
}

熱重載應(yīng)用程序,點(diǎn)擊列表項(xiàng)收藏一些項(xiàng),點(diǎn)擊列表圖標(biāo)(

),在新的 route(路由)頁面中顯示收藏的內(nèi)容。Navigator(導(dǎo)航器)會(huì)在應(yīng)用欄中自動(dòng)添加一個(gè)"返回"按鈕,無需調(diào)用Navigator.pop,點(diǎn)擊后退按鈕就會(huì)返回到主頁路由。

使用 Themes 修改 UI

這一部分,我們將會(huì)一起修改應(yīng)用的主題。Flutter 里我們使用 theme 來控制你應(yīng)用的外觀和風(fēng)格,你可以使用默認(rèn)主題,該主題取決于物理設(shè)備或模擬器,也可以自定義主題以適應(yīng)您的品牌。

你可以通過配置 ThemeData 類輕松更改應(yīng)用程序的主題,目前我們的應(yīng)用程序使用默認(rèn)主題,下面將更改 primaryColor 顏色為白色。

在 MyApp 這個(gè)類里修改顏色:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Startup Name Generator',
      theme: new ThemeData(          // 新增代碼開始... 
        primaryColor: Colors.white,
      ),                             // ... 代碼新增結(jié)束
      home: new RandomWords(),
    );
  }
}

熱重載應(yīng)用。 你會(huì)發(fā)現(xiàn),整個(gè)背景將會(huì)變?yōu)榘咨?app bar(應(yīng)用欄)。

一個(gè)小練習(xí),你可以看一下 ThemeData 的文檔,添加其他屬性來更多改變 UI 樣式。Material library 中的 Colors 類提供了許多可以使用的顏色常量, 你可以使用熱重載來快速簡(jiǎn)單地嘗試、實(shí)驗(yàn)。


以上完成了一個(gè)ListView

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,702評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,143評(píng)論 3 415
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,553評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,620評(píng)論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,416評(píng)論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,940評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,024評(píng)論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,170評(píng)論 0 287
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,709評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,597評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,784評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,291評(píng)論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,029評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,407評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,663評(píng)論 1 280
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,403評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,746評(píng)論 2 370

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