Flutter開發(fā)實(shí)戰(zhàn) 高仿微信(1)首頁

Flutter開發(fā)實(shí)戰(zhàn) 高仿微信(1)首頁

flutter 開發(fā)微信項(xiàng)目 (1)首頁

源碼地址:flutter_wetchat

1. 開發(fā)HomePage頁

  1. 運(yùn)行效果:


    在這里插入圖片描述
  2. 功能介紹
  3. 代碼講解
  • KYLRootPage是根頁面
class KYLRootPage extends StatefulWidget {
  
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return _RootPageState();
  }

}

class _RootPageState extends State<KYLRootPage> {
  int _currentIndex = 0;

  List<Widget> pages = [Scaffold(
    appBar: AppBar(
      title: Text('微信'),
    ),
    body: Center(
      child: Text('微信主頁'),
    ),
  ),
    Scaffold(
      appBar: AppBar(
        title: Text('通訊錄'),
      ),
      body: Center(
        child: Text('通訊錄列表'),
      ),
    ),
    Scaffold(
      appBar: AppBar(
        title: Text('發(fā)現(xiàn)'),
      ),
      body: Center(
        child: Text('發(fā)現(xiàn)列表'),
      ),
    ),
    Scaffold(
      appBar: AppBar(
        title: Text('我'),
      ),
      body: Center(
        child: Text('我的頁面'),
      ),
    )
  ];


  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Container(
      child: Scaffold(
      bottomNavigationBar: BottomNavigationBar(
        onTap: (int index) {
          _currentIndex = index;
        },
          type: BottomNavigationBarType.fixed,
          fixedColor: Colors.green,
          currentIndex: _currentIndex,
          items: <BottomNavigationBarItem>[
        BottomNavigationBarItem(
          icon: Icon(Icons.chat),
          title: Text('微信'),
        ),
        BottomNavigationBarItem(
          icon: Icon(Icons.bookmark),
          title: Text('通訊錄'),
        ),
        BottomNavigationBarItem(
          icon: Icon(Icons.history),
          title: Text('發(fā)現(xiàn)'),
        ),
        BottomNavigationBarItem(
          icon: Icon(Icons.person_outline),
          title: Text('我'),
        ),
      ]),
        body: pages[_currentIndex],
      ),
    );
  }
}
  • main.dart
import 'package:flutter/material.dart';
import 'KYLRootPage.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        // This is the theme of your application.
        //
        // Try running your application with "flutter run". You'll see the
        // application has a blue toolbar. Then, without quitting the app, try
        // changing the primarySwatch below to Colors.green and then invoke
        // "hot reload" (press "r" in the console where you ran "flutter run",
        // or simply save your changes to "hot reload" in a Flutter IDE).
        // Notice that the counter didn't reset back to zero; the application
        // is not restarted.
        primarySwatch: Colors.blue,
      ),
      home: KYLRootPage(),
    );
  }
}

2. 用到的知識(shí)點(diǎn)講解

2.1 BottomNavigationBar

在這里插入圖片描述

相當(dāng)于是一個(gè)自定義的Button,用來放在BottomNavigationBar上,它實(shí)現(xiàn)了Material(Android)和Cupertino(iOS)兩種風(fēng)格。

在這里插入圖片描述

Scaffold是Root Widget- MaterialApp的腳手架。封裝了Material Design App會(huì)用到的AppBar,Drawer,SnackBar,BottomNavigationBar等。BottomNavigationBarType有fixed 和shifting兩種樣式,超過3個(gè)才會(huì)有區(qū)別,一般為了體驗(yàn)一致,我們會(huì)用fixed type。

BottomNavigationBar是一個(gè)StatefulWidget,可以按以下步驟分析這種組件:
1,先看它持有的狀態(tài);
2,看下他的生命周期實(shí)現(xiàn);
3,再仔細(xì)分析它的build方法.

  • 持有狀態(tài)
List<AnimationController> _controllers = <AnimationController>[];
List<CurvedAnimation> _animations;

// A queue of color splashes currently being animated.
final Queue<_Circle> _circles = Queue<_Circle>();

// Last splash circle's color, and the final color of the control after
// animation is complete.
Color _backgroundColor;

前面三個(gè)屬性都和動(dòng)畫相關(guān),第四個(gè)是設(shè)背景。
這里有個(gè)疑問:BottomNavigationBar為什么沒有變量標(biāo)記當(dāng)前哪個(gè)item選中?

函數(shù)式編程一個(gè)原則是要函數(shù)盡量純,currentIndex這個(gè)屬性依賴外邊傳入,每次變化重新觸發(fā)Render。如果自己維護(hù),則還需要提供一個(gè)回調(diào)方法供外部調(diào)用,返回最新的currentIndex值。

  • 生命周期方法
// 初始化操作,具體實(shí)現(xiàn)再resetState里,對(duì)上面的這些狀態(tài)屬性初始化操作
@override
//initState里有個(gè)操作比較隱蔽:_controllers[widget.currentIndex].value = 1.0;
void initState() {
  super.initState();
  _resetState();
}

// 回收資源操作,一般用到動(dòng)畫都需要的
@override
void dispose() {
    for (AnimationController controller in _controllers)
      controller.dispose();
    for (_Circle circle in _circles)
      circle.dispose();
    super.dispose();
  }

// 當(dāng)屬性變化時(shí)Flutter系統(tǒng)回調(diào)該方法。當(dāng)item數(shù)量變化時(shí)直接重新初始化;當(dāng)index變化,做相應(yīng)動(dòng)畫。
@override
void didUpdateWidget(BottomNavigationBar oldWidget) {
    super.didUpdateWidget(oldWidget);

    // No animated segue if the length of the items list changes.
    if (widget.items.length != oldWidget.items.length) {
      _resetState();
      return;
    }

    if (widget.currentIndex != oldWidget.currentIndex) {
      switch (widget.type) {
        case BottomNavigationBarType.fixed:
          break;
        case BottomNavigationBarType.shifting:
          _pushCircle(widget.currentIndex);
          break;
      }
      _controllers[oldWidget.currentIndex].reverse();
      _controllers[widget.currentIndex].forward();
    }

    if (_backgroundColor != widget.items[widget.currentIndex].backgroundColor)
      _backgroundColor = widget.items[widget.currentIndex].backgroundColor;
  }

// 下面分析
@override
Widget build(BuildContext context) {}
  • 分析build方法
@override
  Widget build(BuildContext context) {
    // debug 檢查
    assert(debugCheckHasDirectionality(context));
    assert(debugCheckHasMaterialLocalizations(context));

    // Labels apply up to _bottomMargin padding. Remainder is media padding.
    final double additionalBottomPadding = math.max(MediaQuery.of(context).padding.bottom - _kBottomMargin, 0.0);
    
    // 根據(jù)BottomNavigationBarType設(shè)背景色,shifting才會(huì)有
    Color backgroundColor;
    switch (widget.type) {
      case BottomNavigationBarType.fixed:
        break;
      case BottomNavigationBarType.shifting:
        backgroundColor = _backgroundColor;
        break;
    }
    return Semantics( // Semantics用來實(shí)現(xiàn)無障礙的
      container: true,
      explicitChildNodes: true,
      child: Stack(
        children: <Widget>[
          Positioned.fill(
            child: Material( // Casts shadow.
              elevation: 8.0,
              color: backgroundColor,
            ),
          ),
          ConstrainedBox(
            constraints: BoxConstraints(minHeight: kBottomNavigationBarHeight + additionalBottomPadding),
            child: Stack(
              children: <Widget>[
                Positioned.fill(  // 點(diǎn)擊時(shí)的圓形類波紋動(dòng)畫
                  child: CustomPaint(
                    painter: _RadialPainter(
                      circles: _circles.toList(),
                      textDirection: Directionality.of(context),
                    ),
                  ),
                ),
                Material( // Splashes.
                  type: MaterialType.transparency,
                  child: Padding(
                    padding: EdgeInsets.only(bottom: additionalBottomPadding),
                    child: MediaQuery.removePadding(
                      context: context,
                      removeBottom: true, 
                      // tiles就是_BottomNavigationTile,里面放BottomNavigationBarItem
                      child: _createContainer(_createTiles()),
                    )))]))]));
  }}
  • _BottomNavigationTile看下
Widget _buildIcon() {
    ...
    // 構(gòu)建Icon
  }

  Widget _buildFixedLabel() {
   ....
          // 騷操作,用矩陣來給文字作動(dòng)畫,更平滑
          // The font size should grow here when active, but because of the way
          // font rendering works, it doesn't grow smoothly if we just animate
          // the font size, so we use a transform instead.
          child: Transform(
            transform: Matrix4.diagonal3(
              Vector3.all(
                Tween<double>(
                  begin: _kInactiveFontSize / _kActiveFontSize,
                  end: 1.0,
                ).evaluate(animation),
              ),
            ),
            alignment: Alignment.bottomCenter,
            child: item.title,
          ),
        ),
      ),
    );
  }

  Widget _buildShiftingLabel() {
    return Align(
.....
        // shifting的label是fade動(dòng)畫,只有當(dāng)前選中的才會(huì)顯示label
        child: FadeTransition(
          alwaysIncludeSemantics: true,
          opacity: animation,
          child: DefaultTextStyle.merge(
            style: const TextStyle(
              fontSize: _kActiveFontSize,
              color: Colors.white,
            ),
            child: item.title,
          ),
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    int size;
    Widget label;
    // 生成不同的label
    switch (type) {
      case BottomNavigationBarType.fixed:
        size = 1;
        label = _buildFixedLabel();
        break;
      case BottomNavigationBarType.shifting:
        size = (flex * 1000.0).round();
        label = _buildShiftingLabel();
        break;
    }
    return Expanded(
    ....
                children: <Widget>[
                  _buildIcon(),
                  label,
                ],
              ),
            ),
            Semantics(
              label: indexLabel,
}

2.2 Container

2.2.1. 簡(jiǎn)介

Container在Flutter中太常見了。官方給出的簡(jiǎn)介,是一個(gè)結(jié)合了繪制(painting)、定位(positioning)以及尺寸(sizing)widget的widget。
可以得出幾個(gè)信息,它是一個(gè)組合的widget,內(nèi)部有繪制widget、定位widget、尺寸widget。后續(xù)看到的不少widget,都是通過一些更基礎(chǔ)的widget組合而成的。

2.2.2. 組成
  1. Container的組成如下:

最里層的是child元素;
child元素首先會(huì)被padding包著;
然后添加額外的constraints限制;
最后添加margin。

  1. Container的繪制的過程如下:

首先會(huì)繪制transform效果;
接著繪制decoration;
然后繪制child;
最后繪制foregroundDecoration。

  1. Container自身尺寸的調(diào)節(jié)分兩種情況:

Container在沒有子節(jié)點(diǎn)(children)的時(shí)候,會(huì)試圖去變得足夠大。除非constraints是unbounded限制,在這種情況下,Container會(huì)試圖去變得足夠小。
帶子節(jié)點(diǎn)的Container,會(huì)根據(jù)子節(jié)點(diǎn)尺寸調(diào)節(jié)自身尺寸,但是Container構(gòu)造器中如果包含了width、height以及constraints,則會(huì)按照構(gòu)造器中的參數(shù)來進(jìn)行尺寸的調(diào)節(jié)。

2.2.3. Container的屬性
  • key:Container唯一標(biāo)識(shí)符,用于查找更新。

  • alignment:控制child的對(duì)齊方式,如果container或者container父節(jié)點(diǎn)尺寸大于child的尺寸,這個(gè)屬性設(shè)置會(huì)起作用,有很多種對(duì)齊方式。

  • padding:decoration內(nèi)部的空白區(qū)域,如果有child的話,child位于padding內(nèi)部。padding與margin的不同之處在于,padding是包含在content內(nèi),而margin則是外部邊界,設(shè)置點(diǎn)擊事件的話,padding區(qū)域會(huì)響應(yīng),而margin區(qū)域不會(huì)響應(yīng)。

  • color:用來設(shè)置container背景色,如果foregroundDecoration設(shè)置的話,可能會(huì)遮蓋color效果。

  • decoration:繪制在child后面的裝飾,設(shè)置了decoration的話,就不能設(shè)置color屬性,否則會(huì)報(bào)錯(cuò),此時(shí)應(yīng)該在decoration中進(jìn)行顏色的設(shè)置。

  • foregroundDecoration:繪制在child前面的裝飾。

  • width:container的寬度,設(shè)置為double.infinity可以強(qiáng)制在寬度上撐滿,不設(shè)置,則根據(jù)child和父節(jié)點(diǎn)兩者一起布局。

  • height:container的高度,設(shè)置為double.infinity可以強(qiáng)制在高度上撐滿。

  • constraints:添加到child上額外的約束條件。

  • margin:圍繞在decoration和child之外的空白區(qū)域,不屬于內(nèi)容區(qū)域。

  • transform:設(shè)置container的變換矩陣,類型為Matrix4。

  • child:container中的內(nèi)容widget。

實(shí)例:

new Container(
  constraints: new BoxConstraints.expand(
    height:Theme.of(context).textTheme.display1.fontSize * 1.1 + 200.0,
  ),
  decoration: new BoxDecoration(
    border: new Border.all(width: 2.0, color: Colors.red),
    color: Colors.grey,
    borderRadius: new BorderRadius.all(new Radius.circular(20.0)),
    image: new DecorationImage(
      image: new NetworkImage('http://h.hiphotos.baidu.com/zhidao/wh%3D450%2C600/sign=0d023672312ac65c67506e77cec29e27/9f2f070828381f30dea167bbad014c086e06f06c.jpg'),
      centerSlice: new Rect.fromLTRB(270.0, 180.0, 1360.0, 730.0),
    ),
  ),
  padding: const EdgeInsets.all(8.0),
  alignment: Alignment.center,
  child: new Text('Hello World',
    style: Theme.of(context).textTheme.display1.copyWith(color: Colors.black)),
  transform: new Matrix4.rotationZ(0.3),
)
2.2.4. Container使用

Container算是目前項(xiàng)目中,最經(jīng)常用到的一個(gè)widget。在實(shí)際使用過程中,筆者在以下情況會(huì)使用到Container,當(dāng)然并不是絕對(duì)的,也可以通過其他widget來實(shí)現(xiàn)。

  1. 需要設(shè)置間隔(這種情況下,如果只是單純的間隔,也可以通過Padding來實(shí)現(xiàn));
  2. 需要設(shè)置背景色;
  3. 需要設(shè)置圓角或者邊框的時(shí)候(ClipRRect也可以實(shí)現(xiàn)圓角效果);
  4. 需要對(duì)齊(Align也可以實(shí)現(xiàn));
  5. 需要設(shè)置背景圖片的時(shí)候(也可以使用Stack實(shí)現(xiàn))。
2.2.5. Container源碼分析
decoration = decoration ?? (color != null ? new BoxDecoration(color: color) : null),

可以看出,對(duì)于顏色的設(shè)置,最后都是轉(zhuǎn)換為decoration來進(jìn)行繪制的。如果同時(shí)包含decoration和color兩種屬性,則會(huì)報(bào)錯(cuò)。

@override
  Widget build(BuildContext context) {
    Widget current = child;

    if (child == null && (constraints == null || !constraints.isTight)) {
      current = new LimitedBox(
        maxWidth: 0.0,
        maxHeight: 0.0,
        child: new ConstrainedBox(constraints: const BoxConstraints.expand())
      );
    }

    if (alignment != null)
      current = new Align(alignment: alignment, child: current);

    final EdgeInsetsGeometry effectivePadding = _paddingIncludingDecoration;
    if (effectivePadding != null)
      current = new Padding(padding: effectivePadding, child: current);

    if (decoration != null)
      current = new DecoratedBox(decoration: decoration, child: current);

    if (foregroundDecoration != null) {
      current = new DecoratedBox(
        decoration: foregroundDecoration,
        position: DecorationPosition.foreground,
        child: current
      );
    }

    if (constraints != null)
      current = new ConstrainedBox(constraints: constraints, child: current);

    if (margin != null)
      current = new Padding(padding: margin, child: current);

    if (transform != null)
      current = new Transform(transform: transform, child: current);

    return current;
  }

Container的build函數(shù)不長(zhǎng),繪制也是一個(gè)線性的判斷的過程,一層一層的包裹著widget,去實(shí)現(xiàn)不同的樣式。
最里層的是child,如果為空或者其他約束條件,則最里層包含的為一個(gè)LimitedBox,然后依次是Align、Padding、DecoratedBox、前景DecoratedBox、ConstrainedBox、Padding(實(shí)現(xiàn)margin效果)、Transform。
Container的源碼本身并不復(fù)雜,復(fù)雜的是它的各種布局表現(xiàn)。我們謹(jǐn)記住一點(diǎn),如果內(nèi)部不設(shè)置約束,則按照父節(jié)點(diǎn)盡可能的擴(kuò)大,如果內(nèi)部有約束,則按照內(nèi)部來。

2.3 Scaffold

Scaffold 實(shí)現(xiàn)了基本的 Material 布局。只要是在 Material 中定義了的單個(gè)界面顯示的布局控件元素,都可以使用 Scaffold 來繪制。
提供展示抽屜(drawers,比如:左邊欄)、通知(snack bars) 以及 底部按鈕(bottom sheets)。
我們可以將 Scaffold 理解為一個(gè)布局的容器。可以在這個(gè)容器中繪制我們的用戶界面。

  1. Scaffold源碼分析


    在這里插入圖片描述
  2. Scaffold 主要的屬性說明

  • appBar:顯示在界面頂部的一個(gè) AppBar
    相關(guān)連接:https://flutterchina.club/catalog/samples/
  • body:當(dāng)前界面所顯示的主要內(nèi)容
  • floatingActionButton: 在 Material 中定義的一個(gè)功能按鈕。
  • persistentFooterButtons:固定在下方顯示的按鈕。https://material.google.com/components/buttons.html#buttons-persistent-footer-buttons
  • drawer:側(cè)邊欄控件
  • bottomNavigationBar:顯示在底部的導(dǎo)航欄按鈕欄。可以查看文檔:Flutter學(xué)習(xí)之制作底部菜單導(dǎo)航
  • backgroundColor:背景顏色
  • resizeToAvoidBottomPadding: 控制界面內(nèi)容 body
    是否重新布局來避免底部被覆蓋了,比如當(dāng)鍵盤顯示的時(shí)候,重新布局避免被鍵盤蓋住內(nèi)容。默認(rèn)值為 true。
  1. 代碼示例
class Scaffold extends StatefulWidget {
  /// Creates a visual scaffold for material design widgets.
  const Scaffold({
    Key key,
    this.appBar, //橫向水平布局,通常顯示在頂部(*)
    this.body, // 內(nèi)容(*)
    this.floatingActionButton, //懸浮按鈕,就是上圖右下角按鈕(*)
    this.floatingActionButtonLocation, //懸浮按鈕位置
    //懸浮按鈕在[floatingActionButtonLocation]出現(xiàn)/消失動(dòng)畫
    this.floatingActionButtonAnimator, 
    //在底部呈現(xiàn)一組button,顯示于[bottomNavigationBar]之上,[body]之下
    this.persistentFooterButtons,
    //一個(gè)垂直面板,顯示于左側(cè),初始處于隱藏狀態(tài)(*)
    this.drawer,
    this.endDrawer,
    //出現(xiàn)于底部的一系列水平按鈕(*)
    this.bottomNavigationBar,
    //底部持久化提示框
    this.bottomSheet,
    //內(nèi)容背景顏色
    this.backgroundColor,
    //棄用,使用[resizeToAvoidBottomInset]
    this.resizeToAvoidBottomPadding,
    //重新計(jì)算布局空間大小
    this.resizeToAvoidBottomInset,
    //是否顯示到底部,默認(rèn)為true將顯示到頂部狀態(tài)欄
    this.primary = true,
    //
    this.drawerDragStartBehavior = DragStartBehavior.down,
  }) : assert(primary != null),
       assert(drawerDragStartBehavior != null),
       super(key: key);


  1. Scaffold.of 使用說明

關(guān)于 Scaffold.of 函數(shù)的說明:https://docs.flutter.io/flutter/material/Scaffold/of.html

顯示 snackbar 或者 bottom sheet 的時(shí)候,需要使用當(dāng)前的 BuildContext 參數(shù)調(diào)用 Scaffold.of 函數(shù)來獲取 ScaffoldState 對(duì)象,然后使用 ScaffoldState.showSnackBar 和 ScaffoldState.showBottomSheet 函數(shù)來顯示。

來自官方源碼上面的例子。使用 SnackBar 的寫法。

@override
 Widget build(BuildContext context) {
   return new RaisedButton(
     child: new Text('SHOW A SNACKBAR'),
     onPressed: () {
       Scaffold.of(context).showSnackBar(new SnackBar(
         content: new Text('Hello!'),
       ));
     },
   );
 }

當(dāng) Scaffold 實(shí)際上是在同一個(gè)構(gòu)建函數(shù)中創(chuàng)建時(shí),構(gòu)建函數(shù)的 BuildContext 參數(shù)不能用于查找 Scaffold(因?yàn)樗挥诜祷氐男〔考摹吧戏健保?因?yàn)樵谠创a中 使用的是 return new Scaffold(app:xxxx),在這種情況下面,通過在 Scaffold 中使用一個(gè) Builder 來提供一個(gè)新的 BuildContext:

@override
Widget build(BuildContext context) {
  return new Scaffold(
    appBar: new AppBar(
      title: new Text('Demo')
    ),
    body: new Builder(
      // Create an inner BuildContext so that the onPressed methods
      // can refer to the Scaffold with Scaffold.of().
      builder: (BuildContext context) {
        return new Center(
          child: new RaisedButton(
            child: new Text('SHOW A SNACKBAR'),
            onPressed: () {
              Scaffold.of(context).showSnackBar(new SnackBar(
                content: new Text('Hello!'),
              ));
            },
          ),
        );
      },
    ),
  );
}

按照官方的說法,可以將我們的構(gòu)建函數(shù)拆分到多個(gè) Widgets中。分別引入新的 BuildContext 來獲取 Scaffold.

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

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