【Flutter實(shí)戰(zhàn)】六大布局組件及半圓菜單案例

老孟導(dǎo)讀:Flutter中布局組件有水平 / 垂直布局組件( RowColumn )俐末、疊加布局組件( StackIndexedStack )帽驯、流式布局組件( Wrap )和 自定義布局組件(Flow)。

水平、垂直布局組件

Row 是將子組件以水平方式布局的組件, Column 是將子組件以垂直方式布局的組件。項(xiàng)目中 90% 的頁面布局都可以通過 Row 和 Column 來實(shí)現(xiàn)逢净。

將3個組件水平排列:

Row(
  children: <Widget>[
    Container(
      height: 50,
      width: 100,
      color: Colors.red,
    ),
    Container(
      height: 50,
      width: 100,
      color: Colors.green,
    ),
    Container(
      height: 50,
      width: 100,
      color: Colors.blue,
    ),
  ],
)

將3個組件垂直排列:

Column(
  mainAxisSize: MainAxisSize.min,
  children: <Widget>[
    Container(
      height: 50,
      width: 100,
      color: Colors.red,
    ),
    Container(
      height: 50,
      width: 100,
      color: Colors.green,
    ),
    Container(
      height: 50,
      width: 100,
      color: Colors.blue,
    ),
  ],
)

在 Row 和 Column 中有一個非常重要的概念:主軸( MainAxis )交叉軸( CrossAxis ),主軸就是與組件布局方向一致的軸歼指,交叉軸就是與主軸方向垂直的軸爹土。

具體到 Row 組件,主軸 是水平方向踩身,交叉軸 是垂直方向胀茵。而 Column 與 Row 正好相反,主軸 是垂直方向挟阻,交叉軸 是水平方向琼娘。

明白了 主軸 和 交叉軸 概念,我們來看下 mainAxisAlignment 屬性附鸽,此屬性表示主軸方向的對齊方式脱拼,默認(rèn)值為 start,表示從組件的開始處布局坷备,此處的開始位置和 textDirection 屬性有關(guān)熄浓,textDirection 表示文本的布局方向,其值包括 ltr(從左到右) 和 rtl(從右到左)省撑,當(dāng) textDirection = ltr 時赌蔑,start 表示左側(cè)俯在,當(dāng) textDirection = rtl 時,start 表示右側(cè)娃惯,

Container(
  decoration: BoxDecoration(border: Border.all(color: Colors.black)),
  child: Row(
    children: <Widget>[
      Container(
        height: 50,
        width: 100,
        color: Colors.red,
      ),
      Container(
        height: 50,
        width: 100,
        color: Colors.green,
      ),
      Container(
        height: 50,
        width: 100,
        color: Colors.blue,
      ),
    ],
  ),
)

黑色邊框是Row控件的范圍跷乐,默認(rèn)情況下Row鋪滿父組件。

主軸對齊方式有6種石景,效果如下圖:

spaceAround 和 spaceEvenly 區(qū)別是:

  • spaceAround :第一個子控件距開始位置和最后一個子控件距結(jié)尾位置是其他子控件間距的一半劈猿。
  • spaceEvenly : 所有間距一樣。

和主軸對齊方式相對應(yīng)的就是交叉軸對齊方式 crossAxisAlignment 潮孽,交叉軸對齊方式默認(rèn)是居中揪荣。Row控件的高度是依賴子控件高度,因此子控件高都一樣時往史,Row的高和子控件高相同仗颈,此時是無法體現(xiàn)交叉軸對齊方式,修改3個顏色塊高分別為50椎例,100挨决,150,這樣Row的高是150订歪,代碼如下:

Container(
      decoration: BoxDecoration(border: Border.all(color: Colors.black)),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.center,
        children: <Widget>[
          Container(
            height: 50,
            width: 100,
            color: Colors.red,
          ),
          Container(
            height: 100,
            width: 100,
            color: Colors.green,
          ),
          Container(
            height: 150,
            width: 100,
            color: Colors.blue,
          ),
        ],
      ),
    )

主軸對齊方式效果如下圖:

mainAxisSize 表示主軸尺寸脖祈,有 min 和 max 兩種方式,默認(rèn)是 max刷晋。min 表示盡可能小盖高,max 表示盡可能大。

Container(
    decoration: BoxDecoration(border: Border.all(color: Colors.black)),
    child: Row(
        mainAxisSize: MainAxisSize.min,
        ...
    )
)

看黑色邊框眼虱,正好包裹子組件喻奥,而 max 效果如下:

textDirection 表示子組件主軸布局方向,值包括 ltr(從左到右) 和 rtl(從右到左)

Container(
  decoration: BoxDecoration(border: Border.all(color: Colors.black)),
  child: Row(
    textDirection: TextDirection.rtl,
    children: <Widget>[
      ...
    ],
  ),
)

verticalDirection 表示子組件交叉軸布局方向:

  • up :從底部開始捏悬,并垂直堆疊到頂部撞蚕,對齊方式的 start 在底部,end 在頂部过牙。
  • down: 與 up 相反甥厦。
Container(
  decoration: BoxDecoration(border: Border.all(color: Colors.black)),
  child: Row(
    crossAxisAlignment: CrossAxisAlignment.start,
    verticalDirection: VerticalDirection.up,
    children: <Widget>[
      Container(
        height: 50,
        width: 100,
        color: Colors.red,
      ),
      Container(
        height: 100,
        width: 100,
        color: Colors.green,
      ),
      Container(
        height: 150,
        width: 100,
        color: Colors.blue,
      ),
    ],
  ),
)

想一想這種效果完全可以通過對齊方式實(shí)現(xiàn),那么為什么還要有 textDirectionverticalDirection 這兩個屬性寇钉,官方API文檔已經(jīng)解釋了這個問題:

This is also used to disambiguate start and end values (e.g. [MainAxisAlignment.start] or [CrossAxisAlignment.end]).

用于消除 MainAxisAlignment.start 和 CrossAxisAlignment.end 值的歧義的矫渔。

疊加布局組件

疊加布局組件包含 StackIndexedStack,Stack 組件將子組件疊加顯示摧莽,根據(jù)子組件的順利依次向上疊加,用法如下:

Stack(
  children: <Widget>[
    Container(
      height: 200,
      width: 200,
      color: Colors.red,
    ),
    Container(
      height: 170,
      width: 170,
      color: Colors.blue,
    ),
    Container(
      height: 140,
      width: 140,
      color: Colors.yellow,
    )
  ],
)

Stack 對未定位(不被 Positioned 包裹)子組件的大小由 fit 參數(shù)決定顿痪,默認(rèn)值是 StackFit.loose 镊辕,表示子組件自己決定油够,StackFit.expand 表示盡可能的大,用法如下:

Stack(
  fit: StackFit.expand,
  children: <Widget>[
    Container(
      height: 200,
      width: 200,
      color: Colors.red,
    ),
    Container(
      height: 170,
      width: 170,
      color: Colors.blue,
    ),
    Container(
      height: 140,
      width: 140,
      color: Colors.yellow,
    )
  ],
)

效果只有黃色(最后一個組件的顏色)征懈,并不是其他組件沒有繪制石咬,而是另外兩個組件被黃色組件覆蓋。

Stack 對未定位(不被 Positioned 包裹)子組件的對齊方式由 alignment 控制卖哎,默認(rèn)左上角對齊鬼悠,用法如下:

Stack(
  alignment: AlignmentDirectional.center,
  children: <Widget>[
    Container(
      height: 200,
      width: 200,
      color: Colors.red,
    ),
    Container(
      height: 170,
      width: 170,
      color: Colors.blue,
    ),
    Container(
      height: 140,
      width: 140,
      color: Colors.yellow,
    )
  ],
)

通過 Positioned 定位的子組件:

Stack(
  alignment: AlignmentDirectional.center,
  children: <Widget>[
    Container(
      height: 200,
      width: 200,
      color: Colors.red,
    ),
    Container(
      height: 170,
      width: 170,
      color: Colors.blue,
    ),
    Positioned(
      left: 30,
      right: 40,
      bottom: 50,
      top: 60,
      child: Container(
        color: Colors.yellow,
      ),
    )
  ],
)

topbottom 亏娜、left 焕窝、right 四種定位屬性,分別表示距離上下左右的距離维贺。

如果子組件超過 Stack 邊界由 overflow 控制它掂,默認(rèn)是裁剪,下面設(shè)置總是顯示的用法:

Stack(
  overflow: Overflow.visible,
  children: <Widget>[
    Container(
      height: 200,
      width: 200,
      color: Colors.red,
    ),
    Positioned(
      left: 100,
      top: 100,
      height: 150,
      width: 150,
      child: Container(
        color: Colors.green,
      ),
    )
  ],
)

IndexedStack 是 Stack 的子類溯泣,Stack 是將所有的子組件疊加顯示虐秋,而 IndexedStack 通過 index 只顯示指定索引的子組件,用法如下:

class IndexedStackDemo extends StatefulWidget {
  @override
  _IndexedStackDemoState createState() => _IndexedStackDemoState();
}

class _IndexedStackDemoState extends State<IndexedStackDemo> {
  int _index = 0;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        SizedBox(height: 50,),
        _buildIndexedStack(),
        SizedBox(height: 30,),
        _buildRow(),
      ],
    );
  }

  _buildIndexedStack() {
    return IndexedStack(
      index: _index,
      children: <Widget>[
        Center(
          child: Container(
            height: 300,
            width: 300,
            color: Colors.red,
            alignment: Alignment.center,
            child: Icon(
              Icons.fastfood,
              size: 60,
              color: Colors.blue,
            ),
          ),
        ),
        Center(
          child: Container(
            height: 300,
            width: 300,
            color: Colors.green,
            alignment: Alignment.center,
            child: Icon(
              Icons.cake,
              size: 60,
              color: Colors.blue,
            ),
          ),
        ),
        Center(
          child: Container(
            height: 300,
            width: 300,
            color: Colors.yellow,
            alignment: Alignment.center,
            child: Icon(
              Icons.local_cafe,
              size: 60,
              color: Colors.blue,
            ),
          ),
        ),
      ],
    );
  }

  _buildRow() {
    return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        IconButton(
          icon: Icon(Icons.fastfood),
          onPressed: () {
            setState(() {
              _index = 0;
            });
          },
        ),
        IconButton(
          icon: Icon(Icons.cake),
          onPressed: () {
            setState(() {
              _index = 1;
            });
          },
        ),
        IconButton(
          icon: Icon(Icons.local_cafe),
          onPressed: () {
            setState(() {
              _index = 2;
            });
          },
        ),
      ],
    );
  }
}

流式布局組件

Wrap 為子組件進(jìn)行水平或者垂直方向布局垃沦,且當(dāng)空間用完時客给,Wrap 會自動換行,也就是流式布局肢簿。

創(chuàng)建多個子控件做為 Wrap 的子控件靶剑,代碼如下:

Wrap(
  children: List.generate(10, (i) {
    double w = 50.0 + 10 * i;
    return Container(
      color: Colors.primaries[i],
      height: 50,
      width: w,
      child: Text('$i'),
    );
  }),
)

direction 屬性控制布局方向,默認(rèn)為水平方向译仗,設(shè)置方向?yàn)榇怪贝a如下:

Wrap(
  direction: Axis.vertical,
  children: List.generate(4, (i) {
    double w = 50.0 + 10 * i;
    return Container(
      color: Colors.primaries[i],
      height: 50,
      width: w,
      child: Text('$i'),
    );
  }),
)

alignment 屬性控制主軸對齊方式抬虽,crossAxisAlignment 屬性控制交叉軸對齊方式,對齊方式只對有剩余空間的行或者列起作用纵菌,例如水平方向上正好填充完整阐污,則不管設(shè)置主軸對齊方式為什么,看上去的效果都是鋪滿咱圆。

說明 :主軸就是與當(dāng)前組件方向一致的軸笛辟,而交叉軸就是與當(dāng)前組件方向垂直的軸,如果Wrap的布局方向?yàn)樗椒较?Axis.horizontal,那么主軸就是水平方向序苏,反之布局方向?yàn)榇怪狈较?Axis.vertical 手幢,主軸就是垂直方向。

Wrap(
    alignment: WrapAlignment.spaceBetween,
    ...
)

主軸對齊方式有6種忱详,效果如下圖:

spaceAroundspaceEvenly 區(qū)別是:

  • spaceAround:第一個子控件距開始位置和最后一個子控件距結(jié)尾位置是其他子控件間距的一半围来。
  • spaceEvenly:所有間距一樣。

設(shè)置交叉軸對齊代碼如下:

Wrap(
    crossAxisAlignment: WrapCrossAlignment.center,
    ...
)

如果 Wrap 的主軸方向?yàn)樗椒较颍徊孑S方向則為垂直方向监透,如果想要看到交叉軸對齊方式的效果需要設(shè)置子控件的高不一樣桶错,代碼如下:

Wrap(
  spacing: 5,
  runSpacing: 3,
  crossAxisAlignment: WrapCrossAlignment.center,
  children: List.generate(10, (i) {
    double w = 50.0 + 10 * i;
    double h = 50.0 + 5 * i;
    return Container(
      color: Colors.primaries[i],
      height: h,
      alignment: Alignment.center,
      width: w,
      child: Text('$i'),
    );
  }),
)

runAlignment 屬性控制 Wrap 的交叉抽方向上每一行的對齊方式,下面直接看 runAlignment 6中方式對應(yīng)的效果圖胀蛮,

runAlignmentalignment 的區(qū)別:

  • alignment :是主軸方向上對齊方式院刁,作用于每一行。
  • runAlignment :是交叉軸方向上將每一行看作一個整體的對齊方式粪狼。

spacingrunSpacing 屬性控制Wrap主軸方向和交叉軸方向子控件之間的間隙退腥,代碼如下:

Wrap(
    spacing: 5,
    runSpacing: 2,
    ...
)

textDirection 屬性表示 Wrap 主軸方向上子組件的方向,取值范圍是 ltr(從左到右) 和 rtl(從右到左)再榄,下面是從右到左的代碼:

Wrap(
    textDirection: TextDirection.rtl,
    ...
)

verticalDirection 屬性表示 Wrap 交叉軸方向上子組件的方向狡刘,取值范圍是 up(向上) 和 down(向下),設(shè)置代碼如下:

Wrap(
    verticalDirection: VerticalDirection.up,
    ...
)

注意:文字為0的組件是在下面的不跟。

自定義布局組件

大部分情況下颓帝,不會使用到 Flow ,但 Flow 可以調(diào)整子組件的位置和大小窝革,結(jié)合Matrix4繪制出各種酷炫的效果购城。

Flow 組件對使用轉(zhuǎn)換矩陣操作子組件經(jīng)過系統(tǒng)優(yōu)化,性能非常高效虐译。

基本用法如下:

Flow(
  delegate: SimpleFlowDelegate(),
  children: List.generate(5, (index) {
    return Container(
      height: 100,
      color: Colors.primaries[index % Colors.primaries.length],
    );
  }),
)

delegate 控制子組件的位置和大小瘪板,定義如下 :

class SimpleFlowDelegate extends FlowDelegate {
  @override
  void paintChildren(FlowPaintingContext context) {
    for (int i = 0; i < context.childCount; ++i) {
      context.paintChild(i);
    }
  }

  @override
  bool shouldRepaint(SimpleFlowDelegate oldDelegate) {
    return false;
  }
}

delegate 要繼承 FlowDelegate,重寫 paintChildrenshouldRepaint 函數(shù)漆诽,上面直接繪制子組件侮攀,效果如下:

只看到一種顏色并不是只繪制了這一個,而是疊加覆蓋了厢拭,和 Stack 類似兰英,下面讓每一個組件有一定的偏移,SimpleFlowDelegate 修改如下:

class SimpleFlowDelegate extends FlowDelegate {
  @override
  void paintChildren(FlowPaintingContext context) {
    for (int i = 0; i < context.childCount; ++i) {
      context.paintChild(i,transform: Matrix4.translationValues(0,i*30.0,0));
    }
  }

  @override
  bool shouldRepaint(SimpleFlowDelegate oldDelegate) {
    return false;
  }
}

每一個子組件比上一個組件向下偏移30供鸠。

仿 掘金-我的效果

效果如下:

到拿到一個頁面時畦贸,先要將其拆分,上面的效果拆分如下:

總體分為3個部分楞捂,水平布局薄坏,紅色區(qū)域圓形頭像代碼如下:

_buildCircleImg() {
  return Container(
    height: 60,
    width: 60,
    decoration: BoxDecoration(
        shape: BoxShape.circle,
        image: DecorationImage(image: AssetImage('assets/images/logo.png'))),
  );
}

藍(lán)色區(qū)域代碼如下:

_buildCenter() {
  return Column(
    mainAxisAlignment: MainAxisAlignment.center,
    crossAxisAlignment: CrossAxisAlignment.start,
    children: <Widget>[
      Text('老孟Flutter', style: TextStyle(fontSize: 20),),
      Text('Flutter、Android', style: TextStyle(color: Colors.grey),)
    ],
  );
}

綠色區(qū)域是一個圖標(biāo)寨闹,代碼如下:

Icon(Icons.arrow_forward_ios,color: Colors.grey,size: 14,),

將這3部分組合在一起:

Container(
  color: Colors.grey.withOpacity(.5),
  alignment: Alignment.center,
  child: Container(
    height: 100,
    color: Colors.white,
    child: Row(
      children: <Widget>[
        SizedBox(
          width: 15,
        ),
        _buildCircleImg(),
        SizedBox(
          width: 25,
        ),
        Expanded(
          child: _buildCenter(),
        ),
        Icon(Icons.arrow_forward_ios,color: Colors.grey,size: 14,),
        SizedBox(
          width: 15,
        ),
      ],
    ),
  ),
)

最終的效果就是開始我們看到的效果圖胶坠。

水平展開/收起菜單

使用Flow實(shí)現(xiàn)水平展開/收起菜單的功能,代碼如下:

class DemoFlowPopMenu extends StatefulWidget {
  @override
  _DemoFlowPopMenuState createState() => _DemoFlowPopMenuState();
}

class _DemoFlowPopMenuState extends State<DemoFlowPopMenu>
    with SingleTickerProviderStateMixin {
  //動畫必須要with這個類
  AnimationController _ctrlAnimationPopMenu; //定義動畫的變量
  IconData lastTapped = Icons.notifications;
  final List<IconData> menuItems = <IconData>[
    //菜單的icon
    Icons.home,
    Icons.new_releases,
    Icons.notifications,
    Icons.settings,
    Icons.menu,
  ];

  void _updateMenu(IconData icon) {
    if (icon != Icons.menu) {
      setState(() => lastTapped = icon);
    } else {
      _ctrlAnimationPopMenu.status == AnimationStatus.completed
          ? _ctrlAnimationPopMenu.reverse() //展開和收攏的效果
          : _ctrlAnimationPopMenu.forward();
    }
  }

  @override
  void initState() {
    super.initState();
    _ctrlAnimationPopMenu = AnimationController(
      //必須初始化動畫變量
      duration: const Duration(milliseconds: 250), //動畫時長250毫秒
      vsync: this, //SingleTickerProviderStateMixin的作用
    );
  }

//生成Popmenu數(shù)據(jù)
  Widget flowMenuItem(IconData icon) {
    final double buttonDiameter =
        MediaQuery.of(context).size.width * 2 / (menuItems.length * 3);
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 8.0),
      child: RawMaterialButton(
        fillColor: lastTapped == icon ? Colors.amber[700] : Colors.blue,
        splashColor: Colors.amber[100],
        shape: CircleBorder(),
        constraints: BoxConstraints.tight(Size(buttonDiameter, buttonDiameter)),
        onPressed: () {
          _updateMenu(icon);
        },
        child: Icon(icon, color: Colors.white, size: 30.0),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Flow(
        delegate: FlowMenuDelegate(animation: _ctrlAnimationPopMenu),
        children: menuItems
            .map<Widget>((IconData icon) => flowMenuItem(icon))
            .toList(),
      ),
    );
  }
}

FlowMenuDelegate 定義如下:

class FlowMenuDelegate extends FlowDelegate {
  FlowMenuDelegate({this.animation}) : super(repaint: animation);
  final Animation<double> animation;

  @override
  void paintChildren(FlowPaintingContext context) {
    double x = 50.0; //起始位置
    double y = 50.0; //橫向展開,y不變
    for (int i = 0; i < context.childCount; ++i) {
      x = context.getChildSize(i).width * i * animation.value;
      context.paintChild(
        i,
        transform: Matrix4.translationValues(x, y, 0),
      );
    }
  }

  @override
  bool shouldRepaint(FlowMenuDelegate oldDelegate) =>
      animation != oldDelegate.animation;
}

半圓菜單展開/收起

代碼如下:

import 'dart:math';

import 'package:flutter/material.dart';

class DemoFlowMenu extends StatefulWidget {
  @override
  _DemoFlowMenuState createState() => _DemoFlowMenuState();
}

class _DemoFlowMenuState extends State<DemoFlowMenu>
    with TickerProviderStateMixin {
  //動畫需要這個類來混合
  //動畫變量,以及初始化和銷毀
  AnimationController _ctrlAnimationCircle;

  @override
  void initState() {
    super.initState();
    _ctrlAnimationCircle = AnimationController(
        //初始化動畫變量
        lowerBound: 0,
        upperBound: 80,
        duration: Duration(milliseconds: 300),
        vsync: this);
    _ctrlAnimationCircle.addListener(() => setState(() {}));
  }

  @override
  void dispose() {
    _ctrlAnimationCircle.dispose(); //銷毀變量,釋放資源
    super.dispose();
  }

  //生成Flow的數(shù)據(jù)
  List<Widget> _buildFlowChildren() {
    return List.generate(
        5,
        (index) => Container(
              child: Icon(
                index.isEven ? Icons.timer : Icons.ac_unit,
                color: Colors.primaries[index % Colors.primaries.length],
              ),
            ));
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        Positioned.fill(
          child: Flow(
            delegate: FlowAnimatedCircle(_ctrlAnimationCircle.value),
            children: _buildFlowChildren(),
          ),
        ),
        Positioned.fill(
          child: IconButton(
            icon: Icon(Icons.menu),
            onPressed: () {
              setState(() {
                //點(diǎn)擊后讓動畫可前行或回退
                _ctrlAnimationCircle.status == AnimationStatus.completed
                    ? _ctrlAnimationCircle.reverse()
                    : _ctrlAnimationCircle.forward();
              });
            },
          ),
        ),
      ],
    );
  }
}

FlowAnimatedCircle 代碼如下:

class FlowAnimatedCircle extends FlowDelegate {
  final double radius; //綁定半徑,讓圓動起來
  FlowAnimatedCircle(this.radius);

  @override
  void paintChildren(FlowPaintingContext context) {
    if (radius == 0) {
      return;
    }
    double x = 0; //開始(0,0)在父組件的中心
    double y = 0;
    for (int i = 0; i < context.childCount; i++) {
      x = radius * cos(i * pi / (context.childCount - 1)); //根據(jù)數(shù)學(xué)得出坐標(biāo)
      y = radius * sin(i * pi / (context.childCount - 1)); //根據(jù)數(shù)學(xué)得出坐標(biāo)
      context.paintChild(i, transform: Matrix4.translationValues(x, -y, 0));
    } //使用Matrix定位每個子組件
  }

  @override
  bool shouldRepaint(FlowDelegate oldDelegate) => true;
}

交流

老孟Flutter博客地址(330個控件用法):http://laomengit.com

歡迎加入Flutter交流群(微信:laomengit)繁堡、關(guān)注公眾號【老孟Flutter】:

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末沈善,一起剝皮案震驚了整個濱河市乡数,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌矮瘟,老刑警劉巖瞳脓,帶你破解...
    沈念sama閱讀 211,376評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異澈侠,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)埋酬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評論 2 385
  • 文/潘曉璐 我一進(jìn)店門哨啃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人写妥,你說我怎么就攤上這事拳球。” “怎么了珍特?”我有些...
    開封第一講書人閱讀 156,966評論 0 347
  • 文/不壞的土叔 我叫張陵祝峻,是天一觀的道長。 經(jīng)常有香客問我扎筒,道長莱找,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,432評論 1 283
  • 正文 為了忘掉前任嗜桌,我火速辦了婚禮奥溺,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘骨宠。我一直安慰自己浮定,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,519評論 6 385
  • 文/花漫 我一把揭開白布层亿。 她就那樣靜靜地躺著桦卒,像睡著了一般。 火紅的嫁衣襯著肌膚如雪匿又。 梳的紋絲不亂的頭發(fā)上方灾,一...
    開封第一講書人閱讀 49,792評論 1 290
  • 那天,我揣著相機(jī)與錄音琳省,去河邊找鬼迎吵。 笑死,一個胖子當(dāng)著我的面吹牛针贬,可吹牛的內(nèi)容都是我干的击费。 我是一名探鬼主播,決...
    沈念sama閱讀 38,933評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼桦他,長吁一口氣:“原來是場噩夢啊……” “哼蔫巩!你這毒婦竟也來了谆棱?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,701評論 0 266
  • 序言:老撾萬榮一對情侶失蹤圆仔,失蹤者是張志新(化名)和其女友劉穎垃瞧,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體坪郭,經(jīng)...
    沈念sama閱讀 44,143評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡个从,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,488評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了歪沃。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嗦锐。...
    茶點(diǎn)故事閱讀 38,626評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖沪曙,靈堂內(nèi)的尸體忽然破棺而出奕污,到底是詐尸還是另有隱情,我是刑警寧澤液走,帶...
    沈念sama閱讀 34,292評論 4 329
  • 正文 年R本政府宣布碳默,位于F島的核電站,受9級特大地震影響缘眶,放射性物質(zhì)發(fā)生泄漏嘱根。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,896評論 3 313
  • 文/蒙蒙 一磅崭、第九天 我趴在偏房一處隱蔽的房頂上張望儿子。 院中可真熱鬧,春花似錦砸喻、人聲如沸柔逼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽愉适。三九已至,卻和暖如春癣漆,著一層夾襖步出監(jiān)牢的瞬間维咸,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工惠爽, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留癌蓖,地道東北人。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓婚肆,卻偏偏與公主長得像租副,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子较性,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,494評論 2 348