首先说说数据源
{
"data": [{
"id": 3,
"tname": "【成人票】小七孔门票1+划船+小吃",
"desc": "正常门票,划船项目,各种小吃饮料",
"price": "150.00",
"marketp": "198.00",
"couponinfo": [{
"id": 3,
"cname": "荔波景区专属--现金优惠券30元",
"desc": "荔波景区专属--现金优惠券30元",
"type": 1,
"price": 30,
"start": "2018-12-27",
"end": "2019-01-11",
"limit": 1,
"cash": 2,
"fullprice": null
}, {
"id": 4,
"cname": "元旦优惠来就打折--8折优惠券",
"desc": "元旦优惠来就打折--8折优惠券",
"type": 2,
"price": 8,
"start": "2018-12-31",
"end": "2019-01-12",
"limit": 1,
"cash": 1,
"fullprice": null
}, {
"id": 5,
"cname": "黄果树春节活动--满350立减50",
"desc": "黄果树春节活动--满350立减50",
"type": 3,
"price": 50,
"start": "2019-01-01",
"end": "2019-02-28",
"limit": 1,
"cash": null,
"fullprice": 300
}]
}, {
"id": 6,
"tname": "【成人票】小七孔门票+茂兰风景区门票",
"desc": "【成人票】小七孔门票+茂兰风景区门票",
"price": "200.00",
"marketp": "299.00",
"couponinfo": [{
"id": 5,
"cname": "黄果树春节活动--满350立减50",
"desc": "黄果树春节活动--满350立减50",
"type": 3,
"price": 50,
"start": "2019-01-01",
"end": "2019-02-28",
"limit": 1,
"cash": null,
"fullprice": 300
}]
}],
"msg": "获取成功",
"code": 1
}
看到数据源为两个listjson数组
效果为这样
布局中定义
首先,我们需要在xml的布局文件中声明ExpandableListView:
<ExpandableListView
android:id="@+id/detail_page_lv_comment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@null"
android:layout_marginBottom="64dp"
android:listSelector="@android:color/transparent"
android:scrollbars="none"/>
这里需要说明两个问题:
- ExpandableListView默认为它的item加上了点击效果,由于item里面还包含了childItem,所以,点击后,整个item里面的内容都会有点击效果。我们可以取消其点击特效,避免其影响用户体验,只需要设置如上代码中的listSelector即可。
- ExpandableListView具有默认的分割线,可以通过divider属性将其隐藏。
正如使用listView那样,我们需要为ExpandableListView设置一个适配器Adapter,为其绑定数据和视图。ExpandableListView的adapter需要继承自ExpandableListAdapter,具体代码如下:
/**
* Author: Moos
* E-mail: [email protected]
* Date: 18/4/20.
* Desc: 评论与回复列表的适配器
*/
public class CommentExpandAdapter extends BaseExpandableListAdapter {
private static final String TAG = "CommentExpandAdapter";
private List<CommentDetailBean> commentBeanList;
private Context context;
public CommentExpandAdapter(Context context, List<CommentDetailBean> commentBeanList) {
this.context = context;
this.commentBeanList = commentBeanList;
}
@Override
public int getGroupCount() {
return commentBeanList.size();
}
@Override
public int getChildrenCount(int i) {
if(commentBeanList.get(i).getReplyList() == null){
return 0;
}else {
return commentBeanList.get(i).getReplyList().size()>0 ? commentBeanList.get(i).getReplyList().size():0;
}
}
@Override
public Object getGroup(int i) {
return commentBeanList.get(i);
}
@Override
public Object getChild(int i, int i1) {
return commentBeanList.get(i).getReplyList().get(i1);
}
@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return getCombinedChildId(groupPosition, childPosition);
}
@Override
public boolean hasStableIds() {
return true;
}
boolean isLike = false;
@Override
public View getGroupView(final int groupPosition, boolean isExpand, View convertView, ViewGroup viewGroup) {
final GroupHolder groupHolder;
if(convertView == null){
convertView = LayoutInflater.from(context).inflate(R.layout.comment_item_layout, viewGroup, false);
groupHolder = new GroupHolder(convertView);
convertView.setTag(groupHolder);
}else {
groupHolder = (GroupHolder) convertView.getTag();
}
Glide.with(context).load(R.drawable.user_other)
.diskCacheStrategy(DiskCacheStrategy.RESULT)
.error(R.mipmap.ic_launcher)
.centerCrop()
.into(groupHolder.logo);
groupHolder.tv_name.setText(commentBeanList.get(groupPosition).getNickName());
groupHolder.tv_time.setText(commentBeanList.get(groupPosition).getCreateDate());
groupHolder.tv_content.setText(commentBeanList.get(groupPosition).getContent());
groupHolder.iv_like.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(isLike){
isLike = false;
groupHolder.iv_like.setColorFilter(Color.parseColor("#aaaaaa"));
}else {
isLike = true;
groupHolder.iv_like.setColorFilter(Color.parseColor("#FF5C5C"));
}
}
});
return convertView;
}
@Override
public View getChildView(final int groupPosition, int childPosition, boolean b, View convertView, ViewGroup viewGroup) {
final ChildHolder childHolder;
if(convertView == null){
convertView = LayoutInflater.from(context).inflate(R.layout.comment_reply_item_layout,viewGroup, false);
childHolder = new ChildHolder(convertView);
convertView.setTag(childHolder);
}
else {
childHolder = (ChildHolder) convertView.getTag();
}
String replyUser = commentBeanList.get(groupPosition).getReplyList().get(childPosition).getNickName();
if(!TextUtils.isEmpty(replyUser)){
childHolder.tv_name.setText(replyUser + ":");
}
childHolder.tv_content.setText(commentBeanList.get(groupPosition).getReplyList().get(childPosition).getContent());
return convertView;
}
@Override
public boolean isChildSelectable(int i, int i1) {
return true;
}
private class GroupHolder{
private CircleImageView logo;
private TextView tv_name, tv_content, tv_time;
private ImageView iv_like;
public GroupHolder(View view) {
logo = view.findViewById(R.id.comment_item_logo);
tv_content = view.findViewById(R.id.comment_item_content);
tv_name = view.findViewById(R.id.comment_item_userName);
tv_time = view.findViewById(R.id.comment_item_time);
iv_like = view.findViewById(R.id.comment_item_like);
}
}
private class ChildHolder{
private TextView tv_name, tv_content;
public ChildHolder(View view) {
tv_name = (TextView) view.findViewById(R.id.reply_item_user);
tv_content = (TextView) view.findViewById(R.id.reply_item_content);
}
}
}
- getGroupCount,返回group分组的数量,在当前需求中指代评论的数量。
- getChildrenCount,返回所在group中child的数量,这里指代当前评论对应的回复数目。
- getGroup,返回group的实际数据,这里指的是当前评论数据。
- getChild,返回group中某个child的实际数据,这里指的是当前评论的某个回复数据。
- getGroupId,返回分组的id,一般将当前group的位置传给它。
- getChildId,返回分组中某个child的id,一般也将child当前位置传给它,不过为了避免重复,可以使用
getCombinedChildId(groupPosition, childPosition);
来获取id并返回。 - hasStableIds,表示分组和子选项是否持有稳定的id,这里返回true即可。
- isChildSelectable,表示分组中的child是否可以选中,这里返回true。
- getGroupView,即返回group的视图,一般在这里进行一些数据和视图绑定的工作,一般为了复用和高效,可以自定义ViewHolder,用法与listview一样,这里就不多说了。
- getChildView,返回分组中child子项的视图,比较容易理解,第一个参数是当前group所在的位置,第二个参数是当前child所在位置。
源码