大家在做项目时肯定都会使用到RecyclerView来显示列表数据,今天实现一个左右并排的效果。
用到的依赖库如下
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
界面中用到的Api接口来自于玩Android,同时感谢鸿洋大大的分享。
接口地址 我这里用的是体系数据相关的Api
接着是布局,xml中是一个线性布局,放置了一个TextView用来显示标题的,下面是两个RecyclerView 分别用来显示左侧内容和右侧内容。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".activity.KnowledgeActivity">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="@color/colorPrimary">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginLeft="12dp"
android:text="知识体系"
android:textSize="15sp"
android:textColor="@color/white"/>
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:background="@color/white">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_left_view"
android:layout_width="120dp"
android:layout_height="match_parent"
android:overScrollMode="never">
</androidx.recyclerview.widget.RecyclerView>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_right_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:overScrollMode="never">
</androidx.recyclerview.widget.RecyclerView>
</LinearLayout>
</LinearLayout>
接下来在项目中定义一个接口用来存放请求的Url
package com.ranlegeran.aroutertest.api;
import com.ranlegeran.aroutertest.bean.Knowledge;
import com.ranlegeran.aroutertest.bean.KnowledgeArticle;
import com.ranlegeran.aroutertest.bean.ProjectTree;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Url;
public interface ApiService {
//体系数据
@GET("tree/json")
Call<Knowledge> getKnowledge();
//知识体系下的文章
@GET()
Call<KnowledgeArticle> getKnowledgeArticle(@Url String url);
}
Knowledge类和KnowledgeArticle类的实体
package com.ranlegeran.aroutertest.bean;
import java.io.Serializable;
import java.util.List;
public class Knowledge {
private int errorCode;
private String errorMsg;
private List<DataBean> data;
public int getErrorCode() {
return errorCode;
}
public void setErrorCode(int errorCode) {
this.errorCode = errorCode;
}
public String getErrorMsg() {
return errorMsg;
}
public void setErrorMsg(String errorMsg) {
this.errorMsg = errorMsg;
}
public List<DataBean> getData() {
return data;
}
public void setData(List<DataBean> data) {
this.data = data;
}
public static class DataBean {
private int courseId;
private int id;
private String name;
private int order;
private int parentChapterId;
private boolean userControlSetTop;
private int visible;
private List<ChildrenBean> children;
public int getCourseId() {
return courseId;
}
public void setCourseId(int courseId) {
this.courseId = courseId;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
public int getParentChapterId() {
return parentChapterId;
}
public void setParentChapterId(int parentChapterId) {
this.parentChapterId = parentChapterId;
}
public boolean isUserControlSetTop() {
return userControlSetTop;
}
public void setUserControlSetTop(boolean userControlSetTop) {
this.userControlSetTop = userControlSetTop;
}
public int getVisible() {
return visible;
}
public void setVisible(int visible) {
this.visible = visible;
}
public List<ChildrenBean> getChildren() {
return children;
}
public void setChildren(List<ChildrenBean> children) {
this.children = children;
}
public static class ChildrenBean {
private int courseId;
private int id;
private String name;
private int order;
private int parentChapterId;
private boolean userControlSetTop;
private int visible;
private List<?> children;
public int getCourseId() {
return courseId;
}
public void setCourseId(int courseId) {
this.courseId = courseId;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
public int getParentChapterId() {
return parentChapterId;
}
public void setParentChapterId(int parentChapterId) {
this.parentChapterId = parentChapterId;
}
public boolean isUserControlSetTop() {
return userControlSetTop;
}
public void setUserControlSetTop(boolean userControlSetTop) {
this.userControlSetTop = userControlSetTop;
}
public int getVisible() {
return visible;
}
public void setVisible(int visible) {
this.visible = visible;
}
public List<?> getChildren() {
return children;
}
public void setChildren(List<?> children) {
this.children = children;
}
}
}
}
package com.ranlegeran.aroutertest.bean;
import java.io.Serializable;
import java.util.List;
public class KnowledgeArticle {
private DataBean data;
private int errorCode;
private String errorMsg;
public DataBean getData() {
return data;
}
public void setData(DataBean data) {
this.data = data;
}
public int getErrorCode() {
return errorCode;
}
public void setErrorCode(int errorCode) {
this.errorCode = errorCode;
}
public String getErrorMsg() {
return errorMsg;
}
public void setErrorMsg(String errorMsg) {
this.errorMsg = errorMsg;
}
public static class DataBean {
private int curPage;
private int offset;
private boolean over;
private int pageCount;
private int size;
private int total;
private List<DatasBean> datas;
public int getCurPage() {
return curPage;
}
public void setCurPage(int curPage) {
this.curPage = curPage;
}
public int getOffset() {
return offset;
}
public void setOffset(int offset) {
this.offset = offset;
}
public boolean isOver() {
return over;
}
public void setOver(boolean over) {
this.over = over;
}
public int getPageCount() {
return pageCount;
}
public void setPageCount(int pageCount) {
this.pageCount = pageCount;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public int getTotal() {
return total;
}
public void setTotal(int total) {
this.total = total;
}
public List<DatasBean> getDatas() {
return datas;
}
public void setDatas(List<DatasBean> datas) {
this.datas = datas;
}
public static class DatasBean {
private String apkLink;
private int audit;
private String author;
private boolean canEdit;
private int chapterId;
private String chapterName;
private boolean collect;
private int courseId;
private String desc;
private String descMd;
private String envelopePic;
private boolean fresh;
private String host;
private int id;
private String link;
private String niceDate;
private String niceShareDate;
private String origin;
private String prefix;
private String projectLink;
private long publishTime;
private int realSuperChapterId;
private int selfVisible;
private long shareDate;
private String shareUser;
private int superChapterId;
private String superChapterName;
private String title;
private int type;
private int userId;
private int visible;
private int zan;
private List<?> tags;
public String getApkLink() {
return apkLink;
}
public void setApkLink(String apkLink) {
this.apkLink = apkLink;
}
public int getAudit() {
return audit;
}
public void setAudit(int audit) {
this.audit = audit;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public boolean isCanEdit() {
return canEdit;
}
public void setCanEdit(boolean canEdit) {
this.canEdit = canEdit;
}
public int getChapterId() {
return chapterId;
}
public void setChapterId(int chapterId) {
this.chapterId = chapterId;
}
public String getChapterName() {
return chapterName;
}
public void setChapterName(String chapterName) {
this.chapterName = chapterName;
}
public boolean isCollect() {
return collect;
}
public void setCollect(boolean collect) {
this.collect = collect;
}
public int getCourseId() {
return courseId;
}
public void setCourseId(int courseId) {
this.courseId = courseId;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public String getDescMd() {
return descMd;
}
public void setDescMd(String descMd) {
this.descMd = descMd;
}
public String getEnvelopePic() {
return envelopePic;
}
public void setEnvelopePic(String envelopePic) {
this.envelopePic = envelopePic;
}
public boolean isFresh() {
return fresh;
}
public void setFresh(boolean fresh) {
this.fresh = fresh;
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
public String getNiceDate() {
return niceDate;
}
public void setNiceDate(String niceDate) {
this.niceDate = niceDate;
}
public String getNiceShareDate() {
return niceShareDate;
}
public void setNiceShareDate(String niceShareDate) {
this.niceShareDate = niceShareDate;
}
public String getOrigin() {
return origin;
}
public void setOrigin(String origin) {
this.origin = origin;
}
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public String getProjectLink() {
return projectLink;
}
public void setProjectLink(String projectLink) {
this.projectLink = projectLink;
}
public long getPublishTime() {
return publishTime;
}
public void setPublishTime(long publishTime) {
this.publishTime = publishTime;
}
public int getRealSuperChapterId() {
return realSuperChapterId;
}
public void setRealSuperChapterId(int realSuperChapterId) {
this.realSuperChapterId = realSuperChapterId;
}
public int getSelfVisible() {
return selfVisible;
}
public void setSelfVisible(int selfVisible) {
this.selfVisible = selfVisible;
}
public long getShareDate() {
return shareDate;
}
public void setShareDate(long shareDate) {
this.shareDate = shareDate;
}
public String getShareUser() {
return shareUser;
}
public void setShareUser(String shareUser) {
this.shareUser = shareUser;
}
public int getSuperChapterId() {
return superChapterId;
}
public void setSuperChapterId(int superChapterId) {
this.superChapterId = superChapterId;
}
public String getSuperChapterName() {
return superChapterName;
}
public void setSuperChapterName(String superChapterName) {
this.superChapterName = superChapterName;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public int getVisible() {
return visible;
}
public void setVisible(int visible) {
this.visible = visible;
}
public int getZan() {
return zan;
}
public void setZan(int zan) {
this.zan = zan;
}
public List<?> getTags() {
return tags;
}
public void setTags(List<?> tags) {
this.tags = tags;
}
}
}
}
现在来编写左边RecyclerView的适配器
package com.ranlegeran.aroutertest.adapter;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.ranlegeran.aroutertest.R;
import com.ranlegeran.aroutertest.bean.Knowledge;
import java.util.ArrayList;
import java.util.List;
public class KnowledgeLeftAdapter extends RecyclerView.Adapter<KnowledgeLeftAdapter.ViewHolder> {
private List<Knowledge.DataBean> mDataList = new ArrayList<>();
//用来标记选中的位置
private int mCurrentPosition = 0;
//左侧Item的点击事件
private OnLeftItemClickListener mOnItemClickListener = null;
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View mView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_knowledge_left, parent, false);
return new ViewHolder(mView);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Knowledge.DataBean mDataBean = mDataList.get(position);
holder.mTextName.setText(mDataBean.getName());
if (mCurrentPosition == position) {
//选中的背景颜色和字体颜色
holder.mTextName.setBackgroundColor(Color.parseColor("#FFFFFF"));
holder.mTextName.setTextColor(Color.parseColor("#FF402E"));
} else {
//未选中的背景颜色和字体颜色
holder.mTextName.setBackgroundColor(Color.parseColor("#F2F3F8"));
holder.mTextName.setTextColor(Color.parseColor("#333333"));
}
holder.itemView.setOnClickListener(v -> {
if (mOnItemClickListener != null && mCurrentPosition != position) {
mCurrentPosition = position;
mOnItemClickListener.onLeftItemClick(mDataBean);
notifyDataSetChanged();
}
});
}
@Override
public int getItemCount() {
return mDataList.size();
}
//设置数据
public void setData(Knowledge mKnowledge) {
List<Knowledge.DataBean> mData = mKnowledge.getData();
if (mData != null) {
mDataList.clear();
mDataList.addAll(mData);
notifyDataSetChanged();
}
if (mDataList.size() > 0) {
mOnItemClickListener.onLeftItemClick(mDataList.get(mCurrentPosition));
}
}
class ViewHolder extends RecyclerView.ViewHolder {
TextView mTextName;
public ViewHolder(@NonNull View itemView) {
super(itemView);
mTextName = (TextView) itemView.findViewById(R.id.item_left_text_name);
}
}
public void setOnLeftItemClickListener(OnLeftItemClickListener listener) {
this.mOnItemClickListener = listener;
}
public interface OnLeftItemClickListener {
void onLeftItemClick(Knowledge.DataBean item);
}
}
左边item的布局文件,item_knowledge_left.xml 里面只放置了一个TextView用来显示文字。
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/item_left_text_name"
android:layout_width="match_parent"
android:layout_height="43dp"
android:gravity="center"
android:text="知识体系"
android:textSize="15sp">
</TextView>
右边的RecyclerView适配器
package com.ranlegeran.aroutertest.adapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.ranlegeran.aroutertest.R;
import com.ranlegeran.aroutertest.bean.KnowledgeArticle;
import java.util.ArrayList;
import java.util.List;
public class RightContentAdapter extends RecyclerView.Adapter<RightContentAdapter.ViewHolder> {
private List<KnowledgeArticle.DataBean.DatasBean> mDataList = new ArrayList<>();
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View mView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_right_content, parent, false);
return new ViewHolder(mView);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
KnowledgeArticle.DataBean.DatasBean mDataBean = mDataList.get(position);
holder.mTextTitle.setText(mDataBean.getTitle());
}
@Override
public int getItemCount() {
return mDataList.size();
}
//设置数据
public void setData(KnowledgeArticle mKnowledgeArticle) {
List<KnowledgeArticle.DataBean.DatasBean> mData = mKnowledgeArticle.getData().getDatas();
mDataList.clear();
mDataList.addAll(mData);
notifyDataSetChanged();
}
class ViewHolder extends RecyclerView.ViewHolder {
TextView mTextTitle;
public ViewHolder(@NonNull View itemView) {
super(itemView);
mTextTitle = (TextView) itemView.findViewById(R.id.item_right_text_title);
}
}
}
右边的item布局,item_right_content 同样也只放置了一个TextView
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/item_right_text_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="15dp"
android:textSize="13sp">
</TextView>
最后KnowledgeActivity中的Java代码了
package com.ranlegeran.aroutertest.activity;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import android.util.Log;
import com.ranlegeran.aroutertest.R;
import com.ranlegeran.aroutertest.adapter.KnowledgeLeftAdapter;
import com.ranlegeran.aroutertest.adapter.RightContentAdapter;
import com.ranlegeran.aroutertest.api.ApiService;
import com.ranlegeran.aroutertest.bean.Knowledge;
import com.ranlegeran.aroutertest.bean.KnowledgeArticle;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class KnowledgeActivity extends AppCompatActivity implements KnowledgeLeftAdapter.OnLeftItemClickListener {
private static final String BASE_URL = "https://www.wanandroid.com/";
private RecyclerView mRvLeftView;
private RecyclerView mRvRightView;
private KnowledgeLeftAdapter mLeftAdapter;
private RightContentAdapter mRightAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_knowledge);
initView();
}
private void initView() {
mRvLeftView = (RecyclerView) findViewById(R.id.rv_left_view);
mRvRightView = (RecyclerView) findViewById(R.id.rv_right_view);
//左侧列表
mRvLeftView.setLayoutManager(new LinearLayoutManager(this));
mLeftAdapter = new KnowledgeLeftAdapter();
mRvLeftView.setAdapter(mLeftAdapter);
mLeftAdapter.setOnLeftItemClickListener(this);
//右侧列表
mRvRightView.setLayoutManager(new LinearLayoutManager(this));
mRightAdapter = new RightContentAdapter();
mRvRightView.setAdapter(mRightAdapter);
//请求接口
getKnowledge();
}
private void getKnowledge() {
Retrofit mRetrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
ApiService mApi = mRetrofit.create(ApiService.class);
Call<Knowledge> mCall = mApi.getKnowledge();
mCall.enqueue(new Callback<Knowledge>() {
@Override
public void onResponse(Call<Knowledge> call, Response<Knowledge> response) {
Knowledge mKnowledge = response.body();
//设置左边Adapter的数据
mLeftAdapter.setData(mKnowledge);
}
@Override
public void onFailure(Call<Knowledge> call, Throwable t) {
}
});
}
@Override
public void onLeftItemClick(Knowledge.DataBean item) {
int articleId = item.getId();
int page = 0;
String targetUrl = "article/list/" + page + "/json?" + "cid=" + articleId;
Log.e("TAG", "Url: >>> " + targetUrl);
Retrofit mRetrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
ApiService mApi = mRetrofit.create(ApiService.class);
Call<KnowledgeArticle> mCall = mApi.getKnowledgeArticle(targetUrl);
mCall.enqueue(new Callback<KnowledgeArticle>() {
@Override
public void onResponse(Call<KnowledgeArticle> call, Response<KnowledgeArticle> response) {
KnowledgeArticle mKnowledgeArticle = response.body();
//设置右边Adapter的数据
mRightAdapter.setData(mKnowledgeArticle);
mRvRightView.scrollToPosition(0);
}
@Override
public void onFailure(Call<KnowledgeArticle> call, Throwable t) {
}
});
}
}
首先在initView方法中把两个RecyclerView的控件找到,然后给两个View都设置了一个LayoutManager,接着拿到咱们创建的KnowledgeLeftAdapter和RightContentAdapter绑定在了对应的RecyclerView上。
getKnowledge();方法就是请求网络数据的部分在Retrofit的onResponse中调用了mLeftAdapter.setData(mKnowledge);来给左边的Adapter设置数据。
onLeftItemClick是左边Item的点击事件,我们在点击的时候拿到对应的id,然后根据这个id去请求知识体系下的文章,请求成功后同样在onResponse中调用 mRightAdapter.setData(mKnowledgeArticle);给右边的Adapter设置数据
mRvRightView.scrollToPosition(0); 这个方法是在点击左边切换内容的时候,右边的列表内容可以置顶到顶部。