之前寫過一篇類似的文章,但是只有dialog的部分,鏈接:http://www.reibang.com/p/c1941eee0c4a
當(dāng)時想的是難點在框框偷厦,其他的都還好,什么二級評論寫起來容易司忱,以后遇到也不怕北秽,所以沒進一步寫,結(jié)果現(xiàn)在看別人的東西了袁,自己又想去寫的時候朗恳,發(fā)現(xiàn)不一般啊,第一天的時候居然沒寫出來载绿。所以記錄一下粥诫,目的不為別的,就怕以后在遇到崭庸,能拿過來就用怀浆。
demo的功能范圍:
1、評論框BottomSheetDialogFragment的設(shè)置怕享,能滑動隱藏dialog执赡。
2、一級評論二級評論的加載函筋,二級評論的加載更多與收起功能沙合。
3、評論記載失敗一級加載更多處理跌帐。
4首懈、發(fā)送模擬新主評論绊率,以及回復(fù)他人評論
這次主要做二級評論,和抖音一樣能加載跟多子評論加載完全部猜拾,能收起即舌。
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)
}
}
}
}