RecyclerView 從零開(kāi)始一步步深入

RecyclerView作為L(zhǎng)istView,GridView的升級(jí)版,使用起來(lái)非常靈活碍讯。并且配合動(dòng)畫(huà)可以實(shí)現(xiàn)非常贊的效果。

基本使用步驟:
mRecyclerView = findView(R.id.id_recyclerview);
//設(shè)置布局管理器
mRecyclerView.setLayoutManager(layout);
//設(shè)置adapter
mRecyclerView.setAdapter(adapter)
//設(shè)置Item增加、移除動(dòng)畫(huà)
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
//添加分割線(xiàn)
mRecyclerView.addItemDecoration(new DividerItemDecoration(
getActivity(), DividerItemDecoration.HORIZONTAL_LIST));

1.基礎(chǔ)知識(shí)點(diǎn)

  • LayoutManager 顧名思義 負(fù)責(zé)布局的管理,通過(guò)切換布局管理器我們可以輕松實(shí)現(xiàn)列表柱蟀,網(wǎng)格,瀑布流等效果蚜厉。
  • Adapter 用于適配item,這里的Adapter是繼承自RecyclerView.Adapter不是BaseAdapter
  • ItemDecoration 通俗點(diǎn)講就是“分割線(xiàn)”长已,類(lèi)似listView中的divider,但是RecyclerView中并未提供這個(gè)屬性,要實(shí)現(xiàn)分割線(xiàn)术瓮,需要通過(guò)調(diào)用addItemDecoration()康聂,系統(tǒng)并未提供缺省的ItemDecoration實(shí)現(xiàn)類(lèi)。幸運(yùn)的是已經(jīng)有第三方實(shí)現(xiàn)好了的ItemDecoration胞四,后面介紹
  • ItemAnimator 有了它可以實(shí)現(xiàn)各種炫酷的動(dòng)畫(huà)效果恬汁,系統(tǒng)提供了缺省的DefaultItemAnimator

2.知識(shí)點(diǎn)詳解

⑴ LayoutManager 系統(tǒng)提供了LinearLayoutManager,GridLayoutManager撬讽,StaggeredGridLayoutManager,分別對(duì)應(yīng)三種效果 列表蕊连,網(wǎng)格悬垃,瀑布流游昼。示例代碼:

 mNormalRecyclerView.setLayoutManager(new LinearLayoutManager(this));//設(shè)置list布局
 mNormalRecyclerView.setLayoutManager(new GridLayoutManager(this, 4));//設(shè)置網(wǎng)格布局
 mNormalRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL));//設(shè)置瀑布流布局

可以看到想要切換效果只需要設(shè)置下LayoutManager,對(duì)于有需求要求顯示多種布局效果的時(shí)候尝蠕,用RecyclerView相比listView等要省力靈活很多烘豌。
...
也許這還不夠打動(dòng)你,接著往下看
通常我們的listView看彼,GirdView都是豎直方向流向的廊佩,需求來(lái)了要實(shí)現(xiàn)橫向的listView腫么辦?過(guò)去還是要花點(diǎn)力氣去實(shí)現(xiàn)的吧靖榕,看RecyclerView分分鐘秒殺你

      LinearLayoutManager layoutManager=new LinearLayoutManager(this);
      layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
      mNormalRecyclerView.setLayoutManager(layoutManager);//設(shè)置list橫向布局

⑵ Adapter 適配item布局的東東看代碼标锄,先寫(xiě)個(gè)最簡(jiǎn)單的Adapter


public class AdapterNormal extends RecyclerView.Adapter<AdapterNormal.MyViewHolder> {
  private Context context;
  private List<String> list;

  public AdapterNormal(Context context, List<String> list) {
      this.context = context;
      this.list = list;
  }

  @Override
  public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {//產(chǎn)生幾個(gè)可復(fù)用的ViewHolder實(shí)例
      MyViewHolder viewHolder = new MyViewHolder(LayoutInflater.from(context).inflate(R.layout.adapter_item, parent, false));
      return viewHolder;
  }

  @Override
  public int getItemCount() {
      return list.size();
  }

  @Override
  public void onBindViewHolder(final MyViewHolder holder, final int position) {//為每一項(xiàng)View綁定數(shù)據(jù)
      holder.mTextView.setText(list.get(position));
  }


  class MyViewHolder extends RecyclerView.ViewHolder {//ViewHolder 大家都不陌生
      private TextView mTextView;

      public MyViewHolder(View itemView) {
          super(itemView);
          mTextView = (TextView) itemView.findViewById(R.id.mText);
      }
  }
}

調(diào)用它

adapterNormal = new AdapterNormal(getApplicationContext(), list);
mNormalRecyclerView.setAdapter(adapterNormal);//設(shè)置適配器

多個(gè)不同項(xiàng)布局,Adapter該怎么寫(xiě)茁计?

  @Override
  public int getItemViewType(int position) {//在Adapter中重寫(xiě)該方法料皇,根據(jù)條件返回不同的值例如100,101
      if (...) {
          return 100;
      }else if (...) {
          return 101;
      }else{
          return super.getItemViewType(position);
      }
  }

  @Override
  public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {//根據(jù)getItemViewType返回的值生成不同的ViewHolder實(shí)例
      MyViewHolder viewHolder = null;
      switch (viewType) {//示例邏輯
          case 100:
              viewHolder=...;
              break;
          case 101:
              viewHolder=...;
              break;
          default:
              viewHolder = new MyViewHolder(LayoutInflater.from(context).inflate(R.layout.adapter_item, parent, false));
              break;
      }
      return viewHolder;
  }

  @Override
  public void onBindViewHolder(final MyViewHolder holder, final int position) {//為不同的布局適配數(shù)據(jù)
      switch (holder.getItemViewType()) {
          case 100:
              ...
              break;
          case 101:
              ...
              break;
          default:
              holder.mTextView.setText(list.get(position));
              break;
      }
  }

每次都這樣寫(xiě)Adapter是不是覺(jué)得很累?簡(jiǎn)化它

首先引入 compile 'com.zhy:base-adapter:2.0.0'

Android 萬(wàn)能的Adapter for ListView,RecyclerView,GridView等星压,支持多種Item類(lèi)型的情況践剂。

mRecyclerView.setAdapter(new CommonAdapter<String>(this, R.layout.item_list, mDatas)
{
    @Override
    public void convert(ViewHolder holder, String s)
    {
        holder.setText(R.id.id_item_list_title, s);
    }
});

是不是相當(dāng)方便,在convert方法中完成數(shù)據(jù)娜膘、事件綁定即可逊脯。還有多種ItemViewType的封裝等自行研究都很方便

⑶ItemDecoration "分割線(xiàn)" 這玩意感覺(jué)沒(méi)什么好說(shuō)的直接看代碼

  
/**
 * ListView的分割線(xiàn)
 */
public class ListItemDecoration extends RecyclerView.ItemDecoration {

    private static final int[] ATTRS = new int[]{
            android.R.attr.listDivider
    };

    public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;

    public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;

    private Drawable mDivider;

    private int mOrientation;

    public ListItemDecoration(Context context, int orientation) {
        final TypedArray a = context.obtainStyledAttributes(ATTRS);
        mDivider = a.getDrawable(0);
        a.recycle();
        setOrientation(orientation);
    }

    public void setOrientation(int orientation) {
        if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
            throw new IllegalArgumentException("invalid orientation");
        }
        mOrientation = orientation;
    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        if (mOrientation == VERTICAL_LIST) {
            drawVertical(c, parent);
        } else {
            drawHorizontal(c, parent);
        }

    }


    public void drawVertical(Canvas c, RecyclerView parent) {
        final int left = parent.getPaddingLeft();
        final int right = parent.getWidth() - parent.getPaddingRight();

        final int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View child = parent.getChildAt(i);
            android.support.v7.widget.RecyclerView v = new android.support.v7.widget.RecyclerView(parent.getContext());
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
                    .getLayoutParams();
            final int top = child.getBottom() + params.bottomMargin;
            final int bottom = top + mDivider.getIntrinsicHeight();
            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }

    public void drawHorizontal(Canvas c, RecyclerView parent) {
        final int top = parent.getPaddingTop();
        final int bottom = parent.getHeight() - parent.getPaddingBottom();

        final int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View child = parent.getChildAt(i);
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
                    .getLayoutParams();
            final int left = child.getRight() + params.rightMargin;
            final int right = left + mDivider.getIntrinsicHeight();
            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        if (mOrientation == VERTICAL_LIST) {
            outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
        } else {
            outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
        }
    }
}

/**
 * @author 鴻洋
 * GridView的分割線(xiàn)
 * 因?yàn)樽髡咂俨剂鞯姆指罹€(xiàn)在item高度不一樣的情況下有bug,所以被我去掉了
 */
public class GridItemDecoration extends RecyclerView.ItemDecoration {

    private static final int[] ATTRS = new int[]{android.R.attr.listDivider};
    private Drawable mDivider;

    public GridItemDecoration(Context context) {
        final TypedArray a = context.obtainStyledAttributes(ATTRS);
        mDivider = a.getDrawable(0);
        a.recycle();
    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        drawHorizontal(c, parent);
        drawVertical(c, parent);
    }

    private int getSpanCount(RecyclerView parent) {
        // 列數(shù)
        int spanCount = -1;
        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
        spanCount = ((GridLayoutManager) layoutManager).getSpanCount();
        return spanCount;
    }

    public void drawHorizontal(Canvas c, RecyclerView parent) {
        int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View child = parent.getChildAt(i);
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
                    .getLayoutParams();
            final int left = child.getLeft() - params.leftMargin;
            final int right = child.getRight() + params.rightMargin
                    + mDivider.getIntrinsicWidth();
            final int top = child.getBottom() + params.bottomMargin;
            final int bottom = top + mDivider.getIntrinsicHeight();
            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }

    public void drawVertical(Canvas c, RecyclerView parent) {
        final int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View child = parent.getChildAt(i);
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
                    .getLayoutParams();
            final int top = child.getTop() - params.topMargin;
            final int bottom = child.getBottom() + params.bottomMargin;
            final int left = child.getRight() + params.rightMargin;
            final int right = left + mDivider.getIntrinsicWidth();
            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }

    private boolean isLastColum(int pos, int spanCount) {
        if ((pos + 1) % spanCount == 0)// 如果是最后一列竣贪,則不需要繪制右邊
        {
            return true;
        }
        return false;
    }

    private boolean isLastRaw(int pos, int spanCount, int childCount) {
        childCount = childCount - childCount % spanCount;
        if (pos >= childCount)// 如果是最后一行军洼,則不需要繪制底部
            return true;
        return false;
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        int spanCount = getSpanCount(parent);
        int childCount = parent.getAdapter().getItemCount();
        if (isLastRaw(parent.getChildAdapterPosition(view), spanCount, childCount))// 如果是最后一行,則不需要繪制底部
        {
            outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
        } else if (isLastColum(parent.getChildAdapterPosition(view), spanCount))// 如果是最后一列演怎,則不需要繪制右邊
        {
            outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
        } else {
            outRect.set(0, 0, mDivider.getIntrinsicWidth(),
                    mDivider.getIntrinsicHeight());
        }
    }
}

⑷ ItemAnimator 前面說(shuō)過(guò)了可以產(chǎn)生炫酷的動(dòng)畫(huà)歉眷,提升逼格的神器
https://github.com/wasabeef/recyclerview-animators

demo3.gif

demo2.gif

demo.gif

⑸ “遺憾”。 是的RecyclerView并沒(méi)有像listView,GridView那樣提供itemClickListener和itemLongClickListener颤枪,我們需要自行實(shí)現(xiàn)汗捡,可以通過(guò)設(shè)置接口回調(diào),好消息是上面提到的Android 萬(wàn)能的Adapter 已經(jīng)為我們實(shí)現(xiàn)好了這些工作。

⑹ 補(bǔ)充扇住。當(dāng)數(shù)據(jù)發(fā)生變化時(shí)我們需要更新數(shù)據(jù)集

adapterNormal.notifyDataSetChanged(); //無(wú)動(dòng)畫(huà)效果
adapterNormal.notifyItemInserted(0);//有動(dòng)畫(huà)效果

以上就是RecyclerView的基本使用春缕,華麗的分割線(xiàn),提升艘蹋。锄贼。。


自定義RecyclerView女阀,實(shí)現(xiàn)下拉刷新宅荤,上拉加載更多
https://github.com/jianghejie/XRecyclerView
看效果先

default.gif

源碼淺析:

public class XRecyclerView extends RecyclerView {
  @Override
  public void setAdapter(Adapter adapter) {//重寫(xiě)適配器方法
      mWrapAdapter = new WrapAdapter(adapter);//一個(gè)包裝類(lèi)
      super.setAdapter(mWrapAdapter);//設(shè)置這個(gè)包裝后的適配器作為適配器
      adapter.registerAdapterDataObserver(mDataObserver);//注冊(cè)自定義的數(shù)據(jù)觀察者,因?yàn)檫m配器是包裝后的適配器
      mDataObserver.onChanged();
  }

  @Override
  public void onScrollStateChanged(int state) {//通過(guò)判斷最后一個(gè)可見(jiàn)item的位置和項(xiàng)數(shù)量的大小關(guān)系實(shí)現(xiàn)上拉加載更多
      super.onScrollStateChanged(state);

      if (state == RecyclerView.SCROLL_STATE_IDLE && mLoadingListener != null && !isLoadingData && loadingMoreEnabled) {
          LayoutManager layoutManager = getLayoutManager();
          int lastVisibleItemPosition;
          if (layoutManager instanceof GridLayoutManager) {
              lastVisibleItemPosition = ((GridLayoutManager) layoutManager).findLastVisibleItemPosition();
          } else if (layoutManager instanceof StaggeredGridLayoutManager) {
              int[] into = new int[((StaggeredGridLayoutManager) layoutManager).getSpanCount()];
              ((StaggeredGridLayoutManager) layoutManager).findLastVisibleItemPositions(into);
              lastVisibleItemPosition = findMax(into);
          } else {
              lastVisibleItemPosition = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();
          }
          if (layoutManager.getChildCount() > 0
                  && lastVisibleItemPosition >= layoutManager.getItemCount() - 1 && layoutManager.getItemCount() > layoutManager.getChildCount() && !isNoMore && mRefreshHeader.getState() < ArrowRefreshHeader.STATE_REFRESHING) {

              View footView = mFootViews.get(0);
              isLoadingData = true;
              if (footView instanceof LoadingMoreFooter) {
                  ((LoadingMoreFooter) footView).setState(LoadingMoreFooter.STATE_LOADING);
              } else {
                  footView.setVisibility(View.VISIBLE);
              }
              mLoadingListener.onLoadMore();
          }
      }
  }

  @Override
  public boolean onTouchEvent(MotionEvent ev) {//通過(guò)重寫(xiě)觸摸事件實(shí)現(xiàn)下拉刷新
      if (mLastY == -1) {
          mLastY = ev.getRawY();
      }
      switch (ev.getAction()) {
          case MotionEvent.ACTION_DOWN:
              mLastY = ev.getRawY();
              break;
          case MotionEvent.ACTION_MOVE:
              final float deltaY = ev.getRawY() - mLastY;
              mLastY = ev.getRawY();
              if (isOnTop() && pullRefreshEnabled) {
                  mRefreshHeader.onMove(deltaY / DRAG_RATE);
                  if (mRefreshHeader.getVisibleHeight() > 0 && mRefreshHeader.getState() < ArrowRefreshHeader.STATE_REFRESHING) {
                      return false;
                  }
              }
              break;
          default:
              mLastY = -1; // reset
              if (isOnTop() && pullRefreshEnabled) {
                  if (mRefreshHeader.releaseAction()) {
                      if (mLoadingListener != null) {
                          mLoadingListener.onRefresh();
                      }
                  }
              }
              break;
      }
      return super.onTouchEvent(ev);
  }
}
   private class WrapAdapter extends RecyclerView.Adapter<ViewHolder> {//定義一個(gè)包裝類(lèi)浸策,將外部自定義的適配器和內(nèi)部適配器邏輯關(guān)聯(lián)起來(lái)

      private RecyclerView.Adapter adapter;//持有我們使用的時(shí)候自定義的適配器


      public WrapAdapter(RecyclerView.Adapter adapter) {
          this.adapter = adapter;
      }

      @Override
      public void onAttachedToRecyclerView(RecyclerView recyclerView) {//只執(zhí)行一次
          super.onAttachedToRecyclerView(recyclerView);
          RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
          if (manager instanceof GridLayoutManager) {
              final GridLayoutManager gridManager = ((GridLayoutManager) manager);
              gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {//設(shè)置監(jiān)聽(tīng)回調(diào)只需要設(shè)置一次
                  @Override
                  public int getSpanSize(int position) {//SpanSize 代表占幾列
                      return (isHeader(position) || isFooter(position))//頭部或者尾部占滿(mǎn)全行或者全列
                              ? gridManager.getSpanCount() : 1;
                  }
              });
          }
      }

      @Override
      public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {//被多次調(diào)用
          super.onViewAttachedToWindow(holder);
          ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
          if (lp != null
                  && lp instanceof StaggeredGridLayoutManager.LayoutParams
                  && (isHeader(holder.getLayoutPosition()) || isFooter(holder.getLayoutPosition()))) {
              StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp;
              p.setFullSpan(true);//頭部或者尾部占滿(mǎn)全行或者全列
          }
      }

      @Override
      public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
          if (viewType == TYPE_REFRESH_HEADER) {//根據(jù)返回的類(lèi)型生成不同的ViewHolder實(shí)例
              mCurrentPosition++;
              return new SimpleViewHolder(mHeaderViews.get(0));
          } else if (isContentHeader(mCurrentPosition)) {
              if (viewType == sHeaderTypes.get(mCurrentPosition - 1)) {
                  mCurrentPosition++;
                  return new SimpleViewHolder(mHeaderViews.get(headerPosition++));
              }
          } else if (viewType == TYPE_FOOTER) {
              return new SimpleViewHolder(mFootViews.get(0));
          }
          return adapter.onCreateViewHolder(parent, viewType);
      }

      private int mCurrentPosition;

      @Override
      public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {//為我們自定義的item類(lèi)型綁定數(shù)據(jù)
          if (isHeader(position)) {
              return;
          }
          int adjPosition = position - getHeadersCount();
          int adapterCount;
          if (adapter != null) {
              adapterCount = adapter.getItemCount();
              if (adjPosition < adapterCount) {
                  adapter.onBindViewHolder(holder, adjPosition);
                  return;
              }
          }
      }


      @Override
      public int getItemViewType(int position) {//返回刷新頭類(lèi)型冯键,普通頭類(lèi)型,尾部類(lèi)型庸汗,我們自定義的類(lèi)型
          if (isRefreshHeader(position)) {
              return TYPE_REFRESH_HEADER;
          }
          if (isHeader(position)) {
              position = position - 1;
              return sHeaderTypes.get(position);
          }
          if (isFooter(position)) {
              return TYPE_FOOTER;
          }
          int adjPosition = position - getHeadersCount();
          int adapterCount;
          if (adapter != null) {
              adapterCount = adapter.getItemCount();
              if (adjPosition < adapterCount) {
                  return adapter.getItemViewType(adjPosition);
              }
          }
          return TYPE_NORMAL;
      }
 }
   private class DataObserver extends RecyclerView.AdapterDataObserver {
      @Override
      public void onChanged() {//數(shù)據(jù)改變的時(shí)候通過(guò)比較item數(shù)量顯示隱藏EmptyView
          Adapter<?> adapter = getAdapter();
          if (adapter != null && mEmptyView != null) {
              int emptyCount = 0;
              if (pullRefreshEnabled) {
                  emptyCount++;
              }
              if (loadingMoreEnabled) {
                  emptyCount++;
              }
              if (adapter.getItemCount() == emptyCount) {
                  mEmptyView.setVisibility(View.VISIBLE);
                  XRecyclerView.this.setVisibility(View.GONE);
              } else {
                  mEmptyView.setVisibility(View.GONE);
                  XRecyclerView.this.setVisibility(View.VISIBLE);
              }
          }
          if (mWrapAdapter != null) {
              mWrapAdapter.notifyDataSetChanged();
          }
      }

      @Override
      public void onItemRangeInserted(int positionStart, int itemCount) {
          mWrapAdapter.notifyItemRangeInserted(positionStart, itemCount);
      }

      @Override
      public void onItemRangeChanged(int positionStart, int itemCount) {
          mWrapAdapter.notifyItemRangeChanged(positionStart, itemCount);
      }

      @Override
      public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
          mWrapAdapter.notifyItemRangeChanged(positionStart, itemCount, payload);
      }

      @Override
      public void onItemRangeRemoved(int positionStart, int itemCount) {
          mWrapAdapter.notifyItemRangeRemoved(positionStart, itemCount);
      }

      @Override
      public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
          mWrapAdapter.notifyItemMoved(fromPosition, toPosition);
      }
  };

大致思路:定義一個(gè)包裝適配器惫确,通過(guò)不同的item類(lèi)型判斷生成刷新頭,普通頭部蚯舱,尾部改化,我們自定義的itemView并綁定item數(shù)據(jù)→監(jiān)聽(tīng)滾動(dòng)和觸摸事件來(lái)顯示隱藏刷新頭和加載更多尾部視圖并通過(guò)接口拋出刷新和加載更多抽象方法

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市枉昏,隨后出現(xiàn)的幾起案子陈肛,更是在濱河造成了極大的恐慌,老刑警劉巖兄裂,帶你破解...
    沈念sama閱讀 216,470評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件句旱,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡懦窘,警方通過(guò)查閱死者的電腦和手機(jī)前翎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)畅涂,“玉大人港华,你說(shuō)我怎么就攤上這事∥缢ィ” “怎么了立宜?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,577評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)臊岸。 經(jīng)常有香客問(wèn)我橙数,道長(zhǎng),這世上最難降的妖魔是什么帅戒? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,176評(píng)論 1 292
  • 正文 為了忘掉前任灯帮,我火速辦了婚禮崖技,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘钟哥。我一直安慰自己迎献,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布腻贰。 她就那樣靜靜地躺著吁恍,像睡著了一般。 火紅的嫁衣襯著肌膚如雪播演。 梳的紋絲不亂的頭發(fā)上冀瓦,一...
    開(kāi)封第一講書(shū)人閱讀 51,155評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音写烤,去河邊找鬼翼闽。 笑死,一個(gè)胖子當(dāng)著我的面吹牛顶霞,可吹牛的內(nèi)容都是我干的肄程。 我是一名探鬼主播锣吼,決...
    沈念sama閱讀 40,041評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼选浑,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了玄叠?” 一聲冷哼從身側(cè)響起古徒,我...
    開(kāi)封第一講書(shū)人閱讀 38,903評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎读恃,沒(méi)想到半個(gè)月后隧膘,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,319評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡寺惫,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評(píng)論 2 332
  • 正文 我和宋清朗相戀三年疹吃,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片西雀。...
    茶點(diǎn)故事閱讀 39,703評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡萨驶,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出艇肴,到底是詐尸還是另有隱情腔呜,我是刑警寧澤,帶...
    沈念sama閱讀 35,417評(píng)論 5 343
  • 正文 年R本政府宣布再悼,位于F島的核電站核畴,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏冲九。R本人自食惡果不足惜谤草,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧丑孩,春花似錦泳炉、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,664評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至枫浙,卻和暖如春刨肃,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背箩帚。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,818評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工真友, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人紧帕。 一個(gè)月前我還...
    沈念sama閱讀 47,711評(píng)論 2 368
  • 正文 我出身青樓盔然,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親是嗜。 傳聞我的和親對(duì)象是個(gè)殘疾皇子愈案,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評(píng)論 2 353

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