Android 記錄一下仿抖音評論列表

之前寫過一篇類似的文章,但是只有dialog的部分,鏈接:http://www.reibang.com/p/c1941eee0c4a

1636094985044.gif

當(dāng)時想的是難點在框框偷厦,其他的都還好,什么二級評論寫起來容易司忱,以后遇到也不怕北秽,所以沒進一步寫,結(jié)果現(xiàn)在看別人的東西了袁,自己又想去寫的時候朗恳,發(fā)現(xiàn)不一般啊,第一天的時候居然沒寫出來载绿。所以記錄一下粥诫,目的不為別的,就怕以后在遇到崭庸,能拿過來就用怀浆。
demo的功能范圍:
1、評論框BottomSheetDialogFragment的設(shè)置怕享,能滑動隱藏dialog执赡。
2、一級評論二級評論的加載函筋,二級評論的加載更多與收起功能沙合。
3、評論記載失敗一級加載更多處理跌帐。
4首懈、發(fā)送模擬新主評論绊率,以及回復(fù)他人評論

這次主要做二級評論,和抖音一樣能加載跟多子評論加載完全部猜拾,能收起即舌。


image.png

demo的設(shè)定是一條一級評論,如果他有二級評論挎袜,并且二級評論數(shù)量超過1條時就會出現(xiàn)加載更多條目顽聂。

我分析的結(jié)論是有兩種做法:
1、對于一條評論體來說盯仪,我們可以把里面的二級評論看做是一個子recycleview紊搪,二級評論的加載更多條目可以用底部布局來寫,就相當(dāng)于一個大recycleview來展示所有一級評論全景,然后每一條一級評論里面可能有一個次recycleview耀石。這樣做的話,就是recycleview的復(fù)用需要好好處理了爸黄。
2滞伟、不采用嵌套的recycleview的方式,把一級評論炕贵、二級評論加載更多條目三種都看做是recycleview的條目梆奈,給他們設(shè)定itemType類型,分別展示称开。這個需要處理好加載更多時亩钟,插入位置的計算。
權(quán)衡利弊鳖轰,demo采用了第二種清酥。第一種我也會去做,但是可能不會發(fā)出來蕴侣。

說到給recycleview分類焰轻,那肯定用BaseRecyclerViewAdapterHelper更方便【χ耄可惜的是項目里面用的是2.x的版本鹦马,沒有3.x的,它的3.x版本有node模式忆肾,解決這種二級列表問題更快荸频,demo為了更好的模擬項目,也就用了2.x版本客冈。

數(shù)據(jù)方面旭从,好好思考一下一級,二級,加載更多的javabean結(jié)構(gòu)和悦。這里我模擬了公司后臺返回的數(shù)據(jù)模型退疫。
一級評論:MainCommendBean
數(shù)據(jù)體:返回評論文字內(nèi)容、所有子評論數(shù)量鸽素、當(dāng)前默認(rèn)需要展示的二級評論集合(默認(rèn)先展示一條二級評論褒繁,所以默認(rèn)集合大小為1)。
二級評論:ChildCommendBean
數(shù)據(jù)體:返回評論文字內(nèi)容
加載更多評論條目:MoreCommendBean(這個后臺不會返回馍忽,是我們拿到數(shù)據(jù)后自己往數(shù)據(jù)里面加棒坏,主要是為了持有一級評論,方便邏輯判斷)
數(shù)據(jù)體:對應(yīng)的一級評論引用遭笋、點擊加載更多二級評論存放的集合坝冕。

好累啊,直接上代碼把瓦呼。
主要評論框:CommendMsgDialogFragment

public class CommendMsgDialogFragment extends BottomSheetDialogFragment implements OnClickLoadMoreChildCallBack, View.OnClickListener, OnCommendItemClickCallBack {
    private OnDisMissCallBack onDisMissCallBack;
    private RecyclerView mRecyclerView;
    private int page = 0;
    private int pageNum = 20;
    private View emptyView;
    private DataTestUtil dataTestUtil;
    private CommendAdapter mAdapter;
    private TextView mTextView;
    private CommendInputDialogFragment mCommendInputDialog;
    private TextView mTvSend;

    public void setOnDisMissCallBack(OnDisMissCallBack onDisMissCallBack) {
        this.onDisMissCallBack = onDisMissCallBack;
    }

    public static CommendMsgDialogFragment newInstance() {

        Bundle args = new Bundle();

        CommendMsgDialogFragment fragment = new CommendMsgDialogFragment();
        fragment.setArguments(args);
        return fragment;
    }


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setStyle(BottomSheetDialogFragment.STYLE_NORMAL, R.style.CustomBottomSheetDialogTheme);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.fragment_commend_msg_dialog, container, false);
        return view;
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        Window window = getDialog().getWindow();
        window.requestFeature(Window.FEATURE_NO_TITLE);
        super.onActivityCreated(savedInstanceState);
        //設(shè)置背景為透明
        FrameLayout bottom = getDialog().findViewById(R.id.design_bottom_sheet);
        if (bottom != null) {
            bottom.setBackgroundResource(android.R.color.transparent);
        }
        //去除陰影
        window.setGravity(Gravity.BOTTOM);
        WindowManager.LayoutParams layoutParams = window.getAttributes();
        layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
        layoutParams.dimAmount = 0.0f;
        window.setAttributes(layoutParams);
        getDialog().setOnDismissListener(new DialogInterface.OnDismissListener() {
            @Override
            public void onDismiss(DialogInterface dialog) {
                if(onDisMissCallBack != null){
                    onDisMissCallBack.onDismiss();
                }
                dismissAllowingStateLoss();
            }
        });
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        dataTestUtil = new DataTestUtil();//初始模擬數(shù)據(jù)工具
        initView(view);
        getMainCommends(true);
    }

    private void initView(View view) {
        emptyView = LayoutInflater.from(getContext()).inflate(R.layout.empty_view, null, false);
        mRecyclerView = view.findViewById(R.id.mRecyclerView);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));//加載更多
        mAdapter = new CommendAdapter(null);
        mAdapter.setLoadMoreView(new LoadMoreAndFooterView());
        mAdapter.setOnClickLoadMoreChildCallBack(this);
        mAdapter.setOnLoadMoreListener(new BaseQuickAdapter.RequestLoadMoreListener() {
            @Override
            public void onLoadMoreRequested() {
                getMainCommends(false);
            }
        });
        mAdapter.setOnCommendItemClickCallBack(this);
        mRecyclerView.setAdapter(mAdapter);
        mTextView = view.findViewById(R.id.mTextView);
        mTextView.setOnClickListener(this);
        mTvSend = view.findViewById(R.id.mTvSend);
        mTvSend.setOnClickListener(this);
    }

    /**
     * 獲取主評論
     */
    private void getMainCommends(boolean isRefresh) {
        if(isRefresh){
            CommendMsgDialogFragment.this.page = 0;
        }
        dataTestUtil.getMainCommends(isRefresh, page, pageNum, new OnMainCommendCallBack() {
            @Override
            public void onSuccess(boolean isRefresh, List<MainCommendBean> list) {
                CommendMsgDialogFragment.this.page += 1;
                List<MultiItemEntity> newList = getMutilItems(list);
                if(isRefresh){
                    mAdapter.setNewData(newList);
                }else{
                    mAdapter.addData(newList);
                }
                mAdapter.expandAll();
                mAdapter.loadMoreComplete();
            }

            @Override
            public void onFail() {
                if(isRefresh){
                    mAdapter.setEmptyView(emptyView);
                }else{
                    mAdapter.loadMoreEnd();
                }
            }
        });
    }

    /**
     * 轉(zhuǎn)換并且設(shè)置二級數(shù)據(jù)
     * @param list
     * @return
     */
    private List<MultiItemEntity> getMutilItems(List<MainCommendBean> list) {
        List<MultiItemEntity> datas = new ArrayList<>();
        for (MainCommendBean mainCommendBean : list) {
            if(mainCommendBean != null && mainCommendBean.getChildList() != null && mainCommendBean.getChildList().size() > 0){
                //如果有子回復(fù)喂窟,需要綁定
                for (ChildCommendBean childCommendBean : mainCommendBean.getChildList()) {
                    mainCommendBean.addSubItem(childCommendBean);
                }
                //最后加一條加載更多條目
                MoreCommendBean moreCommendBean = new MoreCommendBean();
                moreCommendBean.setMainCommendBean(mainCommendBean);
                mainCommendBean.addSubItem(moreCommendBean);
            }
            datas.add(mainCommendBean);
        }
        return datas;
    }

    /**
     * 點擊展示更多子評論條目
     * @param tvExpandNum
     * @param loadingImageView
     * @param moreCommendBean
     */
    @Override
    public void onClickMoreChild(TextView tvExpandNum, ProgressBar loadingImageView, MoreCommendBean moreCommendBean) {
        if(moreCommendBean.isLoaded()){
            loadChildCommendFromLocal(moreCommendBean);
        }else{
            loadChildCommendFromNet(moreCommendBean,tvExpandNum,loadingImageView);
        }
    }

    /**
     * 網(wǎng)絡(luò)上的數(shù)據(jù)加載
     * @param moreCommendBean
     */
    private void loadChildCommendFromNet(MoreCommendBean moreCommendBean,TextView tvExpandNum, ProgressBar loadingImageView) {
        showChileLoading(true,tvExpandNum,loadingImageView,moreCommendBean);
        dataTestUtil.getChildCommends(moreCommendBean.getMainCommendBean().getChildList().size(), moreCommendBean.getMainCommendBean().getChildNumber(), new OnChildCommendCallBack() {
            @Override
            public void onSuccess(List<ChildCommendBean> list) {
                //沒加載完全部,就去網(wǎng)絡(luò)
                moreCommendBean.getMainCommendBean().getChildList().addAll(list);
                moreCommendBean.getSubList().addAll(list);
                int index = mAdapter.getData().indexOf(moreCommendBean);
                mAdapter.addData(index,list);
                if(moreCommendBean.getMainCommendBean().getChildList().size() == moreCommendBean.getMainCommendBean().getChildNumber()){
                    //全部加載完了
                    moreCommendBean.setZheDie(false);
                    moreCommendBean.setLoaded(true);
                }
                mAdapter.notifyItemChanged(index+list.size());
                showChileLoading(false,tvExpandNum,loadingImageView,moreCommendBean);
            }
        });
    }

    /**
     * 網(wǎng)上數(shù)據(jù)全部加載完了央串,下次再點擊暫開收起磨澡,數(shù)據(jù)就是本地的
     * 新加入的子評論都在moreCommendBean.getSubList里面
     */
    private void loadChildCommendFromLocal(MoreCommendBean moreCommendBean) {
        if(moreCommendBean.isZheDie()){
            //加載完了,就不要網(wǎng)絡(luò)加載了质和,去本地
            int index = mAdapter.getData().indexOf(moreCommendBean);
            //去除最先加入的subitem
            mAdapter.addData(index,moreCommendBean.getSubList());
            moreCommendBean.setZheDie(false);
        }else{
            //全部展開了钱贯,點擊需要收起
            //移除就行了
            int start = mAdapter.getData().indexOf(moreCommendBean)-1;
            int end = start - moreCommendBean.getSubList().size();
            for(int x = start; x > end; x--){
                mAdapter.remove(x);
            }
            moreCommendBean.setZheDie(true);
        }
    }

    private void showChileLoading(boolean show, TextView tvExpandNum, ProgressBar loadingImageView, MoreCommendBean moreCommendBean){
        if(show){
            tvExpandNum.setVisibility(View.GONE);
            loadingImageView.setVisibility(View.VISIBLE);
            moreCommendBean.isLoading = true;
        }else{
            tvExpandNum.setVisibility(View.VISIBLE);
            loadingImageView.setVisibility(View.GONE);
            moreCommendBean.isLoading = false;
        }
    }

    private void showInputDialog(MainCommendBean mainCommendBean) {
        if(mCommendInputDialog == null){
            mCommendInputDialog = CommendInputDialogFragment.newInstance(mTextView.getText().toString());
            mCommendInputDialog.setOnDisMissCallBack(new CommendInputDialogFragment.OnDisMissCallBack() {
                @Override
                public void onDismiss() {
                    mCommendInputDialog = null;
                }

                @Override
                public void saveCommend() {
                    onCommitCommend(mainCommendBean);
                }

                @Override
                public void onCommendTextChanged(String contend) {
                    mTextView.setText(contend);
                }
            });
            mCommendInputDialog.show(getChildFragmentManager(), mCommendInputDialog.getTag());
        }
    }

    private void onCommitCommend(MainCommendBean mainCommendBean) {
        //如果mainCommendBean為空,表示回復(fù)全部人侦另,提交的評論加到主評論的第一個
        //如果不為空,說明是插入到某一個主評論下的第一個評論
        String content = mTextView.getText().toString();
        if(TextUtils.isEmpty(content)){
            Toast.makeText(App.getInstance(), "數(shù)據(jù)不能為空", Toast.LENGTH_SHORT).show();
            return;
        }
        if(mainCommendBean == null){
            MainCommendBean addMainCommendBean = new MainCommendBean(content);
            mAdapter.addData(0,addMainCommendBean);
            mRecyclerView.smoothScrollToPosition(0);
        }else{
            int index = mAdapter.getData().indexOf(mainCommendBean) + 1;
            ChildCommendBean childCommendBean = new ChildCommendBean(content);
            mAdapter.addData(index,childCommendBean);
        }
        mTextView.setText("");
    }

    @Override
    public void onClick(View view) {
        int id = view.getId();
        if(id == R.id.mTextView){
            showInputDialog(null);
        }else if(id == R.id.mTvSend){
            onCommitCommend(null);
        }
    }

    @Override
    public void onItemClick(MainCommendBean mainCommendBean) {
        showInputDialog(mainCommendBean);
    }
}

樣式:CustomBottomSheetDialogTheme

<style name="CustomBottomSheetDialogTheme" parent="Theme.Design.BottomSheetDialog">
        <item name="android:windowFrame">@null</item>
        <item name="android:windowIsFloating">true</item>
        <item name="android:windowIsTranslucent">true</item>
        <item name="android:background">@android:color/transparent</item>
        <item name="android:windowBackground">@android:color/transparent</item>
        <item name="backgroundColor">@android:color/transparent</item>
        <item name="android:backgroundDimEnabled">false</item>
    </style>

布局:fragment_commend_msg_dialog

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom"
    android:background="@drawable/round_top_12dp_wirth_bg"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    tools:context=".commendDialog.dialog.CommendMsgDialogFragment">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/mRecyclerView"
        android:layout_width="match_parent"
        android:layout_height="400dp"
        app:behavior_hideable="true"
        app:behavior_peekHeight="66dp"
        android:paddingBottom="50dp"
        app:layout_behavior="@string/bottom_sheet_behavior"/>
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="@drawable/storke_line_1dp_dcdcdc"
        android:layout_gravity="bottom"
        app:layout_constraintBottom_toBottomOf="parent">

        <TextView
            android:id="@+id/mTvSend"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            android:layout_marginRight="15dp"
            android:background="@drawable/send_commend_bg"
            android:paddingLeft="15dp"
            android:paddingTop="5dp"
            android:paddingRight="15dp"
            android:paddingBottom="5dp"
            android:text="發(fā)送"
            android:textColor="@android:color/white"
            android:textSize="16sp" />

        <TextView
            android:id="@+id/mTextView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:minHeight="35dp"
            android:background="@drawable/et_search_bg"
            android:layout_toLeftOf="@id/mTvSend"
            android:layout_marginRight="15dp"
            android:layout_centerVertical="true"
            android:layout_marginLeft="15dp"
            android:text=""
            android:gravity="center_vertical"
            android:hint="發(fā)個評論尉共,說不定能火"
            android:paddingTop="3dp"
            android:paddingBottom="3dp"
            android:maxLines="2"
            android:paddingLeft="10dp"
            android:paddingRight="10dp"
            android:textColor="@color/f5f5f5"
            android:textColorHint="@color/f5f5f5"
            android:textSize="14sp" />
    </RelativeLayout>
</FrameLayout>

評論框消失監(jiān)聽:OnDisMissCallBack

public interface OnDisMissCallBack {
    void onDismiss();
}

發(fā)送評論的dialog框:CommendInputDialogFragment

public class CommendInputDialogFragment extends DialogFragment {
    public static final String CONTENT = "content";
    private String mContent;
    private int mAllowableErrorHeight;
    private int mLastDiff = 0;
    public CommendInputDialogFragment() {
    }

    public static CommendInputDialogFragment newInstance(String content) {
        CommendInputDialogFragment fragment = new CommendInputDialogFragment();
        Bundle args = new Bundle();
        args.putString(CONTENT, content);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mContent = getArguments().getString(CONTENT);
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        Window window = getDialog().getWindow();
        super.onActivityCreated(savedInstanceState);
        getDialog().setCancelable(true);
        getDialog().setCanceledOnTouchOutside(true);
        //設(shè)置背景為透明
        window.setWindowAnimations(R.style.AnimBottom);
        window.setBackgroundDrawable(ContextCompat.getDrawable(getContext(), android.R.color.transparent));
        //去除陰影
        window.setGravity(Gravity.BOTTOM);
        WindowManager.LayoutParams layoutParams = window.getAttributes();
        layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
        layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
        layoutParams.dimAmount = 0.3f;
        window.setAttributes(layoutParams);
        window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE|WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
        getDialog().setOnDismissListener(new DialogInterface.OnDismissListener() {
            @Override
            public void onDismiss(DialogInterface dialog) {
                dismissDialog();
            }
        });
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_commend_input_dialog, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        TextView mTvSend = view.findViewById(R.id.mTvSend);
        EditText mEditText = view.findViewById(R.id.mEditText);
        mTvSend.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String content = mEditText.getText().toString();
                if (TextUtils.isEmpty(content)) {
                    Toast.makeText(App.getInstance(), "內(nèi)容不能為空", Toast.LENGTH_SHORT).show();
                    return;
                }
                if (mOnDisMissCallBack != null) {
                    mOnDisMissCallBack.saveCommend();
                }
                dismissDialog();
            }
        });
        //進入褒傅,就要選中輸入框
        mEditText.setFocusable(true);
        mEditText.setFocusableInTouchMode(true);
        mEditText.requestFocus();
        mEditText.postDelayed(new Runnable() {
            @Override
            public void run() {
                InputMethodManager imm = (InputMethodManager) getContext()
                        .getSystemService(Context.INPUT_METHOD_SERVICE);
                imm.toggleSoftInput(0, InputMethodManager.SHOW_FORCED);
                Rect r = new Rect();
                //獲取當(dāng)前界面可視部分
                getActivity().getWindow().getDecorView().getRootView().getWindowVisibleDisplayFrame(r);
                //獲取屏幕的高度
                int screenHeight = getActivity().getWindow().getDecorView().getRootView().getHeight();

                //此處就是用來獲取鍵盤的高度的, 在鍵盤沒有彈出的時候 此高度為0 鍵盤彈出的時候為一個正數(shù)
                mAllowableErrorHeight = screenHeight - r.bottom;
                setOnKeyBordListener();
            }
        },100);
        mEditText.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                String content = mEditText.getText().toString();
                if(mOnDisMissCallBack != null){
                    mOnDisMissCallBack.onCommendTextChanged(content);
                }
            }

            @Override
            public void afterTextChanged(Editable s) {

            }
        });
        //設(shè)置已經(jīng)填過的文字袄友,以及移動光標(biāo)
        mEditText.setText(mContent);
        if(!TextUtils.isEmpty(mContent) && mContent.length() > 0){
            mEditText.setSelection(mContent.length());
        }
    }

    private void setOnKeyBordListener() {
        getActivity().getWindow().getDecorView().addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
            @Override
            public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
                try {
                    Rect r = new Rect();
                    //獲取當(dāng)前界面可視部分
                    getActivity().getWindow().getDecorView().getRootView().getWindowVisibleDisplayFrame(r);
                    //獲取屏幕的高度
                    int screenHeight = getActivity().getWindow().getDecorView().getRootView().getHeight();

                    //此處就是用來獲取鍵盤的高度的殿托, 在鍵盤沒有彈出的時候 此高度為0 鍵盤彈出的時候為一個正數(shù)
                    int heightDifference = screenHeight - r.bottom;
                    if (heightDifference > mAllowableErrorHeight && mLastDiff >= 0) {
                        //開軟鍵盤
                    } else {
                        //關(guān)閉軟鍵盤
                        dismissDialog();
                    }
                    mLastDiff = heightDifference;
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    private void dismissDialog() {
        if (mOnDisMissCallBack != null) {
            mOnDisMissCallBack.onDismiss();
        }
        dismissAllowingStateLoss();
    }

    public interface OnDisMissCallBack {
        void onDismiss();
        void saveCommend();
        void onCommendTextChanged(String contend);
    }

    private OnDisMissCallBack mOnDisMissCallBack;

    public void setOnDisMissCallBack(OnDisMissCallBack mOnDisMissCallBack) {
        this.mOnDisMissCallBack = mOnDisMissCallBack;
    }
}

布局:fragment_commend_input_dialog

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@android:color/white"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    tools:context=".commendDialog.dialog.CommendInputDialogFragment">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="@drawable/storke_line_1dp_dcdcdc"
        android:layout_gravity="bottom"
        app:layout_constraintBottom_toBottomOf="parent">

        <TextView
            android:id="@+id/mTvSend"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="發(fā)送"
            android:textSize="16sp"
            android:textColor="@android:color/white"
            android:paddingTop="5dp"
            android:paddingBottom="5dp"
            android:paddingLeft="15dp"
            android:paddingRight="15dp"
            android:layout_alignParentRight="true"
            android:layout_marginRight="15dp"
            android:layout_centerVertical="true"
            android:background="@drawable/send_commend_bg" />

        <EditText
            android:id="@+id/mEditText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:minHeight="35dp"
            android:background="@drawable/et_search_bg"
            android:layout_toLeftOf="@id/mTvSend"
            android:layout_marginRight="15dp"
            android:layout_centerVertical="true"
            android:layout_marginLeft="15dp"
            android:text=""
            android:gravity="center_vertical"
            android:hint="發(fā)個評論,說不定能火"
            android:paddingTop="3dp"
            android:paddingBottom="3dp"
            android:maxLines="2"
            android:paddingLeft="10dp"
            android:paddingRight="10dp"
            android:textColorHint="@color/f5f5f5"
            android:textColor="@color/f5f5f5"
            android:textSize="14sp" />
    </RelativeLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

數(shù)據(jù)模擬工具:DataTestUtil

public class DataTestUtil {
    Handler handler = null;
    public DataTestUtil() {
        handler = new Handler(Looper.getMainLooper());
    }

    public void getMainCommends(boolean isRefresh,int page,int pageNum,OnMainCommendCallBack callBack){
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                //一定的失敗機率
                Random random = new Random();
                int num = random.nextInt(10);
                if((num % 10 == 1 || num % 10 == 2 || num % 10 == 3) && !isRefresh){
                    if(callBack != null){
                        callBack.onFail();
                    }
                }else {
                    //模擬線上項目的數(shù)據(jù)返回
                    //先返回一部分的主評論剧蚣,子評論也只會先返回一個
                    int start = page * pageNum;
                    List<MainCommendBean> list = new ArrayList<>();
                    for(int x = start; (x < (start + pageNum)); x++){
                        MainCommendBean mainCommendBean = new MainCommendBean("主評論"+x);
                        if(x % 10 == 3){
                            //選擇一部分?jǐn)?shù)據(jù)作為有子數(shù)據(jù)的主評論
                            ChildCommendBean childCommendBean = new ChildCommendBean("子評論0");
                            mainCommendBean.setChildNumber(20);
                            List<ChildCommendBean> childList = new ArrayList<>();
                            childList.add(childCommendBean);
                            mainCommendBean.setChildList(childList);
                        }
                        list.add(mainCommendBean);
                    }
                    if(callBack != null){
                        callBack.onSuccess(isRefresh,list);
                    }
                }
            }
        },500);
    }

    public void getChildCommends(int currentNum,int maxChildNum,OnChildCommendCallBack onChildCommendCallBack){
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                int start = currentNum;
                List<ChildCommendBean> list = new ArrayList<>();
                for(int x = start; (x < (currentNum + 5) && x < (maxChildNum)); x++){
                    ChildCommendBean childCommendBean = new ChildCommendBean("子評論"+x);
                    list.add(childCommendBean);
                }
                if(onChildCommendCallBack != null){
                    onChildCommendCallBack.onSuccess(list);
                }
            }
        },500);
    }
}

二級評論數(shù)據(jù)回調(diào)接口:OnChildCommendCallBack

public interface OnChildCommendCallBack {
    void onSuccess(List<ChildCommendBean> list);
}

一級評論數(shù)據(jù)回調(diào)接口:OnMainCommendCallBack

public interface OnMainCommendCallBack {
    void onSuccess(boolean isRefresh, List<MainCommendBean> list);
    void onFail();
}

一級評論JavaBean:MainCommendBean

public class MainCommendBean extends AbstractExpandableItem<MultiItemEntity> implements MultiItemEntity {
    private String content;
    private List<ChildCommendBean> childList = new ArrayList<>();
    private int childNumber = 0;

    public MainCommendBean(String content) {
        this.content = content;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public List<ChildCommendBean> getChildList() {
        return childList;
    }

    public void setChildList(List<ChildCommendBean> childList) {
        this.childList = childList;
    }

    public int getChildNumber() {
        return childNumber;
    }

    public void setChildNumber(int childNumber) {
        this.childNumber = childNumber;
    }

    @Override
    public int getLevel() {
        return 0;
    }

    @Override
    public int getItemType() {
        return CommendAdapter.MAIN_COMMEND;
    }
}

二級評論javabean:ChildCommendBean

public class ChildCommendBean implements MultiItemEntity {
    private String content;

    public ChildCommendBean(String content) {
        this.content = content;
    }


    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    @Override
    public int getItemType() {
        return CommendAdapter.CHILD_COMMEND;
    }
}

加載更多Javabean:MoreCommendBean

public class MoreCommendBean implements MultiItemEntity {
    public boolean isLoading = false;//有沒有在加載數(shù)據(jù)支竹,他控制加載更多條目的loading控件的展示。
    private MainCommendBean mainCommendBean;
    private boolean isZheDie = true;//是否是折疊狀態(tài)
    private boolean isLoaded = false;//全部子view是否已經(jīng)加載完成鸠按。
    private List<ChildCommendBean> subList = new ArrayList<>();//除了開始的時候展示的一條礼搁,后面加入的新的,都存放在這

    public List<ChildCommendBean> getSubList() {
        return subList;
    }

    public boolean isLoaded() {
        return isLoaded;
    }

    public void setLoaded(boolean loaded) {
        isLoaded = loaded;
    }

    public boolean isZheDie() {
        return isZheDie;
    }

    public void setZheDie(boolean zheDie) {
        isZheDie = zheDie;
    }

    public MainCommendBean getMainCommendBean() {
        return mainCommendBean;
    }

    public void setMainCommendBean(MainCommendBean mainCommendBean) {
        this.mainCommendBean = mainCommendBean;
    }

    @Override
    public int getItemType() {
        return CommendAdapter.MORE_COMMEND;
    }
}

評論列表適配器:CommendAdapter

public class CommendAdapter extends BaseMultiItemQuickAdapter<MultiItemEntity, BaseViewHolder> {
    public static final int MAIN_COMMEND = 0;
    public static final int CHILD_COMMEND = 1;
    public static final int MORE_COMMEND = 2;
    private OnClickLoadMoreChildCallBack onClickLoadMoreChildCallBack;
    private OnCommendItemClickCallBack onCommendItemClickCallBack;

    public CommendAdapter(List<MultiItemEntity> data) {
        super(data);
        addItemType(MAIN_COMMEND, R.layout.main_commend_layout);
        addItemType(CHILD_COMMEND, R.layout.child_commend_layout);
        addItemType(MORE_COMMEND,R.layout.more_commend_layout);
    }

    public void setOnClickLoadMoreChildCallBack(OnClickLoadMoreChildCallBack onClickLoadMoreChildCallBack) {
        this.onClickLoadMoreChildCallBack = onClickLoadMoreChildCallBack;
    }

    public void setOnCommendItemClickCallBack(OnCommendItemClickCallBack onCommendItemClickCallBack) {
        this.onCommendItemClickCallBack = onCommendItemClickCallBack;
    }

    @Override
    protected void convert(@NonNull BaseViewHolder helper, MultiItemEntity item) {
        if(helper.getItemViewType() == MAIN_COMMEND){
            MainCommendBean mainCommendBean = (MainCommendBean) item;
            TextView tvCommentContent = helper.getView(R.id.tvCommentContent);
            tvCommentContent.setText(mainCommendBean.getContent());
            helper.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    if(onCommendItemClickCallBack != null){
                        onCommendItemClickCallBack.onItemClick(mainCommendBean);
                    }
                }
            });
        }else if(helper.getItemViewType() == CHILD_COMMEND){
            int position = getParentPositionInAll(helper.getAdapterPosition());
            MultiItemEntity multiItemEntity = getData().get(position);
            ChildCommendBean childCommendBean = (ChildCommendBean) item;
            TextView tvCommentContent = helper.getView(R.id.tvCommentContent);
            tvCommentContent.setText(childCommendBean.getContent());
            helper.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    if(onCommendItemClickCallBack != null){
                        onCommendItemClickCallBack.onItemClick((MainCommendBean) multiItemEntity);
                    }
                }
            });
        }else if(helper.getItemViewType() == MORE_COMMEND){
            TextView tvExpandNum = helper.getView(R.id.tvExpandNum);
            ProgressBar loadingImageView = helper.getView(R.id.loadingImageView);
            MoreCommendBean moreCommendBean = (MoreCommendBean) item;
            setLoadingState(tvExpandNum,loadingImageView,moreCommendBean);

            setTipsText(tvExpandNum,moreCommendBean);
            tvExpandNum.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    if(onClickLoadMoreChildCallBack != null){
                        onClickLoadMoreChildCallBack.onClickMoreChild(tvExpandNum,loadingImageView,moreCommendBean);
                    }
                }
            });
        }
    }

    /**
     * 設(shè)置折疊條目的文案
     * @param tvExpandNum
     * @param moreCommendBean
     */
    private void setTipsText(TextView tvExpandNum, MoreCommendBean moreCommendBean) {
        if(moreCommendBean.isZheDie()){
            int number = 0;
            if(!moreCommendBean.isLoaded()){
                //沒有全部加載完成的話目尖,剩余條目就是全部子條目的數(shù)目減去已經(jīng)加載了的子條目數(shù)目
                number  = moreCommendBean.getMainCommendBean().getChildNumber() - moreCommendBean.getMainCommendBean().getChildList().size();
            }else{
                //全部都加在過了馒吴,那么提示的條目就應(yīng)該是后續(xù)額外請求網(wǎng)絡(luò)數(shù)據(jù)加載的子條目數(shù)
                number = moreCommendBean.getSubList().size();
            }
            tvExpandNum.setText("展開剩余"+number+"條評論");
        }else{
            tvExpandNum.setText("收起");
        }
    }

    /**
     * 設(shè)置加載狀態(tài),由于recycleview的復(fù)用,
     * 所以我們要每次加載數(shù)據(jù)饮戳,就要判斷一下該條目是否在加載
     * @param tvExpandNum
     * @param loadingImageView
     * @param moreCommendBean
     */
    private void setLoadingState(TextView tvExpandNum, ProgressBar loadingImageView,MoreCommendBean moreCommendBean) {
        if(moreCommendBean.isLoading){
            tvExpandNum.setVisibility(View.GONE);
            loadingImageView.setVisibility(View.VISIBLE);
        }else{
            tvExpandNum.setVisibility(View.VISIBLE);
            loadingImageView.setVisibility(View.GONE);
        }
    }
}

一級評論布局:main_commend_layout

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="8dp"
    android:layout_marginBottom="7dp"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto">


    <ImageView
        android:id="@+id/imgAvatar"
        android:layout_width="36dp"
        android:layout_height="36dp"
        android:layout_marginStart="12dp"
        android:src="@mipmap/ic_launcher"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/tvCommentNickname"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="8dp"
        android:tag="binding_3"
        android:text="小豬喬治"
        android:textColor="@color/ff333333"
        android:textSize="12sp"
        app:layout_constraintLeft_toRightOf="@+id/imgAvatar"
        app:layout_constraintTop_toTopOf="@+id/imgAvatar" />

    <TextView
        android:id="@+id/tvCommentTagAuthor"
        android:layout_width="28dp"
        android:layout_height="14dp"
        android:layout_marginLeft="2dp"
        android:layout_marginTop="2dp"
        android:layout_marginBottom="3dp"
        android:background="@drawable/community_focus_shape_orange_2"
        android:gravity="center"
        android:tag="binding_4"
        android:text="@string/author"
        android:textColor="@color/mainColor"
        android:textSize="10sp"
        app:layout_constraintLeft_toRightOf="@+id/tvCommentNickname"
        app:layout_constraintTop_toTopOf="@+id/tvCommentNickname" />

    <TextView
        android:id="@+id/tvTime"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="4dp"
        android:text="2021-05-24"
        android:textColor="@color/ccccccc"
        android:textSize="11sp"
        app:layout_constraintBottom_toBottomOf="@+id/tvCommentNickname"
        app:layout_constraintLeft_toRightOf="@+id/tvCommentTagAuthor"
        app:layout_constraintTop_toTopOf="@+id/tvCommentNickname" />

    <ImageView
        android:id="@+id/imageLike"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="parent"
        android:paddingEnd="12dp"
        android:paddingStart="12dp"
        app:layout_constraintTop_toTopOf="@+id/tvCommentNickname"
        android:src="@mipmap/community_found_icon_comment_line_love"/>
    <TextView
        android:id="@+id/tvCommentLike"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        tools:text="3456"
        android:textColor="@color/ff666666"
        android:textSize="11sp"
        app:layout_constraintStart_toStartOf="@+id/imageLike"
        app:layout_constraintEnd_toEndOf="@+id/imageLike"
        app:layout_constraintTop_toBottomOf="@+id/imageLike" />

    <TextView
        android:id="@+id/tvCommentContent"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="5dp"
        android:layout_marginEnd="56dp"
        tools:text="我覺得小餅干簡直是人間美味啊~"
        android:textColor="@color/ff666666"
        android:textSize="13sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/imgAvatar"
        app:layout_constraintTop_toBottomOf="@+id/tvCommentNickname" />
</androidx.constraintlayout.widget.ConstraintLayout>

二級評論布局:child_commend_layout

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="8dp"
    android:layout_marginBottom="7dp"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <ImageView
        android:id="@+id/imgAvatar"
        android:layout_width="24dp"
        android:layout_height="24dp"
        android:layout_marginStart="56dp"
        android:src="@mipmap/ic_launcher"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

    <TextView
        android:id="@+id/tvCommentNickname"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="8dp"
        android:tag="binding_3"
        android:text="小豬喬治"
        android:textColor="@color/ff333333"
        android:textSize="12sp"
        app:layout_constraintLeft_toRightOf="@+id/imgAvatar"
        app:layout_constraintTop_toTopOf="@+id/imgAvatar" />

    <TextView
        android:id="@+id/tvCommentTagAuthor"
        android:layout_width="28dp"
        android:layout_height="14dp"
        android:layout_marginLeft="2dp"
        android:layout_marginTop="2dp"
        android:layout_marginBottom="3dp"
        android:background="@drawable/community_focus_shape_orange_2"
        android:gravity="center"
        android:tag="binding_4"
        android:text="@string/author"
        android:textColor="@color/mainColor"
        android:textSize="10sp"
        app:layout_constraintLeft_toRightOf="@+id/tvCommentNickname"
        app:layout_constraintTop_toTopOf="@+id/tvCommentNickname" />

    <TextView
        android:id="@+id/tvTime"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="@dimen/dp_4"
        tools:text="2021-05-24"
        android:textColor="@color/ccccccc"
        android:textSize="11sp"
        app:layout_constraintBottom_toBottomOf="@+id/tvCommentNickname"
        app:layout_constraintLeft_toRightOf="@+id/tvCommentTagAuthor"
        app:layout_constraintTop_toTopOf="@+id/tvCommentNickname" />


    <ImageView
        android:id="@+id/imageLike"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="parent"
        android:paddingEnd="12dp"
        android:paddingStart="12dp"
        app:layout_constraintTop_toTopOf="@+id/tvCommentNickname"
        android:src="@mipmap/community_found_icon_comment_line_love"/>
    <TextView
        android:id="@+id/tvCommentLike"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        tools:text="3456"
        android:textColor="@color/ff666666"
        android:textSize="11sp"
        app:layout_constraintStart_toStartOf="@+id/imageLike"
        app:layout_constraintEnd_toEndOf="@+id/imageLike"
        app:layout_constraintTop_toBottomOf="@+id/imageLike" />

    <TextView
        android:id="@+id/tvCommentContent"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:layout_marginEnd="56dp"
        tools:text="我覺得小餅干簡直是人間美味啊~"
        android:textColor="@color/ff666666"
        android:textSize="13sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="@+id/tvCommentNickname"
        app:layout_constraintTop_toBottomOf="@+id/tvCommentNickname" />

</androidx.constraintlayout.widget.ConstraintLayout>

加載更多布局:more_commend_layout

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <TextView
        android:id="@+id/tvExpandNum"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:textSize="11sp"
        android:layout_marginStart="56dp"
        android:textColor="@color/ff333333"
        android:paddingTop="6dp"
        android:paddingBottom="7dp"
        android:drawablePadding="@dimen/dp_4"
        android:visibility="gone"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:drawableEnd="@mipmap/community_icon_common_down_white"/>
    <ProgressBar
        android:id="@+id/loadingImageView"
        android:layout_width="25dp"
        android:layout_height="25dp"
        app:layout_constraintStart_toStartOf="parent"
        android:visibility="gone"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="11dp"
        app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>

加載更多點擊回調(diào):OnClickLoadMoreChildCallBack

public interface OnClickLoadMoreChildCallBack {
    void onClickMoreChild(TextView tvExpandNum, ProgressBar loadingImageView, MoreCommendBean moreCommendBean);
}

一級豪治、二級評論被點擊時回調(diào):OnCommendItemClickCallBack

public interface OnCommendItemClickCallBack {
    void onItemClick(MainCommendBean mainCommendBean);
}

然后在activity里面點擊一個按鈕彈出對話框

class CommendDialogActivity : AppCompatActivity() {
    private var mCommendMsgDialogFragment:CommendMsgDialogFragment? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_commend_dialog)
        mBtnCommend?.setOnClickListener {
            if (mCommendMsgDialogFragment == null) {
                 mCommendMsgDialogFragment = CommendMsgDialogFragment.newInstance()
                mCommendMsgDialogFragment?.setOnDisMissCallBack { mCommendMsgDialogFragment = null }
                mCommendMsgDialogFragment?.show(supportFragmentManager,mCommendMsgDialogFragment?.tag)
            }
        }
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市扯罐,隨后出現(xiàn)的幾起案子负拟,更是在濱河造成了極大的恐慌,老刑警劉巖歹河,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件掩浙,死亡現(xiàn)場離奇詭異,居然都是意外死亡启泣,警方通過查閱死者的電腦和手機涣脚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來寥茫,“玉大人遣蚀,你說我怎么就攤上這事∩闯埽” “怎么了芭梯?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長弄喘。 經(jīng)常有香客問我玖喘,道長,這世上最難降的妖魔是什么蘑志? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任累奈,我火速辦了婚禮,結(jié)果婚禮上急但,老公的妹妹穿的比我還像新娘澎媒。我一直安慰自己,他們只是感情好波桩,可當(dāng)我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布戒努。 她就那樣靜靜地躺著,像睡著了一般镐躲。 火紅的嫁衣襯著肌膚如雪储玫。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天萤皂,我揣著相機與錄音撒穷,去河邊找鬼。 笑死敌蚜,一個胖子當(dāng)著我的面吹牛桥滨,可吹牛的內(nèi)容都是我干的窝爪。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼齐媒,長吁一口氣:“原來是場噩夢啊……” “哼蒲每!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起喻括,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤邀杏,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后唬血,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體望蜡,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年拷恨,在試婚紗的時候發(fā)現(xiàn)自己被綠了脖律。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡腕侄,死狀恐怖小泉,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情冕杠,我是刑警寧澤微姊,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站分预,受9級特大地震影響兢交,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜笼痹,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一配喳、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧凳干,春花似錦界逛、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽溉潭。三九已至净响,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間喳瓣,已是汗流浹背馋贤。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留畏陕,地道東北人配乓。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親犹芹。 傳聞我的和親對象是個殘疾皇子崎页,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,592評論 2 353

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