之前写过一篇类似的文章,但是只有dialog的部分,链接:https://www.jianshu.com/p/c1941eee0c4a
当时想的是难点在框框,其他的都还好,什么二级评论写起来容易,以后遇到也不怕,所以没进一步写,结果现在看别人的东西,自己又想去写的时候,发现不一般啊,第一天的时候居然没写出来。所以记录一下,目的不为别的,就怕以后在遇到,能拿过来就用。
demo的功能范围:
1、评论框BottomSheetDialogFragment的设置,能滑动隐藏dialog。
2、一级评论二级评论的加载,二级评论的加载更多与收起功能。
3、评论记载失败一级加载更多处理。
4、发送模拟新主评论,以及回复他人评论
这次主要做二级评论,和抖音一样能加载跟多子评论加载完全部,能收起。
demo的设定是一条一级评论,如果他有二级评论,并且二级评论数量超过1条时就会出现加载更多条目。
我分析的结论是有两种做法:
1、对于一条评论体来说,我们可以把里面的二级评论看做是一个子recycleview,二级评论的加载更多条目可以用底部布局来写,就相当于一个大recycleview来展示所有一级评论,然后每一条一级评论里面可能有一个次recycleview。这样做的话,就是recycleview的复用需要好好处理了。
2、不采用嵌套的recycleview的方式,把一级评论、二级评论加载更多条目三种都看做是recycleview的条目,给他们设定itemType类型,分别展示。这个需要处理好加载更多时,插入位置的计算。
权衡利弊,demo采用了第二种。第一种我也会去做,但是可能不会发出来。
说到给recycleview分类,那肯定用BaseRecyclerViewAdapterHelper更方便。可惜的是项目里面用的是2.x的版本,没有3.x的,它的3.x版本有node模式,解决这种二级列表问题更快,demo为了更好的模拟项目,也就用了2.x版本。
数据方面,好好思考一下一级,二级,加载更多的javabean结构。这里我模拟了公司后台返回的数据模型。
一级评论:MainCommendBean
数据体:返回评论文字内容、所有子评论数量、当前默认需要展示的二级评论集合(默认先展示一条二级评论,所以默认集合大小为1)。
二级评论:ChildCommendBean
数据体:返回评论文字内容
加载更多评论条目:MoreCommendBean(这个后台不会返回,是我们拿到数据后自己往数据里面加,主要是为了持有一级评论,方便逻辑判断)
数据体:对应的一级评论引用、点击加载更多二级评论存放的集合。
好累啊,直接上代码把。
主要评论框: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);
//设置背景为透明
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();//初始模拟数据工具
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();
}
}
});
}
/**
* 转换并且设置二级数据
* @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){
//如果有子回复,需要绑定
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);
}
}
/**
* 网络上的数据加载
* @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) {
//没加载完全部,就去网络
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);
}
});
}
/**
* 网上数据全部加载完了,下次再点击暂开收起,数据就是本地的
* 新加入的子评论都在moreCommendBean.getSubList里面
*/
private void loadChildCommendFromLocal(MoreCommendBean moreCommendBean) {
if(moreCommendBean.isZheDie()){
//加载完了,就不要网络加载了,去本地
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为空,表示回复全部人,提交的评论加到主评论的第一个
//如果不为空,说明是插入到某一个主评论下的第一个评论
String content = mTextView.getText().toString();
if(TextUtils.isEmpty(content)){
Toast.makeText(App.getInstance(), "数据不能为空", 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="发送"
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="发个评论,说不定能火"
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>
评论框消失监听:OnDisMissCallBack
public interface OnDisMissCallBack {
void onDismiss();
}
发送评论的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);
//设置背景为透明
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(), "内容不能为空", 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();
//获取当前界面可视部分
getActivity().getWindow().getDecorView().getRootView().getWindowVisibleDisplayFrame(r);
//获取屏幕的高度
int screenHeight = getActivity().getWindow().getDecorView().getRootView().getHeight();
//此处就是用来获取键盘的高度的, 在键盘没有弹出的时候 此高度为0 键盘弹出的时候为一个正数
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) {
}
});
//设置已经填过的文字,以及移动光标
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();
//获取当前界面可视部分
getActivity().getWindow().getDecorView().getRootView().getWindowVisibleDisplayFrame(r);
//获取屏幕的高度
int screenHeight = getActivity().getWindow().getDecorView().getRootView().getHeight();
//此处就是用来获取键盘的高度的, 在键盘没有弹出的时候 此高度为0 键盘弹出的时候为一个正数
int heightDifference = screenHeight - r.bottom;
if (heightDifference > mAllowableErrorHeight && mLastDiff >= 0) {
//开软键盘
} else {
//关闭软键盘
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="发送"
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="发个评论,说不定能火"
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>
数据模拟工具: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 {
//模拟线上项目的数据返回
//先返回一部分的主评论,子评论也只会先返回一个
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){
//选择一部分数据作为有子数据的主评论
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);
}
}
二级评论数据回调接口:OnChildCommendCallBack
public interface OnChildCommendCallBack {
void onSuccess(List<ChildCommendBean> list);
}
一级评论数据回调接口: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;//有没有在加载数据,他控制加载更多条目的loading控件的展示。
private MainCommendBean mainCommendBean;
private boolean isZheDie = true;//是否是折叠状态
private boolean isLoaded = false;//全部子view是否已经加载完成。
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);
}
}
});
}
}
/**
* 设置折叠条目的文案
* @param tvExpandNum
* @param moreCommendBean
*/
private void setTipsText(TextView tvExpandNum, MoreCommendBean moreCommendBean) {
if(moreCommendBean.isZheDie()){
int number = 0;
if(!moreCommendBean.isLoaded()){
//没有全部加载完成的话,剩余条目就是全部子条目的数目减去已经加载了的子条目数目
number = moreCommendBean.getMainCommendBean().getChildNumber() - moreCommendBean.getMainCommendBean().getChildList().size();
}else{
//全部都加在过了,那么提示的条目就应该是后续额外请求网络数据加载的子条目数
number = moreCommendBean.getSubList().size();
}
tvExpandNum.setText("展开剩余"+number+"条评论");
}else{
tvExpandNum.setText("收起");
}
}
/**
* 设置加载状态,由于recycleview的复用,
* 所以我们要每次加载数据,就要判断一下该条目是否在加载
* @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>
加载更多点击回调:OnClickLoadMoreChildCallBack
public interface OnClickLoadMoreChildCallBack {
void onClickMoreChild(TextView tvExpandNum, ProgressBar loadingImageView, MoreCommendBean moreCommendBean);
}
一级、二级评论被点击时回调: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)
}
}
}
}