一、效果图展示
二、思路分析
首先,上效果图,这样的评论界面很常见,日常新闻,社交等类的app中都有评论功能,今天就来看看怎么实现?
实现这种效果并不难,首先最外层肯定是Recycleview
,然后设置他的Adapter来实现,重点在于Adapter的实现。
三、准备
1.首先,得有一个评论javaBean
类,用来封装评论信息,当然这些信息在开发中都是从服务器端获取的,这个类为CommentBean
,代码如下:
public class CommentBean {
/**
* author : xiaowei
* content : 正解啊,比如中午登机,早上不吃空腹上,到时候飞机餐就算是两个圆圆的小面包都吃得有滋有味!开始怀疑,到底是飞机旅行、真是高大上呀!??哈哈…我见不少人特意留着飞机上发的食物带回去,落地后送人吃,很拽的来一句:飞机食品哦!…笑得不行鸟
* avatar : http://pic1.zhimg.com/da8e974dc_im.jpg
* time : 1413603692
* reply_to : {"content":"习惯就好了。。 国内的航空公司基本都刷过。。 掌握了\u201c让飞机餐变得非常好吃\u201d的秘诀 同学们准备好 秘诀就是〈饿半天肚子登机〉 等到你吃到飞机餐那刻会泪流满面\u2026\u2026 好吧说了那么多其实也就因为六个字 没钱\u2026没钱\u2026没钱 所以,努力当大爷自己买小飞机吧!","status":0,"id":545589,"author":"Samuelback"}
* id : 545838
* likes : 2
*/
private List<CommentsBean> comments;
public List<CommentsBean> getComments() {
return comments;
}
public void setComments(List<CommentsBean> comments) {
this.comments = comments;
}
public static class CommentsBean {
private String author;
private String content;
private String avatar;
private int time;
/**
* content : 习惯就好了。。 国内的航空公司基本都刷过。。 掌握了“让飞机餐变得非常好吃”的秘诀 同学们准备好 秘诀就是〈饿半天肚子登机〉 等到你吃到飞机餐那刻会泪流满面…… 好吧说了那么多其实也就因为六个字 没钱…没钱…没钱 所以,努力当大爷自己买小飞机吧!
* status : 0
* id : 545589
* author : Samuelback
*/
private ReplyToBean reply_to;
private int id;
private int likes;
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getAvatar() {
return avatar;
}
public void setAvatar(String avatar) {
this.avatar = avatar;
}
public int getTime() {
return time;
}
public void setTime(int time) {
this.time = time;
}
public ReplyToBean getReply_to() {
return reply_to;
}
public void setReply_to(ReplyToBean reply_to) {
this.reply_to = reply_to;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getLikes() {
return likes;
}
public void setLikes(int likes) {
this.likes = likes;
}
public static class ReplyToBean {
private String content;
private int status;
private int id;
private String author;
private int expandState = 0;
public int getExpandState() {
return expandState;
}
public void setExpandState(int expandState) {
this.expandState = expandState;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
}
}
}
2.然后,开始编写itme_comment.xml
文件,用来提供给Adapter的每一个item
xml代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:paddingTop="12dp"
android:paddingLeft="12dp"
android:paddingRight="12dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.codeest.geeknews.widget.CircleImageView
android:id="@+id/civ_comment_face"
android:layout_marginEnd="10dp"
android:layout_width="@dimen/comment_face_size"
android:layout_height="@dimen/comment_face_size"/>
<LinearLayout
android:orientation="vertical"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tv_comment_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textStyle="bold"/>
<TextView
android:id="@+id/tv_comment_content"
android:textColor="@color/comment_text"
android:textSize="14sp"
android:layout_marginTop="8dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:lineSpacingMultiplier="1.3"
/>
<TextView
android:id="@+id/tv_comment_reply"
android:textColor="@color/comment_reply"
android:ellipsize="end"
android:layout_marginTop="8dp"
android:background="@drawable/reply_bg"
android:paddingStart="6dp"
android:lineSpacingMultiplier="1.2"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:layout_marginBottom="12dp"
>
<TextView
android:id="@+id/tv_comment_time"
android:layout_alignParentStart="true"
android:textColor="@color/comment_btn"
android:layout_centerVertical="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:layout_toEndOf="@id/tv_comment_time"
android:layout_marginStart="10dp"
android:id="@+id/tv_comment_expand"
android:text="@string/comment_expand"
android:layout_centerVertical="true"
android:textColor="@color/comment_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/tv_comment_like"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginEnd="10dp"
android:textColor="@color/comment_btn"
android:drawableLeft="@mipmap/ic_daily_like"
android:drawablePadding="5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="@color/comment_line"/>
</LinearLayout>
</LinearLayout>
四,重点CommentAdapter
public class CommentAdapter extends RecyclerView.Adapter<CommentAdapter.ViewHolder>{
private LayoutInflater inflater;
private List<CommentBean.CommentsBean> mList;
private Context mContext;
private static final int STATE_NULL = 0; //未知
private static final int STATE_NONE = 1; //无需展开
private static final int STATE_EXPAND = 2; //已展开
private static final int STATE_SHRINK = 3; //已收缩
private static final int MAX_LINE = 2; //起始最多显示2行
public CommentAdapter(Context mContext,List<CommentBean.CommentsBean> mList) {
this.mList = mList;
this.mContext = mContext;
inflater = LayoutInflater.from(mContext);
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ViewHolder(inflater.inflate(R.layout.item_comment,parent,false));
}
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
CommentBean.CommentsBean info = mList.get(position);
ImageLoader.load(mContext,info.getAvatar(),holder.civFace);
holder.tvName.setText(info.getAuthor());
holder.tvContent.setText(info.getContent());
holder.tvTime.setText(DateUtil.formatTime2String(info.getTime()));
holder.tvLike.setText(String.valueOf(info.getLikes()));
if (info.getReply_to() != null && info.getReply_to().getId() != 0) {
holder.tvReply.setVisibility(View.VISIBLE);
SpannableString ss = new SpannableString("@" + info.getReply_to().getAuthor() + ": " + info.getReply_to().getContent());
ss.setSpan(new ForegroundColorSpan(ContextCompat.getColor(mContext,R.color.comment_at)), 0,info.getReply_to().getAuthor().length() + 2 , Spanned.SPAN_INCLUSIVE_INCLUSIVE);
// holder.tvReply.setText(String.format("@%s: %s",info.getReply_to().getAuthor(),info.getReply_to().getContent()));
holder.tvReply.setText(ss);
if (info.getReply_to().getExpandState() == STATE_NULL) { //未知
holder.tvReply.post(new Runnable() {
@Override
public void run() {
if (holder.tvReply.getLineCount() > MAX_LINE) {
holder.tvReply.setMaxLines(MAX_LINE);
holder.tvExpand.setVisibility(View.VISIBLE);
holder.tvExpand.setText("展开");
mList.get(holder.getAdapterPosition()).getReply_to().setExpandState(STATE_SHRINK);
holder.tvExpand.setOnClickListener(new OnStateClickListener(holder.getAdapterPosition(), holder.tvReply));
} else {
holder.tvExpand.setVisibility(View.GONE);
mList.get(holder.getAdapterPosition()).getReply_to().setExpandState(STATE_NONE);
}
}
});
} else if(info.getReply_to().getExpandState() == STATE_NONE) { //无需展开
holder.tvExpand.setVisibility(View.GONE);
} else if(info.getReply_to().getExpandState() == STATE_EXPAND) { //已展开
holder.tvReply.setMaxLines(Integer.MAX_VALUE);
holder.tvExpand.setText("收起");
holder.tvExpand.setVisibility(View.VISIBLE);
holder.tvExpand.setOnClickListener(new OnStateClickListener(holder.getAdapterPosition(), holder.tvReply));
} else { //已收缩
holder.tvReply.setMaxLines(MAX_LINE);
holder.tvExpand.setText("展开");
holder.tvExpand.setVisibility(View.VISIBLE);
holder.tvExpand.setOnClickListener(new OnStateClickListener(holder.getAdapterPosition(), holder.tvReply));
}
} else {
holder.tvReply.setVisibility(View.GONE);
holder.tvExpand.setVisibility(View.GONE);
}
}
@Override
public int getItemCount() {
return mList.size();
}
private class OnStateClickListener implements View.OnClickListener {
TextView replyView;
int position;
public OnStateClickListener(int position,TextView replyView) {
this.position = position;
this.replyView = replyView;
}
@Override
public void onClick(View view) {
TextView tv = (TextView) view;
if (mList.get(position).getReply_to().getExpandState() == STATE_SHRINK) {
tv.setText("收起");
replyView.setMaxLines(Integer.MAX_VALUE);
replyView.setEllipsize(null);
mList.get(position).getReply_to().setExpandState(STATE_EXPAND);
} else {
tv.setText("展开");
replyView.setMaxLines(MAX_LINE);
replyView.setEllipsize(TextUtils.TruncateAt.END);
mList.get(position).getReply_to().setExpandState(STATE_SHRINK);
}
}
}
public static class ViewHolder extends RecyclerView.ViewHolder{
@BindView(R.id.civ_comment_face)
CircleImageView civFace;
@BindView(R.id.tv_comment_name)
TextView tvName;
@BindView(R.id.tv_comment_content)
TextView tvContent;
@BindView(R.id.tv_comment_time)
TextView tvTime;
@BindView(R.id.tv_comment_expand)
TextView tvExpand;
@BindView(R.id.tv_comment_like)
TextView tvLike;
@BindView(R.id.tv_comment_reply)
TextView tvReply;
public ViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this,itemView);
}
}
}
然后,常规操作调用
mList = new ArrayList<>();
mAdapter = new CommentAdapter(mContext,mList);
rvCommentList.setLayoutManager(new LinearLayoutManager(mContext));
rvCommentList.setAdapter(mAdapter);
完成。。。