RecyclerView相比listView和GridView更加灵活高效,之前一直在用ListView,结合自定义ViewHolder做一些界面,用RecyclerView之后感觉二者十分相似,RecyclerView省去了ListView中getViewV()方法的setTag和getTag函数调用。
假期准备比赛第一次用RecyclerView,实现了类似QQ动态详情页的评论列表,点击评论图标发表评论,点击评论字段发送二级评论,点击二级评论可以进行回复,先看一下效果图:
RecyclerView的动态更新,更新前要判定在哪里添加评论,是添加评论Item还是更新Item中的子评论,
同时要注意是否是回复评论人。处理方法是声明3个标记变量,分别对应上述的情况,在监听方法中更改变量,发表新评论就根据
变量的取值对RecyclerView进行更新。
布局文件就是一个简单的RecyclerView,为其设置一个ViewHeader,这个ViewHeader就是所要评论的动态内容。
以下是activity代码:
package com.eztt.dtour.activity;
import android.content.ClipboardManager;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.eztt.dtour.DTourHelper;
import com.eztt.dtour.R;
import com.eztt.dtour.adapter.CommentAdapter;
import com.eztt.dtour.adapter.ImageAdapter;
import com.eztt.dtour.adapter.VideoAdapter;
import com.eztt.dtour.base.BaseActivity;
import com.eztt.dtour.bean.CommentListBean;
import com.eztt.dtour.bean.CommentUserBean;
import com.eztt.dtour.bean.CommentsBean;
import com.eztt.dtour.fragment.DynamicFragment;
import com.eztt.dtour.utils.EmojiUtils;
import com.eztt.dtour.utils.NineUtils;
import com.hyphenate.easeui.domain.EaseEmojicon;
import com.hyphenate.easeui.widget.EaseChatInputMenu;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import java.util.ArrayList;
import java.util.List;
import cn.jzvd.JZVideoPlayer;
import de.hdodenhof.circleimageview.CircleImageView;
public class DynamicDetail extends BaseActivity{
public static final String TAG = DynamicDetail.class.getSimpleName();
private RecyclerView commmentList;
private CommentAdapter commentAdapter;
private TextView UserName;
private TextView Content;
private CircleImageView Avatar;
private RecyclerView Images;
private TextView Location;
private TextView Time;
private TextView CommentNum;
private TextView ThumbNum;
private ImageView Likeimg;
private ImageView commentimg;
private EaseChatInputMenu inputMenu;
private InputMethodManager inputManager;
private ClipboardManager clipboard;
private DisplayImageOptions options;
private static final int main_comment_type = 0;//添加新的评论
private static final int second_comment_type = 1;//点击评论字段发表二级评论
private static final int third_comment_type = 2;//点击二级评论回复
private int current_comment_location;
private int Current_commentItem_location;
private List<CommentsBean> temp_Datas;
private int current_comment_type;
List<CommentListBean> testlist;//评论列表的数据源
@Override
public int getLayoutId() {
return R.layout.dynamic_comment_details;
}
@Override
public void initViews() {
inputMenu = findView(R.id.comment_input_menu);
inputManager = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
clipboard = (ClipboardManager)getSystemService(Context.CLIPBOARD_SERVICE);
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
testlist=new ArrayList<CommentListBean>() ;
commentAdapter=new CommentAdapter(testlist,this);
commmentList = findView(R.id.recycler_view_comment);
LinearLayoutManager layoutManager = new LinearLayoutManager(DynamicDetail.this);
commmentList.setLayoutManager(layoutManager);
setHeaderView(commmentList);
commmentList.setAdapter(commentAdapter);
}
private void setHeaderView(RecyclerView view){
View header = LayoutInflater.from(this).inflate(R.layout.dynamic_detail, view, false);
UserName=header.findViewById(R.id.dynamic_detail_username);
Content=header.findViewById(R.id.dynamic_detail_content);
Avatar=header.findViewById(R.id.dynamic_detail_avatar);
Images=header.findViewById(R.id.dynamic_detail_images);
Location=header.findViewById(R.id.dynamic_detail_location);
Time=header.findViewById(R.id.dynamic_detail_time);
CommentNum=header.findViewById(R.id.dynamic_detail_commentnum);
ThumbNum=header.findViewById(R.id.dynamic_detail_likenum);
Likeimg=header.findViewById(R.id.dynamic_detail_likeimg);
commentimg=header.findViewById(R.id.dynamic_detail_commentimg);
commentAdapter.setHeaderView(header);
}
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
public void initListener() {
inputMenu.init(null);
inputMenu.onCommentHide();
hideKeyboard();
inputMenu.hideExtendMenuContainer();
inputMenu.setVisibility(View.GONE);
inputMenu.setChatInputMenuListener(new EaseChatInputMenu.ChatInputMenuListener() {
@Override
public void onSendMessage(String content) {
switch (current_comment_type)//判断更新位置
{
case main_comment_type:
CommentListBean b=new CommentListBean();
b.setComment_text(content);
b.setName(DTourHelper.getInstance().getCurrentUsernName());
b.setHeadimg("http://p0.so.qhimgs1.com/t0150ebefcc359a1724.jpg");
testlist.add(0,b);
commentAdapter.notifyItemChanged(1);
break;
case second_comment_type:
Log.d(TAG,"刷新第"+current_comment_location+"条评论");
CommentListBean temp = testlist.get(current_comment_location);
temp.getComments().add(new CommentsBean(content,
new CommentUserBean(current_comment_location,
DTourHelper.getInstance().getCurrentUsernName()),null));
testlist.set(current_comment_location,temp);
commentAdapter.notifyItemChanged(current_comment_location+1);
break;
case third_comment_type:
CommentsBean item = temp_Datas.get(Current_commentItem_location);
CommentUserBean replyUser = item.getReplyUser();
CommentsBean reply;
if (replyUser != null) {
reply = new CommentsBean(content,new CommentUserBean(Current_commentItem_location,
DTourHelper.getInstance().getCurrentUsernName()),replyUser);
}
else {
reply = new CommentsBean(content,new CommentUserBean(Current_commentItem_location,
DTourHelper.getInstance().getCurrentUsernName()),item.getCommentsUser());
}
temp_Datas.add(Current_commentItem_location+1,reply);
commentAdapter.notifyDataSetChanged();
break;
}
for(int i=0;i<testlist.size();i++)
{
for(int j=0;j<testlist.get(i).getComments().size();j++)
{
Log.d(TAG,"第"+i+"部分"+testlist.get(i).getComments().get(j).getContent());
}
}
hideKeyboard();
inputMenu.hideExtendMenuContainer();
inputMenu.setVisibility(View.GONE);
}
@Override
public void onBigExpressionClicked(EaseEmojicon emojicon) {
}
@Override
public boolean onPressToSpeakBtnTouch(View v, MotionEvent event) {
return false;
}
});
commentAdapter.setOnRecyclerViewListener(new CommentAdapter.OnRecyclerViewListener() {
@Override
public void onItemClick(int position) {
current_comment_type = second_comment_type;
current_comment_location = position;
Log.d(TAG,"点击第"+position+"条评论");
inputMenu.setVisibility(View.VISIBLE);
}
@Override
public void onCommentItemClick(int position, int y, List<CommentsBean> Data) {
current_comment_type = third_comment_type;
Current_commentItem_location = position;
temp_Datas = Data;
inputMenu.setVisibility(View.VISIBLE);
int[] position2 = new int[2];
inputMenu.getLocationOnScreen(position2);
Log.d(TAG, "commmentList.x = " + position2[0]);
Log.d(TAG, "commmentList.y = " + position2[1]);
commmentList.scrollBy(0, y - position2[1]);
}
@Override
public boolean onItemLongClick(int position) {
return false;
}
});
commmentList.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
hideKeyboard();
inputMenu.hideExtendMenuContainer();
inputMenu.setVisibility(View.GONE);
return false;
}
});
commentimg.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
current_comment_type = main_comment_type;
inputMenu.setVisibility(View.VISIBLE);
}
});
commmentList.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
switch(newState)
{
case 0:
Glide.with(DynamicDetail.this).resumeRequests();
break;
case 1:
Glide.with(DynamicDetail.this).resumeRequests();
break;
case 2:
Glide.with(DynamicDetail.this).pauseRequests();
break;
}
}
});
}
@Override
public void initData() {
InitConfig();
final com.eztt.dtour.bean.Dynamic.DynamicBean bean = (com.eztt.dtour.bean.Dynamic.DynamicBean) getIntent().getSerializableExtra("Dynamic");
final int position=(int)getIntent().getIntExtra("position",0);
UserName.setText(bean.getUsername());
EmojiUtils.setText(Content, bean.getContent());
Location.setText(bean.getLocation());
Time.setText(bean.getTime());
//显示头像
ImageLoader.getInstance().displayImage(bean.getAvatar(), Avatar, options);
CommentNum.setText( ""+bean.getComment());
ThumbNum.setText("" + bean.getLike());
if(bean.getHasFavor()==0){
Likeimg.setImageResource(R.drawable.dynamic_like);
}
else {
Likeimg.setImageResource(R.drawable.dynamic_unlike);
}
Likeimg.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//没点赞则进行点赞
if(DynamicFragment.dynamic.get(position).getHasFavor()==0){
Likeimg.setImageResource(R.drawable.dynamic_unlike);
//点赞的数量+1
int i=DynamicFragment.dynamic.get(position).getLike()+1;
//改变值
DynamicFragment.dynamic.get(position).setLike(i);
ThumbNum.setText(""+i);
DynamicFragment.dynamic.get(position).setHasFavor(1);
}
else{
Likeimg.setImageResource(R.drawable.dynamic_like);
int i=DynamicFragment.dynamic.get(position).getLike()-1;
DynamicFragment.dynamic.get(position).setLike(i);
ThumbNum.setText(""+i);
DynamicFragment.dynamic.get(position).setHasFavor(0);
}
}
});
//展示九宫格
GridLayoutManager manager = new GridLayoutManager(DynamicDetail.this, 3);
Images.setLayoutManager(manager);
if (bean.getFlag() == 0) {
int imageCount = bean.getImageUrls() == null ? 0 : bean.getImageUrls().size();
if (imageCount == 0) {
//没有图片的时候不显示
Images.setVisibility(View.GONE);
} else {
Images.setVisibility(View.VISIBLE);
//刷新图片数据
ImageAdapter mAdapter = new ImageAdapter(bean.getImageUrls(), DynamicDetail.this);
Images.setAdapter(mAdapter);
ViewGroup.LayoutParams layoutParams = Images.getLayoutParams();
if (imageCount == 1) {
manager.setSpanCount(1);
layoutParams.width = ViewGroup.LayoutParams.WRAP_CONTENT;
} else if (imageCount == 4) {
manager.setSpanCount(2);
//两个图片的宽度
layoutParams.width = NineUtils.getGridWidth() * 2;
} else {
manager.setSpanCount(3);
layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
}
}
} else {
int videoCount = bean.getVideoUrls() == null ? 0 : bean.getVideoUrls().size();
if (videoCount == 0) {
//没有图片的时候不显示
Images.setVisibility(View.GONE);
} else {
Images.setVisibility(View.VISIBLE);
//刷新图片数据
VideoAdapter mAdapter = new VideoAdapter(bean.getVideoUrls(), DynamicDetail.this, bean.getCover());
Images.setAdapter(mAdapter);
///mAdapter.setNewData(item.getImageUrls());
//动态指定图片宫格的宽高和recycleview的宽高
//1张图片->1列
//4张图片 ->2列
//其他 ->3列
//目前只支持显示一个视频,所以等于4以及其他情况是摆设
ViewGroup.LayoutParams layoutParams = Images.getLayoutParams();
if (videoCount == 1) {
manager.setSpanCount(1);
layoutParams.width = ViewGroup.LayoutParams.WRAP_CONTENT;
} else if (videoCount == 4) {
manager.setSpanCount(2);
//两个图片的宽度
layoutParams.width = NineUtils.getGridWidth() * 2;
} else {
manager.setSpanCount(3);
layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
}
}
}
}
@Override
public void processClick(View v) {
}
private void InitConfig(){
options = new DisplayImageOptions.Builder()
// 加载中显示的默认图片
.showImageOnLoading(R.drawable.ic_launcher)
// 设置加载失败的默认图片
.showImageOnFail(R.drawable.ic_launcher)
// 内存缓存
.cacheInMemory(true)
// sdcard缓存
.cacheOnDisk(true)
// 设置最低配置
.bitmapConfig(Bitmap.Config.RGB_565)
.build();
}
//动态视频播放需要实现
@Override
public void onBackPressed() {
if (JZVideoPlayer.backPress()) {
return;
}
super.onBackPressed();
}
//动态视频播放需要实现
@Override
protected void onPause() {
super.onPause();
JZVideoPlayer.releaseAllVideos();
}
protected void hideKeyboard() {
if (getWindow().getAttributes().softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN) {
if (getCurrentFocus() != null)
inputManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(),
InputMethodManager.HIDE_NOT_ALWAYS);
}
}
public void back(View view)
{
onBackPressed();
}
}
布局就是一个RecyclerView,不放代码了。RecyclerView的数据源是一个List,其中每个Item对应一条评论,
每个Item中又包含一个List,list中保存每条评论的子评论。
package com.eztt.dtour.bean;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* Created by think on 2018/2/5.
*/
public class CommentListBean implements Serializable {
private int id;
private String name;
private String headimg;
private String time;
private String comment_text;
private int good;
private List<CommentsBean> comments;
public CommentListBean()
{
comments = new ArrayList<CommentsBean>();
}
public void setComments(List<CommentsBean> comments) { this.comments = comments; }
public List<CommentsBean> getComments() { return comments; }
public void setId(int id) { this.id = id; }
public int getId() { return id; }
public void setName(String name) { this.name = name; }
public String getName() { return name; }
public void setHeadimg(String url) { this.headimg = url; }
public String getHeadimg() { return headimg; }
public void setTime(String time) { this.time = time; }
public String getTime() {return time; }
public void setComment_text(String text) { this.comment_text = text; }
public String getComment_text() { return comment_text; }
public void setGood(int good) { this.good = good; }
public int getGood() { return good; }
}
适配器代码:
package com.eztt.dtour.adapter;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.eztt.dtour.R;
import com.eztt.dtour.bean.CommentListBean;
import com.eztt.dtour.bean.CommentsBean;
import com.eztt.dtour.widget.CommentsView;
import com.orhanobut.logger.Logger;
import java.util.List;
/**
* Created by think on 2018/2/5.
*/
public class CommentAdapter extends RecyclerView.Adapter {
public static final String Tag = CommentAdapter.class.getSimpleName();
public static final int TYPE_HEADER = 0;
public static final int TYPE_NORMAL = 1;
private Context context;
private View headerView;
public void setHeaderView(View headerView) {
this.headerView = headerView;
notifyItemInserted(0);
}
public int getItemViewType(int position) {
if (headerView == null){
return TYPE_NORMAL;
}
if (position == 0){
return TYPE_HEADER;
}
return TYPE_NORMAL;
}
public static interface OnRecyclerViewListener {
void onItemClick(int position);
void onCommentItemClick(int position, int y, List<CommentsBean> Data);
boolean onItemLongClick(int position);
}
private OnRecyclerViewListener onRecyclerViewListener;
public void setOnRecyclerViewListener(OnRecyclerViewListener onRecyclerViewListener) {
this.onRecyclerViewListener = onRecyclerViewListener;
}
private static final String TAG = CommentAdapter.class.getSimpleName();
private List<CommentListBean> list;
public CommentAdapter(List<CommentListBean> list,Context context) {
this.list = list;
this.context = context;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
Logger.d(TAG, "onCreateViewHolder, i: " + i);
if(headerView != null && i == TYPE_HEADER) {
return new CommentViewHolder(headerView);
}
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_dynamic_comment, null);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
view.setLayoutParams(lp);
return new CommentViewHolder(view);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int i) {
Logger.d(TAG, "onBindViewHolder, i: " + i + ", viewHolder: " + viewHolder);
if(getItemViewType(i)==TYPE_NORMAL) {
CommentViewHolder holder = (CommentViewHolder) viewHolder;
holder.position = i-1;
CommentListBean commentItem = list.get(i-1);
if(commentItem.getComment_text()!=null)
holder.comment_text.setText(commentItem.getComment_text());
if(commentItem.getName()!=null)
holder.name.setText(commentItem.getName());
if(commentItem.getHeadimg()!=null) {
if(!holder.initHeadImg) {
Glide.with(context).load(commentItem.getHeadimg())
.into(holder.headimg);
holder.initHeadImg = true;
}
}
Log.d("匹配评论信息:", (i-1)+ "");
holder.comment_list.setList(commentItem.getComments());
holder.comment_list.notifyDataSetChanged();
}
}
@Override
public int getItemCount() {
return headerView == null? list.size():list.size()+1;
}
class CommentViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener
{
public de.hdodenhof.circleimageview.CircleImageView headimg;
public ImageView likeimag;
public TextView comment_text;
public CommentsView comment_list;
public TextView name;
public TextView time;
public boolean initHeadImg;
public int good_count;
public int position;
public CommentViewHolder(View itemView) {
super(itemView);
if(itemView == headerView)
return;
headimg = itemView.findViewById(R.id.comment_avatar);
likeimag = itemView.findViewById(R.id.comment_likeimg);
comment_text = itemView.findViewById(R.id.comment_text) ;
name = itemView.findViewById(R.id.comment_name);
time = itemView.findViewById(R.id.comment_time);
comment_list = itemView.findViewById(R.id.comments_list);
comment_text.setOnClickListener(this);
comment_text.setOnLongClickListener(this);
comment_list.setOnItemClickListener(new CommentsView.onItemClickListener() {
@Override
public void onItemClick(int p, int y, List<CommentsBean> Data) {
if (null != onRecyclerViewListener) {
onRecyclerViewListener.onCommentItemClick(p,y,Data);
}
}
});
}
@Override
public void onClick(View v) {
if (null != onRecyclerViewListener) {
onRecyclerViewListener.onItemClick(position);
}
}
@Override
public boolean onLongClick(View v) {
if(null != onRecyclerViewListener){
return onRecyclerViewListener.onItemLongClick(position);
}
return false;
}
}
}