Flutter 之 動(dòng)畫(huà)過(guò)渡組件(三十九)

在Widget屬性發(fā)生變化時(shí)會(huì)執(zhí)行過(guò)渡動(dòng)畫(huà)的組件統(tǒng)稱(chēng)為”動(dòng)畫(huà)過(guò)渡組件“

動(dòng)畫(huà)過(guò)渡組件最明顯的一個(gè)特征就是它會(huì)在內(nèi)部自管理AnimationController

我們知道兔毙,為了方便使用者可以自定義動(dòng)畫(huà)的曲線(xiàn)壮池、執(zhí)行時(shí)長(zhǎng)狠持、方向等匹摇,在前面介紹過(guò)的動(dòng)畫(huà)封裝方法中婆跑,通常都需要使用者自己提供一個(gè)AnimationController對(duì)象來(lái)自定義這些屬性值吧享。但是魏割,如此一來(lái),使用者就必須得手動(dòng)管理AnimationController钢颂,這又會(huì)增加使用的復(fù)雜性钞它。因此,如果也能將AnimationController進(jìn)行封裝殊鞭,則會(huì)大大提高動(dòng)畫(huà)組件的易用性遭垛。

1. Flutter預(yù)置的動(dòng)畫(huà)過(guò)渡組件

組件名 功能
AnimatedPadding 在padding發(fā)生變化時(shí)會(huì)執(zhí)行過(guò)渡動(dòng)畫(huà)到新?tīng)顟B(tài)
AnimatedPositioned 配合Stack一起使用,當(dāng)定位狀態(tài)發(fā)生變化時(shí)會(huì)執(zhí)行過(guò)渡動(dòng)畫(huà)到新的狀態(tài)操灿。
AnimatedOpacity 在透明度opacity發(fā)生變化時(shí)執(zhí)行過(guò)渡動(dòng)畫(huà)到新?tīng)顟B(tài)
AnimatedAlign 當(dāng)alignment發(fā)生變化時(shí)會(huì)執(zhí)行過(guò)渡動(dòng)畫(huà)到新的狀態(tài)锯仪。
AnimatedContainer 當(dāng)Container屬性發(fā)生變化時(shí)會(huì)執(zhí)行過(guò)渡動(dòng)畫(huà)到新的狀態(tài)。
AnimatedDefaultTextStyle 當(dāng)字體樣式發(fā)生變化時(shí)趾盐,子組件中繼承了該樣式的文本組件會(huì)動(dòng)態(tài)過(guò)渡到新樣式卵酪。

1.1 AnimatedPadding


class MSAnimatedPaddingDemo extends StatefulWidget {
  const MSAnimatedPaddingDemo({Key? key}) : super(key: key);

  @override
  State<MSAnimatedPaddingDemo> createState() => _MSAnimatedPaddingDemoState();
}

class _MSAnimatedPaddingDemoState extends State<MSAnimatedPaddingDemo> {
  double _padding = 10;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        alignment: Alignment.center,
        child: ElevatedButton(
          child: AnimatedPadding(
            padding: EdgeInsets.all(_padding),
            duration: Duration(milliseconds: 500),
            child: Text(
              "AnimatedPadding",
              textScaleFactor: 1.5,
            ),
          ),
          onPressed: () {
            setState(() {
              if (_padding == 20) {
                _padding = 10;
              } else {
                _padding = 20;
              }
            });
          },
        ),
      ),
    );
  }
}

61.gif

1.2 AnimatedPositioned


class MSAnimatedPositionedDemo extends StatefulWidget {
  const MSAnimatedPositionedDemo({Key? key}) : super(key: key);

  @override
  State<MSAnimatedPositionedDemo> createState() =>
      _MSAnimatedPositionedDemoState();
}

class _MSAnimatedPositionedDemoState extends State<MSAnimatedPositionedDemo> {
  double _posValue = 50;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: [
          AnimatedPositioned(
            duration: Duration(milliseconds: 500),
            top: _posValue,
            child: ElevatedButton(
                onPressed: () {
                  setState(() {
                    if (_posValue == 100) {
                      _posValue = 50;
                    } else {
                      _posValue = 100;
                    }
                  });
                },
                child: Text(
                  "AnimatedPositioned",
                  textScaleFactor: 1.5,
                )),
          ),
        ],
      ),
    );
  }
}

62.gif

1.3 AnimatedOpacity


class MSAnimatedOpacityDemo extends StatefulWidget {
  const MSAnimatedOpacityDemo({Key? key}) : super(key: key);

  @override
  State<MSAnimatedOpacityDemo> createState() => _MSAnimatedOpacityDemoState();
}

class _MSAnimatedOpacityDemoState extends State<MSAnimatedOpacityDemo> {
  double _opacity = 0.5;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: ElevatedButton(
          child: AnimatedOpacity(
            opacity: _opacity,
            duration: Duration(milliseconds: 500),
            child: Text(
              "AnimatedOpacity",
              textScaleFactor: 1.5,
            ),
          ),
          onPressed: () {
            setState(() {
              if (_opacity == 0.5) {
                _opacity = 0.8;
              } else {
                _opacity = 0.5;
              }
            });
          },
        ),
      ),
    );
  }
}

63.gif

1.4 AnimatedAlign


class MSAnimatedAlignDemo extends StatefulWidget {
  const MSAnimatedAlignDemo({Key? key}) : super(key: key);

  @override
  State<MSAnimatedAlignDemo> createState() => _MSAnimatedAlignDemoState();
}

class _MSAnimatedAlignDemoState extends State<MSAnimatedAlignDemo> {
  double _alignmentValue = 0;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: AnimatedAlign(
          duration: Duration(milliseconds: 500),
          alignment: Alignment(_alignmentValue, _alignmentValue),
          child: ElevatedButton(
            child: Text(
              "AnimatedAlign",
              textScaleFactor: 1.5,
            ),
            onPressed: () {
              setState(() {
                if (_alignmentValue == 0) {
                  _alignmentValue = 0.8;
                } else {
                  _alignmentValue = 0;
                }
              });
            },
          ),
        ),
      ),
    );
  }
}

64.gif

5.5 AnimatedContainer


class MSAnimatedContainerDemo extends StatefulWidget {
  const MSAnimatedContainerDemo({Key? key}) : super(key: key);

  @override
  State<MSAnimatedContainerDemo> createState() =>
      _MSAnimatedContainerDemoState();
}

class _MSAnimatedContainerDemoState extends State<MSAnimatedContainerDemo> {
  double _sizeValue = 200;
  double _paddingValue = 0;
  double _alignmentValue = 0;
  Color _bgColor = Colors.red;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: AnimatedContainer(
          duration: Duration(milliseconds: 500),
          color: _bgColor,
          width: _sizeValue,
          height: _sizeValue,
          alignment: Alignment(_alignmentValue, _alignmentValue),
          padding: EdgeInsets.all(_paddingValue),
          child: ElevatedButton(
            child: Text("AnimatedContainer"),
            onPressed: () {
              setState(() {
                _sizeValue = _sizeValue == 200 ? 350 : 200;
                _paddingValue = _paddingValue == 0 ? 20 : 0;
                _alignmentValue = _alignmentValue == 0 ? -1 : 0;
                _bgColor = _bgColor == Colors.red ? Colors.yellow : Colors.red;
              });
            },
          ),
        ),
      ),
    );
  }
}

66.gif

5.6 AnimatedDefaultTextStyle


class MSAnimatedDefaultTextStyleDemo extends StatefulWidget {
  const MSAnimatedDefaultTextStyleDemo({Key? key}) : super(key: key);

  @override
  State<MSAnimatedDefaultTextStyleDemo> createState() =>
      _MSAnimatedDefaultTextStyleDemoState();
}

class _MSAnimatedDefaultTextStyleDemoState
    extends State<MSAnimatedDefaultTextStyleDemo> {
  TextStyle _textStyle =
      TextStyle(fontSize: 20, fontWeight: FontWeight.w300, color: Colors.amber);
  bool isflag = false;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: GestureDetector(
          child: AnimatedDefaultTextStyle(
            duration: Duration(milliseconds: 500),
            style: _textStyle,
            child: Text("AnimatedDefaultTextStyle"),
          ),
          onTap: () {
            setState(() {
              if (isflag) {
                _textStyle = TextStyle(
                  fontSize: 25,
                  fontWeight: FontWeight.w700,
                  color: Colors.red,
                );
                isflag = false;
              } else {
                _textStyle = TextStyle(
                  fontSize: 20,
                  fontWeight: FontWeight.w300,
                  color: Colors.amber,
                );
                isflag = true;
              }
            });
          },
        ),
      ),
    );
  }
}

65.gif

2. 自定義動(dòng)畫(huà)過(guò)渡組件

要實(shí)現(xiàn)一個(gè)AnimatedDecoratedBox,它可以在decoration屬性發(fā)生變化時(shí)谤碳,從舊狀態(tài)變成新?tīng)顟B(tài)的過(guò)程可以執(zhí)行一個(gè)過(guò)渡動(dòng)畫(huà)

MSAnimatedDecoratedBox


// MSAnimatedDecoratedBox
class MSAnimatedDecoratedBox extends StatefulWidget {
  const MSAnimatedDecoratedBox(
      {Key? key,
      required this.decoration,
      required this.child,
      required this.duration,
      required this.curve,
      this.reverseDuration})
      : super(key: key);
  final BoxDecoration decoration;
  final Widget child;
  final Duration duration;
  final Curve curve;
  final Duration? reverseDuration;

  @override
  State<MSAnimatedDecoratedBox> createState() => _MSAnimatedDecoratedBoxState();
}

class _MSAnimatedDecoratedBoxState extends State<MSAnimatedDecoratedBox>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _animation;
  late DecorationTween _tween;

  @override
  void initState() {
    _controller = AnimationController(
      vsync: this,
      duration: widget.duration,
      reverseDuration: widget.reverseDuration,
    );
    _tween = DecorationTween(begin: widget.decoration);
    _updateCurve();
    super.initState();
  }

  void _updateCurve() {
    _animation = CurvedAnimation(parent: _controller, curve: widget.curve);
  }

  @override
  void didUpdateWidget(covariant MSAnimatedDecoratedBox oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (widget.curve != oldWidget.curve) {
      _updateCurve();
    }

    _controller.duration = widget.duration;
    _controller.reverseDuration = widget.reverseDuration;

    if (widget.decoration != (_tween.end ?? _tween.begin)) {
      _tween
        ..begin = _tween.evaluate(_animation)
        ..end = widget.decoration;
      _controller
        ..value = 0.0
        ..forward();
    }
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _animation,
      builder: (ctx, child) {
        return DecoratedBox(
            decoration: _tween.animate(_animation).value, child: child);
      },
      child: widget.child,
    );
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
}

使用MSAnimatedDecoratedBox來(lái)實(shí)現(xiàn)按鈕點(diǎn)擊后背景色從藍(lán)色過(guò)渡到紅色的效果

...
MSAnimatedDecoratedBox(
  child: TextButton(
    child: Text(
      "AnimatedBecoratedBox",
      textScaleFactor: 1.5,
    ),
    onPressed: () {
      setState(() {
        _decorationColor =
            _decorationColor == Colors.red ? Colors.amber : Colors.red;
      });
    },
  ),
  decoration: BoxDecoration(color: _decorationColor),
  duration: Duration(milliseconds: 500),
  curve: Curves.linear,
),
...

完整代碼


// MSAnimatedBecoratedBoxDemo
class MSAnimatedBecoratedBoxDemo extends StatefulWidget {
  const MSAnimatedBecoratedBoxDemo({Key? key}) : super(key: key);

  @override
  State<MSAnimatedBecoratedBoxDemo> createState() =>
      _MSAnimatedBecoratedBoxDemoState();
}

class _MSAnimatedBecoratedBoxDemoState
    extends State<MSAnimatedBecoratedBoxDemo> {
  bool isflag = false;
  var _decorationColor = Colors.blue;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: MSAnimatedDecoratedBox(
          child: TextButton(
            child: Text(
              "AnimatedBecoratedBox",
              textScaleFactor: 1.5,
              style: TextStyle(color: Colors.white),
            ),
            onPressed: () {
              setState(() {
                _decorationColor = isflag ? Colors.blue : Colors.red;
                isflag = !isflag;
              });
            },
          ),
          decoration: BoxDecoration(color: _decorationColor),
          duration: Duration(seconds: 2),
          curve: Curves.linear,
        ),
      ),
    );
  }
}

// MSAnimatedDecoratedBox
class MSAnimatedDecoratedBox extends StatefulWidget {
  const MSAnimatedDecoratedBox(
      {Key? key,
      required this.decoration,
      required this.child,
      required this.duration,
      required this.curve,
      this.reverseDuration})
      : super(key: key);
  final BoxDecoration decoration;
  final Widget child;
  final Duration duration;
  final Curve curve;
  final Duration? reverseDuration;

  @override
  State<MSAnimatedDecoratedBox> createState() => _MSAnimatedDecoratedBoxState();
}

class _MSAnimatedDecoratedBoxState extends State<MSAnimatedDecoratedBox>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _animation;
  late DecorationTween _tween;

  @override
  void initState() {
    _controller = AnimationController(
      vsync: this,
      duration: widget.duration,
      reverseDuration: widget.reverseDuration,
    );
    _tween = DecorationTween(begin: widget.decoration);
    _updateCurve();
    super.initState();
  }

  void _updateCurve() {
    _animation = CurvedAnimation(parent: _controller, curve: widget.curve);
  }

  @override
  void didUpdateWidget(covariant MSAnimatedDecoratedBox oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (widget.curve != oldWidget.curve) {
      _updateCurve();
    }

    _controller.duration = widget.duration;
    _controller.reverseDuration = widget.reverseDuration;

    if (widget.decoration != (_tween.end ?? _tween.begin)) {
      _tween
        ..begin = _tween.evaluate(_animation)
        ..end = widget.decoration;
      _controller
        ..value = 0.0
        ..forward();
    }
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _animation,
      builder: (ctx, child) {
        return DecoratedBox(
            decoration: _tween.animate(_animation).value, child: child);
      },
      child: widget.child,
    );
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
}


68.gif

上面的代碼雖然實(shí)現(xiàn)了我們期望的功能溃卡,但是代碼卻比較復(fù)雜。稍加思考后蜒简,我們就可以發(fā)現(xiàn)瘸羡,AnimationController的管理以及Tween更新部分的代碼都是可以抽象出來(lái)的,如果我們這些通用邏輯封裝成基類(lèi)搓茬,那么要實(shí)現(xiàn)動(dòng)畫(huà)過(guò)渡組件只需要繼承這些基類(lèi)犹赖,然后定制自身不同的代碼(比如動(dòng)畫(huà)每一幀的構(gòu)建方法)即可队他,這樣將會(huì)簡(jiǎn)化代碼。

為了方便開(kāi)發(fā)者來(lái)實(shí)現(xiàn)動(dòng)畫(huà)過(guò)渡組件的封裝峻村,F(xiàn)lutter提供了一個(gè)ImplicitlyAnimatedWidget抽象類(lèi)麸折,它繼承自StatefulWidget,同時(shí)提供了一個(gè)對(duì)應(yīng)的ImplicitlyAnimatedWidgetState類(lèi)粘昨,AnimationController的管理就在ImplicitlyAnimatedWidgetState類(lèi)中垢啼。開(kāi)發(fā)者如果要封裝動(dòng)畫(huà),只需要分別繼承ImplicitlyAnimatedWidget和ImplicitlyAnimatedWidgetState類(lèi)即可

需要分兩步實(shí)現(xiàn):
1.繼承ImplicitlyAnimatedWidget類(lèi)张肾。

class AnimatedDecoratedBox extends ImplicitlyAnimatedWidget {
  const AnimatedDecoratedBox({
    Key? key,
    required this.decoration,
    required this.child,
    Curve curve = Curves.linear,
    required Duration duration,
  }) : super(
          key: key,
          curve: curve,
          duration: duration,
        );
  final BoxDecoration decoration;
  final Widget child;

  @override
  _AnimatedDecoratedBoxState createState() {
    return _AnimatedDecoratedBoxState();
  }
}

其中curve芭析、duration、reverseDuration三個(gè)屬性在ImplicitlyAnimatedWidget中已定義吞瞪。 可以看到AnimatedDecoratedBox類(lèi)和普通繼承自StatefulWidget的類(lèi)沒(méi)有什么不同馁启。

  1. State類(lèi)繼承自AnimatedWidgetBaseState(該類(lèi)繼承自ImplicitlyAnimatedWidgetState類(lèi))。
class _AnimatedDecoratedBoxState
    extends AnimatedWidgetBaseState<AnimatedDecoratedBox> {
  late DecorationTween _decoration;

  @override
  Widget build(BuildContext context) {
    return DecoratedBox(
      decoration: _decoration.evaluate(animation),
      child: widget.child,
    );
  }

  @override
  void forEachTween(TweenVisitor<dynamic> visitor) {
    _decoration = visitor(
      _decoration,
      widget.decoration,
      (value) => DecorationTween(begin: value),
    ) as DecorationTween;
  }
}

可以看到我們實(shí)現(xiàn)了build和forEachTween兩個(gè)方法芍秆。在動(dòng)畫(huà)執(zhí)行過(guò)程中惯疙,每一幀都會(huì)調(diào)用build方法(調(diào)用邏輯在ImplicitlyAnimatedWidgetState中),所以在build方法中我們需要構(gòu)建每一幀的DecoratedBox狀態(tài)妖啥,因此得算出每一幀的decoration 狀態(tài)螟碎,這個(gè)我們可以通過(guò)_decoration.evaluate(animation) 來(lái)算出,其中animation是ImplicitlyAnimatedWidgetState基類(lèi)中定義的對(duì)象迹栓,_decoration是我們自定義的一個(gè)DecorationTween類(lèi)型的對(duì)象。

那么現(xiàn)在的問(wèn)題就是它是在什么時(shí)候被賦值的呢俭缓?要回答這個(gè)問(wèn)題克伊,我們就得搞清楚什么時(shí)候需要對(duì)_decoration賦值。我們知道_decoration是一個(gè)Tween华坦,而Tween的主要職責(zé)就是定義動(dòng)畫(huà)的起始狀態(tài)(begin)和終止?fàn)顟B(tài)(end)愿吹。對(duì)于AnimatedDecoratedBox來(lái)說(shuō),decoration的終止?fàn)顟B(tài)就是用戶(hù)傳給它的值惜姐,而起始狀態(tài)是不確定的犁跪,有以下兩種情況:

  • AnimatedDecoratedBox首次build,此時(shí)直接將其decoration值置為起始狀態(tài)歹袁,即_decoration值為DecorationTween(begin: decoration) 坷衍。
  • AnimatedDecoratedBox的decoration更新時(shí),則起始狀態(tài)為_(kāi)decoration.animate(animation)条舔,即_decoration值為DecorationTween(begin: _decoration.animate(animation)枫耳,end:decoration)。

現(xiàn)在forEachTween的作用就很明顯了孟抗,它正是用于來(lái)更新Tween的初始值的迁杨,在上述兩種情況下會(huì)被調(diào)用钻心,而開(kāi)發(fā)者只需重寫(xiě)此方法,并在此方法中更新Tween的起始狀態(tài)值即可铅协。而一些更新的邏輯被屏蔽在了visitor回調(diào)捷沸,我們只需要調(diào)用它并給它傳遞正確的參數(shù)即可,visitor方法簽名如下

 Tween<T> visitor(
   Tween<T> tween, //當(dāng)前的tween狐史,第一次調(diào)用為null
   T targetValue, // 終止?fàn)顟B(tài)
   TweenConstructor<T> constructor痒给,//Tween構(gòu)造器,在上述三種情況下會(huì)被調(diào)用以更新tween
 );

可以看到预皇,通過(guò)繼承ImplicitlyAnimatedWidget和ImplicitlyAnimatedWidgetState類(lèi)可以快速的實(shí)現(xiàn)動(dòng)畫(huà)過(guò)渡組件的封裝侈玄,這和我們純手工實(shí)現(xiàn)相比,代碼簡(jiǎn)化了很多

https://book.flutterchina.club/chapter9/animated_widgets.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末吟温,一起剝皮案震驚了整個(gè)濱河市序仙,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌鲁豪,老刑警劉巖潘悼,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異爬橡,居然都是意外死亡治唤,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)糙申,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)宾添,“玉大人,你說(shuō)我怎么就攤上這事柜裸÷粕拢” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵疙挺,是天一觀的道長(zhǎng)扛邑。 經(jīng)常有香客問(wèn)我,道長(zhǎng)铐然,這世上最難降的妖魔是什么蔬崩? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮搀暑,結(jié)果婚禮上沥阳,老公的妹妹穿的比我還像新娘。我一直安慰自己自点,他們只是感情好沪袭,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般冈绊。 火紅的嫁衣襯著肌膚如雪侠鳄。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,541評(píng)論 1 305
  • 那天死宣,我揣著相機(jī)與錄音伟恶,去河邊找鬼。 笑死毅该,一個(gè)胖子當(dāng)著我的面吹牛博秫,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播眶掌,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼挡育,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了朴爬?” 一聲冷哼從身側(cè)響起即寒,我...
    開(kāi)封第一講書(shū)人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎召噩,沒(méi)想到半個(gè)月后母赵,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡具滴,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年凹嘲,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片构韵。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡周蹭,死狀恐怖罢浇,靈堂內(nèi)的尸體忽然破棺而出痹兜,到底是詐尸還是另有隱情饰剥,我是刑警寧澤葡公,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布,位于F島的核電站呢簸,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜萎攒,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望矛绘。 院中可真熱鬧耍休,春花似錦、人聲如沸货矮。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)囚玫。三九已至喧锦,卻和暖如春读规,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背燃少。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工束亏, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人阵具。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓碍遍,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親阳液。 傳聞我的和親對(duì)象是個(gè)殘疾皇子怕敬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355

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