flutter 自定义高度,圆角,间距的CupertinoSegmentedControl

更改系统源码后的新增了自定义高度和圆角

源码默认圆角为5,高度为28,构造方法里面没有这些参数

下图是更改为圆角20,高度50,padding没有用,自己添加margin为10的状态

image.png

1.复制下面的代码到一个新的dart文件当中


// Copyright 2014 The Flutter Authors. All rights reserved.

// Use of this source code is governed by a BSD-style license that can be

// found in the LICENSE file.

// @dart = 2.8

import 'dart:collection';

import 'dart:math' as math;

import 'package:flutter/cupertino.dart';

import 'package:flutter/foundation.dart';

import 'package:flutter/rendering.dart';

import 'package:flutter/widgets.dart';

import 'package:people_manager/config/net_config/api.dart';

// Minimum padding from edges of the segmented control to edges of

// encompassing widget.

const EdgeInsetsGeometry _kHorizontalItemPadding =

EdgeInsets.symmetric(horizontal:30.0);

// Minimum height of the segmented control.

// const double _kMinSegmentedControlHeight = 40.0;

// The duration of the fade animation used to transition when a new widget

// is selected.

const Duration _kFadeDuration =Duration(milliseconds:165);

/// An iOS-style segmented control.

///

/// Displays the widgets provided in the [Map] of [children] in a

/// horizontal list. Used to select between a number of mutually exclusive

/// options. When one option in the segmented control is selected, the other

/// options in the segmented control cease to be selected.

///

/// A segmented control can feature any [Widget] as one of the values in its

/// [Map] of [children]. The type T is the type of the keys used

/// to identify each widget and determine which widget is selected. As

/// required by the [Map] class, keys must be of consistent types

/// and must be comparable. The ordering of the keys will determine the order

/// of the widgets in the segmented control.

///

/// When the state of the segmented control changes, the widget calls the

/// [onValueChanged] callback. The map key associated with the newly selected

/// widget is returned in the [onValueChanged] callback. Typically, widgets

/// that use a segmented control will listen for the [onValueChanged] callback

/// and rebuild the segmented control with a new [groupValue] to update which

/// option is currently selected.

///

/// The [children] will be displayed in the order of the keys in the [Map].

/// The height of the segmented control is determined by the height of the

/// tallest widget provided as a value in the [Map] of [children].

/// The width of each child in the segmented control will be equal to the width

/// of widest child, unless the combined width of the children is wider than

/// the available horizontal space. In this case, the available horizontal space

/// is divided by the number of provided [children] to determine the width of

/// each widget. The selection area for each of the widgets in the [Map] of

/// [children] will then be expanded to fill the calculated space, so each

/// widget will appear to have the same dimensions.

///

/// A segmented control may optionally be created with custom colors. The

/// [unselectedColor], [selectedColor], [borderColor], and [pressedColor]

/// arguments can be used to override the segmented control's colors from

/// [CupertinoTheme] defaults.

///

/// See also:

///

///  * [CupertinoSegmentedControl], a segmented control widget in the style used

///    up until iOS 13.

///  *

class CupertinoSegmentedControlextends StatefulWidget {

/// Creates an iOS-style segmented control bar.

///

  /// The [children] and [onValueChanged] arguments must not be null. The

  /// [children] argument must be an ordered [Map] such as a [LinkedHashMap].

  /// Further, the length of the [children] list must be greater than one.

///

  /// Each widget value in the map of [children] must have an associated key

/// that uniquely identifies this widget. This key is what will be returned

  /// in the [onValueChanged] callback when a new value from the [children] map

/// is selected.

///

  /// The [groupValue] is the currently selected value for the segmented control.

  /// If no [groupValue] is provided, or the [groupValue] is null, no widget will

  /// appear as selected. The [groupValue] must be either null or one of the keys

  /// in the [children] map.

  CupertinoSegmentedControl({

Key key,

    @required this.children,

    @required this.onValueChanged,

    this.groupValue,

    this.unselectedColor,

    this.selectedColor,

    this.borderColor,

    this.radius =5,

    this.kMinSegmentedControlHeight = 30,

    this.pressedColor,

    this.padding,

  })  :assert(children !=null),

        assert(children.length >=2),

        assert(onValueChanged !=null),

        assert(

groupValue ==null ||

children.keys.any((T child) => child == groupValue),

          'The groupValue must be either null or one of the keys in the children map.',

        ),

        super(key: key);

  /// The identifying keys and corresponding widget values in the

/// segmented control.

///

/// The map must have more than one entry.

/// This attribute must be an ordered [Map] such as a [LinkedHashMap].

  final Mapchildren;

  /// The identifier of the widget that is currently selected.

///

  /// This must be one of the keys in the [Map] of [children].

/// If this attribute is null, no widget will be initially selected.

  final TgroupValue;

  /// The callback that is called when a new option is tapped.

///

/// This attribute must not be null.

///

/// The segmented control passes the newly selected widget's associated key

/// to the callback but does not actually change state until the parent

  /// widget rebuilds the segmented control with the new [groupValue].

///

  /// The callback provided to [onValueChanged] should update the state of

/// the parent [StatefulWidget] using the [State.setState] method, so that

/// the parent gets rebuilt; for example:

///

/// {@tool snippet}

///

/// ```dart

/// class SegmentedControlExample extends StatefulWidget {

///  @override

///  State createState() => SegmentedControlExampleState();

/// }

///

/// class SegmentedControlExampleState extends State {

///  final Map children = const {

///    0: Text('Child 1'),

///    1: Text('Child 2'),

///  };

///

///  int currentValue;

///

///  @override

///  Widget build(BuildContext context) {

///    return Container(

///      child: CupertinoSegmentedControl(

///        children: children,

///        onValueChanged: (int newValue) {

///          setState(() {

///            currentValue = newValue;

///          });

///        },

///        groupValue: currentValue,

///      ),

///    );

///  }

/// }

/// ```

/// {@end-tool}

  final ValueChangedonValueChanged;

  /// The color used to fill the backgrounds of unselected widgets and as the

/// text color of the selected widget.

///

/// Defaults to [CupertinoTheme]'s `primaryContrastingColor` if null.

  final ColorunselectedColor;

  /// The color used to fill the background of the selected widget and as the text

/// color of unselected widgets.

///

/// Defaults to [CupertinoTheme]'s `primaryColor` if null.

  final ColorselectedColor;

  /// The color used as the border around each widget.

///

/// Defaults to [CupertinoTheme]'s `primaryColor` if null.

  final ColorborderColor;

  /// The color used to fill the background of the widget the user is

/// temporarily interacting with through a long press or drag.

///

/// Defaults to the selectedColor at 20% opacity if null.

  final ColorpressedColor;

  /// The CupertinoSegmentedControl will be placed inside this padding.

///

/// Defaults to EdgeInsets.symmetric(horizontal: 16.0)

  final EdgeInsetsGeometrypadding;

  final doubleradius;

  final doublekMinSegmentedControlHeight;

  @override

  _SegmentedControlStatecreateState() =>_SegmentedControlState();

}

class _SegmentedControlStateextends State>

with TickerProviderStateMixin> {

T_pressedKey;

  final List_selectionControllers =

[];

  final List_childTweens = [];

  ColorTween_forwardBackgroundColorTween;

  ColorTween_reverseBackgroundColorTween;

  ColorTween_textColorTween;

  Color_selectedColor;

  Color_unselectedColor;

  Color_borderColor;

  double_radius;

  Color_pressedColor;

  double_kMinSegmentedControlHeight;

  AnimationControllercreateAnimationController() {

return AnimationController(

duration: _kFadeDuration,

      vsync:this,

    )..addListener(() {

setState(() {

// State of background/text colors has changed

        });

      });

  }

bool_updateColors() {

assert(mounted, 'This should only be called after didUpdateDependencies');

    bool changed =false;

    final Color selectedColor =

widget.selectedColor ?? CupertinoTheme.of(context).primaryColor;

    if (_selectedColor != selectedColor) {

changed =true;

      _selectedColor = selectedColor;

    }

final Color unselectedColor =widget.unselectedColor ??

CupertinoTheme.of(context).primaryContrastingColor;

    if (_unselectedColor != unselectedColor) {

changed =true;

      _unselectedColor = unselectedColor;

    }

final Color borderColor =

widget.borderColor ?? CupertinoTheme.of(context).primaryColor;

    if (_borderColor != borderColor) {

changed =true;

      _borderColor = borderColor;

    }

_radius =widget.radius;

    _kMinSegmentedControlHeight =widget.kMinSegmentedControlHeight;

    final Color pressedColor =widget.pressedColor ??

CupertinoTheme.of(context).primaryColor.withOpacity(0.2);

    if (_pressedColor != pressedColor) {

changed =true;

      _pressedColor = pressedColor;

    }

_forwardBackgroundColorTween =ColorTween(

begin:_pressedColor,

      end:_selectedColor,

    );

    _reverseBackgroundColorTween =ColorTween(

begin:_unselectedColor,

      end:_selectedColor,

    );

    _textColorTween =ColorTween(

begin:_selectedColor,

      end:_unselectedColor,

    );

    return changed;

  }

void _updateAnimationControllers() {

assert(mounted, 'This should only be called after didUpdateDependencies');

    for (final AnimationController controllerin _selectionControllers) {

controller.dispose();

    }

_selectionControllers.clear();

    _childTweens.clear();

    for (final T keyin widget.children.keys) {

final AnimationController animationController =

createAnimationController();

      if (widget.groupValue == key) {

_childTweens.add(_reverseBackgroundColorTween);

        animationController.value =1.0;

      }else {

_childTweens.add(_forwardBackgroundColorTween);

      }

_selectionControllers.add(animationController);

    }

}

@override

  void didChangeDependencies() {

super.didChangeDependencies();

    if (_updateColors()) {

_updateAnimationControllers();

    }

}

@override

  void didUpdateWidget(CupertinoSegmentedControl oldWidget) {

super.didUpdateWidget(oldWidget);

    if (_updateColors() ||

oldWidget.children.length !=widget.children.length) {

_updateAnimationControllers();

    }

if (oldWidget.groupValue !=widget.groupValue) {

int index =0;

      for (final T keyin widget.children.keys) {

if (widget.groupValue == key) {

_childTweens[index] =_forwardBackgroundColorTween;

          _selectionControllers[index].forward();

        }else {

_childTweens[index] =_reverseBackgroundColorTween;

          _selectionControllers[index].reverse();

        }

index +=1;

      }

}

}

@override

  void dispose() {

for (final AnimationController animationController

in _selectionControllers) {

animationController.dispose();

    }

super.dispose();

  }

void _onTapDown(T currentKey) {

if (_pressedKey ==null && currentKey !=widget.groupValue) {

setState(() {

_pressedKey = currentKey;

      });

    }

}

void _onTapCancel() {

setState(() {

_pressedKey =null;

    });

  }

void _onTap(T currentKey) {

if (currentKey !=_pressedKey)return;

    if (currentKey !=widget.groupValue) {

widget.onValueChanged(currentKey);

    }

_pressedKey =null;

  }

ColorgetTextColor(int index, T currentKey) {

if (_selectionControllers[index].isAnimating)

return _textColorTween.evaluate(_selectionControllers[index]);

    if (widget.groupValue == currentKey)return _unselectedColor;

    return _selectedColor;

  }

ColorgetBackgroundColor(int index, T currentKey) {

if (_selectionControllers[index].isAnimating)

return _childTweens[index].evaluate(_selectionControllers[index]);

    if (widget.groupValue == currentKey)return _selectedColor;

    if (_pressedKey == currentKey)return _pressedColor;

    return _unselectedColor;

  }

@override

  Widgetbuild(BuildContext context) {

final List _gestureChildren = [];

    final List _backgroundColors = [];

    int index =0;

    int selectedIndex;

    int pressedIndex;

    for (final T currentKeyin widget.children.keys) {

selectedIndex = (widget.groupValue == currentKey) ? index : selectedIndex;

      pressedIndex = (_pressedKey == currentKey) ? index : pressedIndex;

      final TextStyle textStyle = DefaultTextStyle.of(context).style.copyWith(

color: getTextColor(index, currentKey),

          );

      final IconThemeData iconTheme =IconThemeData(

color: getTextColor(index, currentKey),

      );

      Widget child =Center(

child:widget.children[currentKey],

      );

      child =GestureDetector(

behavior: HitTestBehavior.opaque,

        onTapDown: (TapDownDetails event) {

_onTapDown(currentKey);

        },

        onTapCancel: _onTapCancel,

        onTap: () {

_onTap(currentKey);

        },

        child:IconTheme(

data: iconTheme,

          child:DefaultTextStyle(

style: textStyle,

            child:Semantics(

button:true,

              inMutuallyExclusiveGroup:true,

              selected:widget.groupValue == currentKey,

              child: child,

            ),

          ),

        ),

      );

      _backgroundColors.add(getBackgroundColor(index, currentKey));

      _gestureChildren.add(child);

      index +=1;

    }

final Widget box =_SegmentedControlRenderWidget(

children: _gestureChildren,

        selectedIndex: selectedIndex,

        pressedIndex: pressedIndex,

        backgroundColors: _backgroundColors,

        borderColor:_borderColor,

        radius:_radius,

        kMinSegmentedControlHeight:_kMinSegmentedControlHeight);

    return Padding(

padding:widget.padding ?? _kHorizontalItemPadding,

      child:UnconstrainedBox(

constrainedAxis: Axis.horizontal,

        child: box,

      ),

    );

  }

}

class _SegmentedControlRenderWidgetextends MultiChildRenderObjectWidget {

_SegmentedControlRenderWidget(

{Key key,

      List children =const [],

      @required this.selectedIndex,

      @required this.pressedIndex,

      @required this.backgroundColors,

      @required this.borderColor,

      @required this.radius,

      @required this.kMinSegmentedControlHeight})

:super(

key: key,

          children: children,

        );

  final intselectedIndex;

  final intpressedIndex;

  final ListbackgroundColors;

  final ColorborderColor;

  final doubleradius;

  final doublekMinSegmentedControlHeight;

  @override

  RenderObjectcreateRenderObject(BuildContext context) {

return _RenderSegmentedControl(

textDirection: Directionality.of(context),

        selectedIndex:selectedIndex,

        pressedIndex:pressedIndex,

        backgroundColors:backgroundColors,

        borderColor:borderColor,

        radius:radius,

        kMinSegmentedControlHeight:kMinSegmentedControlHeight);

  }

@override

  void updateRenderObject(

BuildContext context, _RenderSegmentedControl renderObject) {

renderObject

..textDirection = Directionality.of(context)

..selectedIndex =selectedIndex

      ..pressedIndex =pressedIndex

      ..backgroundColors =backgroundColors

      ..borderColor =borderColor;

  }

}

class _SegmentedControlContainerBoxParentData

extends ContainerBoxParentData {

RRectsurroundingRect;

}

typedef _NextChild = RenderBox Function(RenderBox child);

class _RenderSegmentedControlextends RenderBox

with

        ContainerRenderObjectMixin

            ContainerBoxParentData>,

        RenderBoxContainerDefaultsMixin

            ContainerBoxParentData> {

_RenderSegmentedControl({

@required int selectedIndex,

    @required int pressedIndex,

    @required TextDirection textDirection,

    @required List backgroundColors,

    @required Color borderColor,

    @required double radius,

    @required double kMinSegmentedControlHeight,

  })  :assert(textDirection !=null),

        _textDirection = textDirection,

        _selectedIndex = selectedIndex,

        _pressedIndex = pressedIndex,

        _backgroundColors = backgroundColors,

        _borderColor = borderColor,

        _radius = radius,

        _kMinSegmentedControlHeight = kMinSegmentedControlHeight;

  intget selectedIndex =>_selectedIndex;

  int_selectedIndex;

  set selectedIndex(int value) {

if (_selectedIndex == value) {

return;

    }

_selectedIndex = value;

    markNeedsPaint();

  }

intget pressedIndex =>_pressedIndex;

  int_pressedIndex;

  set pressedIndex(int value) {

if (_pressedIndex == value) {

return;

    }

_pressedIndex = value;

    markNeedsPaint();

  }

TextDirectionget textDirection =>_textDirection;

  TextDirection_textDirection;

  set textDirection(TextDirection value) {

if (_textDirection == value) {

return;

    }

_textDirection = value;

    markNeedsLayout();

  }

Listget backgroundColors =>_backgroundColors;

  List_backgroundColors;

  set backgroundColors(List value) {

if (_backgroundColors == value) {

return;

    }

_backgroundColors = value;

    markNeedsPaint();

  }

Colorget borderColor =>_borderColor;

  Color_borderColor;

  set borderColor(Color value) {

if (_borderColor == value) {

return;

    }

_borderColor = value;

    markNeedsPaint();

  }

doubleget radius =>_radius;

  double_radius;

  set radius(double value) {

if (_radius == value) {

return;

    }

_radius = value;

    markNeedsPaint();

  }

doubleget kMinSegmentedControlHeight =>_kMinSegmentedControlHeight;

  double_kMinSegmentedControlHeight;

  set kMinSegmentedControlHeight(double value) {

if (_kMinSegmentedControlHeight == value) {

return;

    }

_kMinSegmentedControlHeight = value;

    markNeedsPaint();

  }

@override

  doublecomputeMinIntrinsicWidth(double height) {

RenderBox child =firstChild;

    double minWidth =0.0;

    while (child !=null) {

final _SegmentedControlContainerBoxParentData childParentData =

child.parentData as _SegmentedControlContainerBoxParentData;

      final double childWidth = child.getMinIntrinsicWidth(height);

      minWidth = math.max(minWidth, childWidth);

      child = childParentData.nextSibling;

    }

return minWidth *childCount;

  }

@override

  doublecomputeMaxIntrinsicWidth(double height) {

RenderBox child =firstChild;

    double maxWidth =0.0;

    while (child !=null) {

final _SegmentedControlContainerBoxParentData childParentData =

child.parentData as _SegmentedControlContainerBoxParentData;

      final double childWidth = child.getMaxIntrinsicWidth(height);

      maxWidth = math.max(maxWidth, childWidth);

      child = childParentData.nextSibling;

    }

return maxWidth *childCount;

  }

@override

  doublecomputeMinIntrinsicHeight(double width) {

RenderBox child =firstChild;

    double minHeight =0.0;

    while (child !=null) {

final _SegmentedControlContainerBoxParentData childParentData =

child.parentData as _SegmentedControlContainerBoxParentData;

      final double childHeight = child.getMinIntrinsicHeight(width);

      minHeight = math.max(minHeight, childHeight);

      child = childParentData.nextSibling;

    }

return minHeight;

  }

@override

  doublecomputeMaxIntrinsicHeight(double width) {

RenderBox child =firstChild;

    double maxHeight =0.0;

    while (child !=null) {

final _SegmentedControlContainerBoxParentData childParentData =

child.parentData as _SegmentedControlContainerBoxParentData;

      final double childHeight = child.getMaxIntrinsicHeight(width);

      maxHeight = math.max(maxHeight, childHeight);

      child = childParentData.nextSibling;

    }

return maxHeight;

  }

@override

  doublecomputeDistanceToActualBaseline(TextBaseline baseline) {

return defaultComputeDistanceToHighestActualBaseline(baseline);

  }

@override

  void setupParentData(RenderBox child) {

if (child.parentData is! _SegmentedControlContainerBoxParentData) {

child.parentData =_SegmentedControlContainerBoxParentData();

    }

}

void _layoutRects(

_NextChild nextChild, RenderBox leftChild, RenderBox rightChild) {

RenderBox child = leftChild;

    double start =0.0;

    while (child !=null) {

final _SegmentedControlContainerBoxParentData childParentData =

child.parentData as _SegmentedControlContainerBoxParentData;

      final Offset childOffset =Offset(start, 0.0);

      childParentData.offset = childOffset;

      final Rect childRect =

Rect.fromLTWH(start, 0.0, child.size.width, child.size.height);

      RRect rChildRect;

      if (child == leftChild) {

rChildRect =RRect.fromRectAndCorners(childRect,

            topLeft:Radius.circular(radius),

            bottomLeft:Radius.circular(radius));

      }else if (child == rightChild) {

rChildRect =RRect.fromRectAndCorners(childRect,

            topRight:Radius.circular(radius),

            bottomRight:Radius.circular(radius));

      }else {

rChildRect =RRect.fromRectAndCorners(childRect);

      }

childParentData.surroundingRect = rChildRect;

      start += child.size.width;

      child = nextChild(child);

    }

}

@override

  void performLayout() {

final BoxConstraints constraints =this.constraints;

    double maxHeight =_kMinSegmentedControlHeight;

    double childWidth = constraints.minWidth /childCount;

    for (final RenderBox childin getChildrenAsList()) {

childWidth =

math.max(childWidth, child.getMaxIntrinsicWidth(double.infinity));

    }

childWidth = math.min(childWidth, constraints.maxWidth /childCount);

    RenderBox child =firstChild;

    while (child !=null) {

final double boxHeight = child.getMaxIntrinsicHeight(childWidth);

      maxHeight = math.max(maxHeight, boxHeight);

      child = childAfter(child);

    }

constraints.constrainHeight(maxHeight);

    final BoxConstraints childConstraints =BoxConstraints.tightFor(

width: childWidth,

      height: maxHeight,

    );

    child =firstChild;

    while (child !=null) {

child.layout(childConstraints, parentUsesSize:true);

      child = childAfter(child);

    }

switch (textDirection) {

case TextDirection.rtl:

_layoutRects(

childBefore,

          lastChild,

          firstChild,

        );

break;

      case TextDirection.ltr:

_layoutRects(

childAfter,

          firstChild,

          lastChild,

        );

break;

    }

size = constraints.constrain(Size(childWidth *childCount, maxHeight));

  }

@override

  void paint(PaintingContext context, Offset offset) {

RenderBox child =firstChild;

    int index =0;

    while (child !=null) {

_paintChild(context, offset, child, index);

      child = childAfter(child);

      index +=1;

    }

}

void _paintChild(

PaintingContext context, Offset offset, RenderBox child, int childIndex) {

assert(child !=null);

    final _SegmentedControlContainerBoxParentData childParentData =

child.parentData as _SegmentedControlContainerBoxParentData;

    context.canvas.drawRRect(

childParentData.surroundingRect.shift(offset),

      Paint()

..color =backgroundColors[childIndex]

..style = PaintingStyle.fill,

    );

    context.canvas.drawRRect(

childParentData.surroundingRect.shift(offset),

      Paint()

..color =borderColor

        ..strokeWidth =1.0

        ..style = PaintingStyle.stroke,

    );

    context.paintChild(child, childParentData.offset + offset);

  }

@override

  boolhitTestChildren(BoxHitTestResult result, {@required Offset position}) {

assert(position !=null);

    RenderBox child =lastChild;

    while (child !=null) {

final _SegmentedControlContainerBoxParentData childParentData =

child.parentData as _SegmentedControlContainerBoxParentData;

      if (childParentData.surroundingRect.contains(position)) {

return result.addWithPaintOffset(

offset: childParentData.offset,

          position: position,

          hitTest: (BoxHitTestResult result, Offset localOffset) {

assert(localOffset == position - childParentData.offset);

            return child.hitTest(result, position: localOffset);

          },

        );

      }

child = childParentData.previousSibling;

    }

return false;

  }

}

2.引用修改过得文件和组件,准备需要的数据,下面之所以用到用container包裹是因为我发现直接设置padding没有效果,只能靠中间的文字设置margin才能起到padding的作用


import 'package:people_manager/widget/segment_widget.dart' as sement;

//避免和系统组件冲突,因为名字一样

//下面是所需要的数据

Map<String, Container> map = {```

'0':Container(

decoration:BoxDecoration(borderRadius:BorderRadius.circular(20.0)),

    margin:EdgeInsets.symmetric(horizontal:20.0),

    child:Text('Apple'),

  ),

  '1':Container(

decoration:BoxDecoration(borderRadius:BorderRadius.circular(20.0)),

    margin:EdgeInsets.symmetric(horizontal:20.0),

    child:Text('Orange'),

  )

};

static String_fruit ='0';

主要使用代码

sement.CupertinoSegmentedControl(
                                  kMinSegmentedControlHeight: 50,
                      radius: 20,
                      children: map,
                      // 数据
                      groupValue: _fruit,
                      // 选中的数据
                      onValueChanged: (fruit) {
                        setState(() {
                          // 数据改变时通过setState改变选中状态
                          _fruit = fruit;
                        });
                      },
                      unselectedColor: CupertinoColors.white,
                      // 未选中颜色
                      selectedColor: CupertinoColors.activeBlue,
                      // 选中颜色
                      borderColor: CupertinoColors.activeBlue,
                      // 边框颜色
                      pressedColor: const Color(0x33007AFF), // 点击时候的颜色
                    )
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容