[原创]recyclerview实现多行分组 给分组块加圆角.

如果用多个recyclerview 或者里面多套个adapter当我没说,这里的实现方式是通过.借助griviewmanager和item

效果图是要达到这样的.当然这也是我最后搞完的图.

29a5f9a7d0ecebe84ed456ae9ff84eb.jpg

需求:

标题作为1行 内容为3列任意行.
标题内容分组 给标题内容包裹区域加圆角.
只有内容无标题的分组 就给内容区域加圆角

遇到的问题

1.当内容未满3列,颜色为recyclerview颜色或背景色.
2.边距写的不对,导致内容被扭曲,某个item出现背景色而且未和其他行对其.
3.滑动的时候发现我绘制的颜色掉了(是我粗心用的i而不是适配器位置导致)
4.判断末尾行
如果是末尾行直接填充白色圆角
5.如果没有标题,直接给内容加上左 和上右圆角.
6.最底部的边距没得.

其它

直接什么都不做的时候,没有圆角,没有分割线.
设置内容item为3列,但是不满3列,会导致出现背景颜色,有些朋友可能直接设置recyclerview背景了,但是你怕是不要处理圆角了??

如何实现?

  1. 使用GridLayoutManager
    2.给GridLayoutManager 设置setSpanSizeLookup 如果是标题就合并 getSpanSize 表示合并的尺寸,如果是内容是3列,那么这里返回3.否则返回1 ,
  2. 设置ItemDecoration 用getItemOffsets 控制间隔 ,
  3. 设置ItemDecoration 用public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
int spanSize = layoutManager.getSpanSizeLookup().getSpanSize(childAdapterPosition);

主要用于判断当前组是不是0,最后一组我用的另外的方法,组0 index=0, 代表是头部,如果是标题就绘制整个,如果内容 index=0也绘制 ,额好像不需要用到spanGroupIndex我记得用到过得

int spanGroupIndex = layoutManager.getSpanSizeLookup().getSpanGroupIndex(childAdapterPosition, spanCount);
  int spanIndex = layoutManager.getSpanSizeLookup().getSpanIndex(childAdapterPosition, spanCount); //比如第一个是标题 ,第二列是 3格子,标题的永远是0 ,分3列的则是0 12 这样的循环。groupindex就是 每一列的完毕  就算一组。

用于判断是否是最后一行

 int itemCount = parent.getLayoutManager().getItemCount();

用于预测下一个是不是标题,是标题那么现在就应该开始绘制下半身的圆角,以及如果内容item列不满足总列数,就绘制弥补空白处.

int lastspanIndex = layoutManager.getSpanSizeLookup().getSpanIndex(itemCount-1, spanCount); //比如第一个是标题 ,第二列是 3格子,标题的永远是0 ,分3列的则是0 12 这样的循环。groupindex就是 每一列的完毕  就算一组。

下面是具体写完之后的代码.

绘制空缺块和圆角块.
下图红色代表填充的空缺快,最后一组的填充则是绿色 , 头部是蓝色圆角 , 非最后一组底部圆角填充了黄色,我这样做只是为了调试,弄完之后我就把颜色改成白色了..
经常用到的判断
判断当前是跨了几行,用于判断是否是标题

GridLayoutManager layoutManager = new GridLayoutManager(recyclerView.getContext(), spanCount, LinearLayoutManager.VERTICAL, false);
        recyclerView.setLayoutManager(layoutManager);

        layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
            @Override
            public int getSpanSize(int position) {
                int type = recyclerView.getAdapter().getItemViewType(position);
                if (position >= recyclerView.getAdapter().getItemCount()) {
                    return NOT_FOUND_SPAN_SIZE;
                } else if (type == TYPE_MENU_GROUP_NAME) {
                    return MENU_TITLE_SPAN_SIZE;
                } else if (type == TYPE_GROUP_DATA) {
                    return 1;
                } else {
                    return NOT_FOUND_SPAN_SIZE;//这是 decoration调用的。
                }
            }

            @Override
            public int getSpanIndex(int position, int spanCount) {
                int spanIndex = super.getSpanIndex(position, spanCount);
                Log.w(TAG, "spanIndex" + spanIndex + ",pos" + position + ",spanCount:" + spanCount);
                return spanIndex;
            }

            @Override
            public int getSpanGroupIndex(int adapterPosition, int spanCount) {
                int spanGroupIndex = super.getSpanGroupIndex(adapterPosition, spanCount);
                Log.w(TAG, "spanGroupIndex" + spanGroupIndex + ",adapterPosition" + adapterPosition + ",spanCount:" + spanCount);
                return spanGroupIndex;
            }
        });

绘制圆角和空缺快设置代码

  for (int ix = 0; ix < childCount; ix++) {
            final View child = parent.getChildAt(ix);

            int position = parent.getChildAdapterPosition(child);

            GridLayoutManager layoutManager = (GridLayoutManager) parent.getLayoutManager();
            int spanCount = layoutManager.getSpanCount();//表示整个列表分多少列
            int spanSize = layoutManager.getSpanSizeLookup().getSpanSize(position);//表示当前格所占有的格子数
            int spanIndex = layoutManager.getSpanSizeLookup().getSpanIndex(position, spanCount); //这里参数是spanCount,不是spanSize,否则不对,比如第一个是标题 ,第二列是 3格子,标题的永远是0 ,分3列的则是0 12 这样的循环。groupindex就是 每一列的完毕  就算一组。


            if (BuildConfig.DEBUG) {
//                MyAppListAdapter adapter = (MyAppListAdapter) parent.getAdapter();
//                SubMenuItemI subMenuItemI = adapter.getData().get(position);
//                int spanSizeNext = layoutManager.getSpanSizeLookup().getSpanSize(position + 1);
            }

            if (spanSize != MENU_TITLE_SPAN_SIZE) {//普通item只会跨1个。 除非是菜单
            int spanGroupIndex = layoutManager.getSpanSizeLookup().getSpanGroupIndex(position, spanCount);
                int spanSizeNext = layoutManager.getSpanSizeLookup().getSpanSize(position + 1);
                if (spanIndex < MENU_TITLE_SPAN_SIZE - 1) {// MENU_TITLE_SPAN_SIZE 等于new GridManager里面的Count,这里用合并的数来判断也可以做,是否属于最后一个格子,但是最后一个格子又是否铺满整个屏幕是最后一个但是没有刚好没铺满,就把它给铺满。
                    if (spanSizeNext == NOT_FOUND_SPAN_SIZE || spanSizeNext == MENU_TITLE_SPAN_SIZE) {//如果下一个不存在那么是最后一个,或者下一个是标题了。
                        drawable = generateDrawable(-1);//补空缺
                        boundAndDraw(c, child.getRight(), right, drawable, child.getTop(), child.getBottom());//这里没有任何圆角
                        if (BuildConfig.DEBUG) {
            /*                MyAppListAdapter adapter = (MyAppListAdapter) parent.getAdapter();
                            SubMenuItemI subMenuItemI = adapter.getData().get(position);
                            Log.w(TAG, subMenuItemI + ",为最后一个前后面超出!spanIndex:" + spanIndex + ",spanSize:" + spanSize + ",height:" + child.getHeight());
                            */
                        }

                    }
                }

                if (spanSizeNext == NOT_FOUND_SPAN_SIZE || spanSizeNext == MENU_TITLE_SPAN_SIZE) {// 刚好铺满的那种 铺满还需要判断是否下一行是否是标题.
                    //左下角圆角.
                    drawable = generateDrawable(5);//,spanSizeNext == NOT_FOUND_SPAN_SIZE ?Color.GREEN:Color.YELLOW);
                    int top = child.getTop() + child.getHeight();
                    int bottom = (int) (top + radius);
//                            Log.w(TAG,"LEFT:"+left+",top:"+top+",right:"+right+",bottom:"+bottom);
                    boundAndDraw(c, left, right, drawable, top, bottom);
                }
                if( spanGroupIndex==0&&position==0){//没有头部 的顶
                    drawable = generateDrawable(4);
                    int top = (int) (child.getTop() - radius);
                    int bottom = child.getTop();
                    boundAndDraw(c, left, right, drawable, top, bottom);
                }

            } else {//标题头
                drawable = generateDrawable(4);
                int top = (int) (child.getTop() - radius);
                int bottom = child.getTop();
                boundAndDraw(c, left, right, drawable, top, bottom);
            }
        }
    }

    private void debugDrwa(Canvas c, int left, int right, View child) {
        //以下计算主要用来确定绘制的位置
        final int top1 = child.getBottom() + 1;
        ColorDrawable drawable1 = new ColorDrawable(Color.BLUE);
        final int bottom = top1 + drawable1.getIntrinsicHeight();
        boundAndDraw(c, left, right, drawable1, top1, bottom);
    }

/**
     * /外矩形 0左上、1右上、2 右下、3左下的圆角半 4 上 左和右边 5 ,下 左右。
     *
     * @param type
     * @return
     */
    private GradientDrawable generateDrawable(int type, int color) {
        this.color = color;
        return generateDrawable(type);
    }

测距代码 测距就是给view留空间,不留空间就绘制在一坨了.

   int childAdapterPosition = parent.getChildAdapterPosition(view);
        GridLayoutManager layoutManager = (GridLayoutManager) parent.getLayoutManager();
        int spanCount = layoutManager.getSpanCount(); //构造时传递的参数.
        //DefaultSpanSizeLookup
        int spanSize = layoutManager.getSpanSizeLookup().getSpanSize(childAdapterPosition);
        int spanGroupIndex = layoutManager.getSpanSizeLookup().getSpanGroupIndex(childAdapterPosition, spanCount);

        if (spanSize == MENU_TITLE_SPAN_SIZE) { //标题才跨 3个。
//            if (needTop) {
            if (spanGroupIndex == 0) {
                outRect.top = (int) (getSpace() + radius);
            } else {
            outRect.top = (int) (getSpace() + (radius*2));
            }
//            }
        } else  {
            outRect.top = 0;
            outRect.left = 0;
            outRect.right = 0;
            if( spanGroupIndex==0){//没有头部 的顶
                outRect.top = (int) (getSpace()  + radius);
            }else{
                outRect.top = 0;
            }
            int spanIndex = layoutManager.getSpanSizeLookup().getSpanIndex(childAdapterPosition, spanCount); //比如第一个是标题 ,第二列是 3格子,标题的永远是0 ,分3列的则是0 12 这样的循环。groupindex就是 每一列的完毕  就算一组。
            int itemCount = parent.getLayoutManager().getItemCount();
            int lastspanIndex = layoutManager.getSpanSizeLookup().getSpanIndex(itemCount-1, spanCount); //比如第一个是标题 ,第二列是 3格子,标题的永远是0 ,分3列的则是0 12 这样的循环。groupindex就是 每一列的完毕  就算一组。


            if (childAdapterPosition>=itemCount-(lastspanIndex+1)) {//最后一行
                outRect.bottom= (int) (getSpace()+(radius/2));
                if(lastspanIndex==spanIndex&&(1+spanIndex!=MENU_TITLE_SPAN_SIZE)){
//                        outRect.right=30;//=parent.getRight()-parent.getPaddingRight();//写不写其实都一样,因为不绘制右边?不,应该说都铺满屏幕了,不怕控件没给够
                                    }//不能加right,会影响空间
            }

        }

        if (BuildConfig.DEBUG) {
//            int spanGroupIndex =;//1 23格子 或者 1列 都算一组,
            int spanIndex = layoutManager.getSpanSizeLookup().getSpanIndex(childAdapterPosition, spanCount); //比如第一个是标题 ,第二列是 3格子,标题的永远是0 ,分3列的则是0 12 这样的循环。groupindex就是 每一列的完毕  就算一组。


     /*       SubMenuItemI subMenuItemI = ((MyAppListAdapter) parent.getAdapter()).getData().get(childAdapterPosition);
            String title = subMenuItemI.getTitle();*/
            Log.w(TAG, "Decoration SpanIndex:" + spanIndex + ",groupindex:" + spanGroupIndex + ",spanSize:" + spanSize + ",model:" + "title" + ",adapterposition:" + childAdapterPosition);

        }

最终源码


public class MenuDecoration extends SpacesItemDecoration {
    private static final int NOT_FOUND_SPAN_SIZE = -1;
    private static int MENU_TITLE_SPAN_SIZE = 3;
    private final int shadowSize=2;
    private float radius = 30;
    private int color = Color.RED;
    private boolean needTop;
    public static final int TYPE_GROUP_DATA = 1;
    public static final int TYPE_MENU_GROUP_NAME = 0;

    /**
     * @param recyclerView
     * @param spanCount
     * @param needLeft
     * @param needRight
     * @param isneddTop
     */
    public MenuDecoration(RecyclerView recyclerView, int spanCount, boolean needLeft, boolean needRight, boolean isneddTop, int space, float radius, int color) {

        super((int) (space));
        this.radius = radius;
        this.color = color;
        GridLayoutManager layoutManager = new GridLayoutManager(recyclerView.getContext(), spanCount, LinearLayoutManager.VERTICAL, false);
        recyclerView.setLayoutManager(layoutManager);

        layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
            @Override
            public int getSpanSize(int position) {
                int type = recyclerView.getAdapter().getItemViewType(position);
                if (position >= recyclerView.getAdapter().getItemCount()) {
                    return NOT_FOUND_SPAN_SIZE;
                } else if (type == TYPE_MENU_GROUP_NAME) {
                    return MENU_TITLE_SPAN_SIZE;
                } else if (type == TYPE_GROUP_DATA) {
                    return 1;
                } else {
                    return NOT_FOUND_SPAN_SIZE;//这是 decoration调用的。
                }
            }

            @Override
            public int getSpanIndex(int position, int spanCount) {
                int spanIndex = super.getSpanIndex(position, spanCount);
                Log.w(TAG, "spanIndex" + spanIndex + ",pos" + position + ",spanCount:" + spanCount);
                return spanIndex;
            }

            @Override
            public int getSpanGroupIndex(int adapterPosition, int spanCount) {
                int spanGroupIndex = super.getSpanGroupIndex(adapterPosition, spanCount);
                Log.w(TAG, "spanGroupIndex" + spanGroupIndex + ",adapterPosition" + adapterPosition + ",spanCount:" + spanCount);
                return spanGroupIndex;
            }
        });
        /**
         * 顶部 下面实现了
         */
        this.needTop = isneddTop;
        MENU_TITLE_SPAN_SIZE = spanCount;
        recyclerView.setPadding(needLeft ? getSpace()  : 0, isneddTop ? getSpace() / 2 : 0, needRight ? getSpace() : 0, getSpace() / 2);
    }

    private static final String TAG = "Gridlayout";

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {

//        int itemCount = parent.getLayoutManager().getItemCount();
        int childAdapterPosition = parent.getChildAdapterPosition(view);
        GridLayoutManager layoutManager = (GridLayoutManager) parent.getLayoutManager();
        int spanCount = layoutManager.getSpanCount(); //构造时传递的参数.
        //DefaultSpanSizeLookup
        int spanSize = layoutManager.getSpanSizeLookup().getSpanSize(childAdapterPosition);
        int spanGroupIndex = layoutManager.getSpanSizeLookup().getSpanGroupIndex(childAdapterPosition, spanCount);

        if (spanSize == MENU_TITLE_SPAN_SIZE) { //标题才跨 3个。
//            if (needTop) {
            if (spanGroupIndex == 0) {
                outRect.top = (int) (getSpace() + radius);
            } else {
            outRect.top = (int) (getSpace() + (radius*2));
            }
//            }
        } else  {
            outRect.top = 0;
            outRect.left = 0;
            outRect.right = 0;
            if( spanGroupIndex==0){//没有头部 的顶
                outRect.top = (int) (getSpace()  + radius);
            }else{
                outRect.top = 0;
            }
            int spanIndex = layoutManager.getSpanSizeLookup().getSpanIndex(childAdapterPosition, spanCount); //比如第一个是标题 ,第二列是 3格子,标题的永远是0 ,分3列的则是0 12 这样的循环。groupindex就是 每一列的完毕  就算一组。
            int itemCount = parent.getLayoutManager().getItemCount();
            int lastspanIndex = layoutManager.getSpanSizeLookup().getSpanIndex(itemCount-1, spanCount); //比如第一个是标题 ,第二列是 3格子,标题的永远是0 ,分3列的则是0 12 这样的循环。groupindex就是 每一列的完毕  就算一组。


            if (childAdapterPosition>=itemCount-(lastspanIndex+1)) {//最后一行
                outRect.bottom= (int) (getSpace()+(radius/2));
                if(lastspanIndex==spanIndex&&(1+spanIndex!=MENU_TITLE_SPAN_SIZE)){
//                        outRect.right=30;//=parent.getRight()-parent.getPaddingRight();//写不写其实都一样,因为不绘制右边?不,应该说都铺满屏幕了,不怕控件没给够
                                    }//不能加right,会影响空间
            }

        }

        if (BuildConfig.DEBUG) {
//            int spanGroupIndex =;//1 23格子 或者 1列 都算一组,
            int spanIndex = layoutManager.getSpanSizeLookup().getSpanIndex(childAdapterPosition, spanCount); //比如第一个是标题 ,第二列是 3格子,标题的永远是0 ,分3列的则是0 12 这样的循环。groupindex就是 每一列的完毕  就算一组。
     /*       SubMenuItemI subMenuItemI = ((MyAppListAdapter) parent.getAdapter()).getData().get(childAdapterPosition);
            String title = subMenuItemI.getTitle();*/
            Log.w(TAG, "Decoration SpanIndex:" + spanIndex + ",groupindex:" + spanGroupIndex + ",spanSize:" + spanSize + ",model:" + "title" + ",adapterposition:" + childAdapterPosition);

        }
    }


    @Override
    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
//    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        doDraw(c, parent);
    }

    private void doDraw(Canvas c, RecyclerView parent) {
        final int left = parent.getPaddingLeft();
        final int right = parent.getWidth() - parent.getPaddingRight();
        final int childCount = parent.getChildCount();
        Drawable drawable;
        for (int ix = 0; ix < childCount; ix++) {
            final View child = parent.getChildAt(ix);
/*
            if (true) {


                debugDrwa(c, left, right, child);
                continue;
            }*/
            int position = parent.getChildAdapterPosition(child);
//                parent.getChildLayoutPosition()
            GridLayoutManager layoutManager = (GridLayoutManager) parent.getLayoutManager();
            int spanCount = layoutManager.getSpanCount();//表示整个列表分多少列
            int spanSize = layoutManager.getSpanSizeLookup().getSpanSize(position);//表示当前格所占有的格子数
            int spanIndex = layoutManager.getSpanSizeLookup().getSpanIndex(position, spanCount); //这里参数是spanCount,不是spanSize,否则不对,比如第一个是标题 ,第二列是 3格子,标题的永远是0 ,分3列的则是0 12 这样的循环。groupindex就是 每一列的完毕  就算一组。


            if (BuildConfig.DEBUG) {
//                MyAppListAdapter adapter = (MyAppListAdapter) parent.getAdapter();
//                SubMenuItemI subMenuItemI = adapter.getData().get(position);
//                int spanSizeNext = layoutManager.getSpanSizeLookup().getSpanSize(position + 1);
            }

            if (spanSize != MENU_TITLE_SPAN_SIZE) {//普通item只会跨1个。 除非是菜单
            int spanGroupIndex = layoutManager.getSpanSizeLookup().getSpanGroupIndex(position, spanCount);
                int spanSizeNext = layoutManager.getSpanSizeLookup().getSpanSize(position + 1);
                if (spanIndex < MENU_TITLE_SPAN_SIZE - 1) {// MENU_TITLE_SPAN_SIZE 等于new GridManager里面的Count,这里用合并的数来判断也可以做,是否属于最后一个格子,但是最后一个格子又是否铺满整个屏幕是最后一个但是没有刚好没铺满,就把它给铺满。
                    if (spanSizeNext == NOT_FOUND_SPAN_SIZE || spanSizeNext == MENU_TITLE_SPAN_SIZE) {//如果下一个不存在那么是最后一个,或者下一个是标题了。
                        drawable = generateDrawable(-1);//补空缺
                        boundAndDraw(c, child.getRight(), right, drawable, child.getTop(), child.getBottom());//这里没有任何圆角
                        if (BuildConfig.DEBUG) {
            /*                MyAppListAdapter adapter = (MyAppListAdapter) parent.getAdapter();
                            SubMenuItemI subMenuItemI = adapter.getData().get(position);
                            Log.w(TAG, subMenuItemI + ",为最后一个前后面超出!spanIndex:" + spanIndex + ",spanSize:" + spanSize + ",height:" + child.getHeight());
                            */
                        }

                    }
                }

                if (spanSizeNext == NOT_FOUND_SPAN_SIZE || spanSizeNext == MENU_TITLE_SPAN_SIZE) {// 刚好铺满的那种 铺满还需要判断是否下一行是否是标题.
                    //左下角圆角.
                    drawable = generateDrawable(5);//,spanSizeNext == NOT_FOUND_SPAN_SIZE ?Color.GREEN:Color.YELLOW);
                    int top = child.getTop() + child.getHeight();
                    int bottom = (int) (top + radius);
//                            Log.w(TAG,"LEFT:"+left+",top:"+top+",right:"+right+",bottom:"+bottom);
                    boundAndDraw(c, left, right, drawable, top, bottom);
                }
                if( spanGroupIndex==0&&position==0){//没有头部 的顶
                    drawable = generateDrawable(4);
                    int top = (int) (child.getTop() - radius);
                    int bottom = child.getTop();
                    boundAndDraw(c, left, right, drawable, top, bottom);
                }

            } else {//标题头
                drawable = generateDrawable(4);
                int top = (int) (child.getTop() - radius);
                int bottom = child.getTop();
                boundAndDraw(c, left, right, drawable, top, bottom);
            }
        }
    }

    private void debugDrwa(Canvas c, int left, int right, View child) {
        //以下计算主要用来确定绘制的位置
        final int top1 = child.getBottom() + 1;
        ColorDrawable drawable1 = new ColorDrawable(Color.BLUE);
        final int bottom = top1 + drawable1.getIntrinsicHeight();
        boundAndDraw(c, left, right, drawable1, top1, bottom);
    }

    private void boundAndDraw(Canvas c, int left, int right, Drawable drawable, int top, int bottom) {
//        Log.w(TAG,"DrawCall LEFT:"+left+",righ:"+right+",top:"+top+",bottom:"+bottom);
        drawable.setBounds(left, top, right, bottom);
//                                drawable.setBounds(left, (int) (child.getTop()+child.getHeight()-radius), left + child.getWidth(), child.getBottom());
        drawable.draw(c);
    }

    /**
     * /外矩形 0左上、1右上、2 右下、3左下的圆角半 4 上 左和右边 5 ,下 左右。
     *
     * @param type
     * @return
     */
    private Drawable generateDrawable(int type, int color) {
        this.color = color;
        return generateDrawable(type);
    }

    private Drawable generateDrawable(int type) {

        GradientDrawable gd = new GradientDrawable();
        //        color=color|0xff000000;

        gd.setColor(color);
        switch (type) {
            case 0:
                gd.setCornerRadii(new float[]{radius, radius, 0, 0, 0, 0, 0, 0});
                break;
            case 1:
                gd.setCornerRadii(new float[]{0, 0, radius, radius, 0, 0, 0, 0});
                break;
            case 2:
                gd.setCornerRadii(new float[]{0, 0, 0, 0, radius, radius, 0, 0});
                break;
            case 3:
                gd.setCornerRadii(new float[]{0, 0, 0, 0, 0, 0, radius, radius});
                break;
            case 4:
                gd.setCornerRadii(new float[]{radius, radius, radius, radius, 0, 0, 0, 0});
                break;
            case 5:
                gd.setCornerRadii(new float[]{0, 0, 0, 0, radius, radius, radius, radius});
                break;
            case 6:
                gd.setCornerRadii(new float[]{radius, radius, radius, radius, radius, radius, radius, radius});
                break;
            default:
                gd.setCornerRadii(new float[]{0, 0, 0, 0, 0, 0, 0, 0});
                break;
        }
/*
        Drawable[] drawables=new Drawable[2];
        GradientDrawable gdshadow = new GradientDrawable();

        //#ffdb8f  #ffdb8f
        gdshadow.setColor(Color.parseColor("#00ff00"));
        drawables[0]=gdshadow;
        drawables[1]=gd;
        LayerDrawable layerDrawable=new LayerDrawable(drawables);

*/

        return gd;
    }

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容