效果图:
1、引入依赖
2、左侧类型适配器
3、左侧类型布局文件
4、右侧内容适配器
5、右侧内容布局文件
6、MainActivity代码
7、MainActivity布局文件
8、dimens.xml尺寸文件
9、left_item_check_bg.xml左侧选中的背景文件
10、item_right_title.xml分组标题文件
11、ScrollBean实体类
12、在AndroidManifest.xml中加入权限
引入依赖:
先在build.gradle(Project)中加入
allprojects {
repositories {
google()
jcenter()
maven { url "https://jitpack.io" }
}
}
然后在build.gradle(Module)中加入(加入后记得点击右上角的同步(Sync Now))
implementation 'androidx.recyclerview:recyclerview:1.0.0'
implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.47'
implementation 'com.github.bumptech.glide:glide:4.9.0'
implementation 'com.google.android.material:material:1.0.0'
左侧类型适配器(LeftAdapter):
package com.example.recycleview2.adapter;
import android.graphics.Color;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;
import com.example.recycleview2.R;
import java.util.ArrayList;
import java.util.List;
public class LeftAdapter extends BaseQuickAdapter {
private List tvList = new ArrayList<>();
public LeftAdapter(int layoutResId, @Nullable List data){
super(layoutResId,data);
}
@Override
protected void convert(@NonNull BaseViewHolder helper, String item) {
helper.setText(R.id.left_text,item).addOnClickListener(R.id.item);
tvList.add((TextView)helper.getView(R.id.left_text)); //将左侧item中的TextView添加到集合中
//设置进入页面之后,左边列表的初始状态
if(tvList != null && getData() != null && tvList.size() == getData().size()){
selectItemt(0);
}
helper.getView(R.id.item).setSelected(true);
}
public void selectItemt(int i){
for (int j = 0; j < getData().size(); j++) {
if( i == j){
// tvList.get(j).setBackgroundColor(Color.parseColor("#008577")); //选中的背景
tvList.get(j).setBackgroundResource(R.drawable.left_item_check_bg);
tvList.get(j).setTextColor(ContextCompat.getColor(mContext,R.color.white));
}else{
tvList.get(j).setBackgroundColor(0xffffffff); //未选中的背景
tvList.get(j).setTextColor(ContextCompat.getColor(mContext,R.color.gray));
}
}
}
}
左侧类型布局文件(item_left.xml):
右侧内容适配器(RightAdapter):
package com.example.recycleview2.adapter;
import android.media.Image;
import android.widget.ImageView;
import androidx.annotation.Nullable;
import com.bumptech.glide.Glide;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseSectionQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;
import com.example.recycleview2.R;
import com.example.recycleview2.entity.ScrollBean;
import java.util.List;
public class RightAdapter extends BaseSectionQuickAdapter {
public RightAdapter(int layoutResId, int sectionHeadResId, List data){
super(layoutResId,sectionHeadResId,data);
}
@Override
protected void convertHead(BaseViewHolder helper,ScrollBean item){
helper.setText(R.id.right_title,item.header);
}
@Override
protected void convert(@Nullable BaseViewHolder helper,ScrollBean item){
ScrollBean.ScrollItemBean itemBean = item.t;
helper.setText(R.id.main_name,itemBean.getName());
helper.setText(R.id.main_price,itemBean.getPrice());
Glide.with(mContext).load(itemBean.getImg()).into((ImageView)helper.getView(R.id.main_image));
}
}
右侧内容布局文件(item_right.xml):
MainActivity代码:
package com.example.recycleview2;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.content.Context;
import android.graphics.Rect;
import android.icu.util.LocaleData;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.example.recycleview2.adapter.LeftAdapter;
import com.example.recycleview2.adapter.RightAdapter;
import com.example.recycleview2.entity.ScrollBean;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerLeft,recyclerRight;
private TextView tvRightTitle; //右侧item标题
private List leftList; //左侧文本数据
private List rightList; //右侧数据
private LeftAdapter leftAdapter; //左侧适配器
private RightAdapter rightAdapter; //右侧适配器
//右侧标题在数据中所对应的数据集合
private List integerList = new ArrayList<>();
private Context mContext;
private int titleHeight; //标题的高度
private int first = 0; //右侧第一个item数据
private GridLayoutManager gridLayoutManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView(){
mContext = this;
recyclerLeft = findViewById(R.id.rec_left);
recyclerRight = findViewById(R.id.rec_right);
tvRightTitle = findViewById(R.id.right_title);
getLeftData(); //获取左侧数据
getRightData(); //获取右侧数据
initRightLayout();
initLeftLayout();
}
private void getLeftData(){
leftList = new ArrayList<>();
leftList.add("星期一");
leftList.add("星期二");
leftList.add("星期三");
leftList.add("星期四");
leftList.add("星期五");
leftList.add("星期六");
leftList.add("星期日");
}
private void getRightData(){
String imgUrl = "http://imgm.gmw.cn/attachement/jpg/site215/20190902/3742794414253686953.jpg";
rightList = new ArrayList<>();
for (int i = 0; i < leftList.size(); i++) {
rightList.add(new ScrollBean(true,leftList.get(i))); //第一组数据
for (int j = 0; j < 6; j++) {
rightList.add(new ScrollBean((new ScrollBean.ScrollItemBean("数据" + j,String.valueOf(i*j),imgUrl,leftList.get(i)))));
}
}
for (int i = 0; i < rightList.size(); i++) {
if(rightList.get(i).isHeader){
integerList.add(i); //将header添加到集合
}
}
}
//右侧数据布局
private void initRightLayout(){
gridLayoutManager = new GridLayoutManager(mContext,2);
if(rightAdapter == null){
rightAdapter = new RightAdapter(R.layout.item_right,R.layout.item_right_title,null);
recyclerRight.setLayoutManager(gridLayoutManager);
recyclerRight.addItemDecoration(new RecyclerView.ItemDecoration() {
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
outRect.set(dpToPx(mContext, getDimens(mContext, R.dimen.dp3)),0
, dpToPx(mContext, getDimens(mContext, R.dimen.dp3))
, dpToPx(mContext, getDimens(mContext, R.dimen.dp3)));
}
});
recyclerRight.setAdapter(rightAdapter);
}else{
rightAdapter.notifyDataSetChanged();
}
rightAdapter.setNewData(rightList);
//设置右侧初始化标题
if(rightList.get(first).isHeader){
tvRightTitle.setText(rightList.get(first).header);
}
//滑动监听
recyclerRight.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
titleHeight = tvRightTitle.getHeight(); //获取右侧标题的高度
}
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if(rightList.get(first).isHeader){
View view = gridLayoutManager.findViewByPosition(first); //获取item的View
if(view != null){
//item顶部和父容器顶部距离大于等于标题的高度,则设置偏移量
if(view.getTop() >= titleHeight){
tvRightTitle.setY(view.getTop() - titleHeight);
}else{
tvRightTitle.setY(0); //不设置
}
}
}
/*
每次滑动之后,右侧列表中可见的第一个item的position肯定会改变,
并且右侧列表中可见的第一个item的position变换了之后,
才有可能改变右侧title的值,
所以这个方法内的逻辑在右侧可见的第一个item的position改变之后一定会执行
*/
int firstPosition = gridLayoutManager.findFirstVisibleItemPosition();
if(first != firstPosition && firstPosition >= 0){
first = firstPosition; //给first赋值
tvRightTitle.setY(0); //不设置y轴的偏移量
//右侧第一个item是否是header,是则设置相应的值
if(rightList.get(first).isHeader){
tvRightTitle.setText(rightList.get(first).header);
}else{
tvRightTitle.setText(rightList.get(first).t.getType());
}
}
//遍历左边列表,列表对应的内容等于右边的title,则设置左侧对应item高亮
for (int i = 0; i < leftList.size(); i++) {
if(leftList.get(i).equals(tvRightTitle.getText().toString())){
leftAdapter.selectItemt(i);
}
}
/*
如果右边最后一个完全显示的item的position,
等于bean中最后一条数据的position(也就是右侧列表拉到底了),
则设置左侧列表最后一条item高亮
*/
if(gridLayoutManager.findLastCompletelyVisibleItemPosition() == rightList.size() - 1){
leftAdapter.selectItemt(leftList.size() - 1);
}
}
});
}
//左侧数据布局
private void initLeftLayout(){
if(leftAdapter == null){
leftAdapter = new LeftAdapter(R.layout.item_left,null);
recyclerLeft.setLayoutManager(new LinearLayoutManager(mContext,RecyclerView.VERTICAL,false));
recyclerLeft.addItemDecoration(new DividerItemDecoration(mContext,DividerItemDecoration.VERTICAL));
recyclerLeft.setAdapter(leftAdapter);
}else{
leftAdapter.notifyDataSetChanged();
}
leftAdapter.setNewData(leftList);
leftAdapter.setOnItemChildClickListener(new BaseQuickAdapter.OnItemChildClickListener() {
@Override
public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) {
switch (view.getId()){
case R.id.item:
leftAdapter.selectItemt(position);
gridLayoutManager.scrollToPositionWithOffset(integerList.get(position),0);
break;
default:break;
}
}
});
}
private float getDimens(Context context,int id){
DisplayMetrics dm = context.getResources().getDisplayMetrics();
float px = context.getResources().getDimension(id);
return px / dm.density;
}
private int dpToPx(Context context,float dp){
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
return (int) ((dp * displayMetrics.density) + 0.5f);
}
}
MainActivity布局文件:
dimens.xml尺寸文件(此文件放在values文件夹中):
8sp
9sp
10sp
11sp
12sp
13sp
14sp
15sp
16sp
17sp
18sp
19sp
20sp
21sp
22sp
23sp
24sp
25sp
26sp
27sp
28sp
29sp
30sp
1dp
2dp
3dp
4dp
5dp
6dp
7dp
8dp
9dp
10dp
11dp
12dp
13dp
14dp
15dp
16dp
17dp
18dp
19dp
20dp
21dp
22dp
23dp
24dp
25dp
26dp
27dp
28dp
29dp
30dp
31dp
32dp
33dp
34dp
35dp
36dp
37dp
38dp
39dp
40dp
41dp
42dp
43dp
44dp
45dp
46dp
47dp
48dp
49dp
50dp
51dp
52dp
53dp
54dp
55dp
56dp
57dp
58dp
59dp
60dp
61dp
62dp
63dp
64dp
65dp
66dp
67dp
68dp
69dp
70dp
71dp
72dp
73dp
74dp
75dp
76dp
77dp
78dp
79dp
80dp
81dp
82dp
83dp
84dp
85dp
86dp
87dp
88dp
89dp
90dp
91dp
92dp
93dp
94dp
95dp
96dp
97dp
98dp
99dp
100dp
101dp
102dp
103dp
104dp
105dp
106dp
107dp
108dp
109dp
110dp
111dp
112dp
113dp
114dp
115dp
116dp
117dp
118dp
119dp
120dp
121dp
122dp
123dp
124dp
125dp
126dp
127dp
128dp
129dp
130dp
131dp
132dp
133dp
134dp
135dp
136dp
137dp
138dp
139dp
140dp
141dp
142dp
143dp
144dp
145dp
146dp
147dp
148dp
149dp
150dp
151dp
152dp
153dp
154dp
155dp
156dp
157dp
158dp
159dp
160dp
161dp
162dp
163dp
164dp
165dp
166dp
167dp
168dp
169dp
170dp
171dp
172dp
173dp
174dp
175dp
176dp
177dp
178dp
179dp
180dp
181dp
182dp
183dp
184dp
185dp
186dp
187dp
188dp
189dp
190dp
191dp
192dp
193dp
194dp
195dp
196dp
197dp
198dp
199dp
200dp
201dp
202dp
203dp
204dp
205dp
206dp
207dp
208dp
209dp
210dp
211dp
212dp
213dp
214dp
215dp
216dp
217dp
218dp
219dp
220dp
221dp
222dp
223dp
224dp
225dp
226dp
227dp
228dp
229dp
230dp
231dp
232dp
233dp
234dp
235dp
236dp
237dp
238dp
239dp
240dp
241dp
242dp
243dp
244dp
245dp
246dp
247dp
248dp
249dp
250dp
251dp
252dp
253dp
254dp
255dp
256dp
257dp
258dp
259dp
260dp
261dp
262dp
263dp
264dp
265dp
266dp
267dp
268dp
269dp
270dp
271dp
272dp
273dp
274dp
275dp
276dp
277dp
278dp
279dp
280dp
281dp
282dp
283dp
284dp
285dp
286dp
287dp
288dp
289dp
290dp
291dp
292dp
293dp
294dp
295dp
296dp
297dp
298dp
299dp
300dp
0.5dp
left_item_check_bg.xml左侧选中的背景文件:
item_right_title.xml分组标题文件:
ScrollBean实体类:
package com.example.recycleview2.entity;
import com.chad.library.adapter.base.entity.SectionEntity;
public class ScrollBean extends SectionEntity {
public ScrollBean(boolean isHeader,String header){
super(isHeader,header);
}
public ScrollBean(ScrollItemBean bean){
super(bean);
}
public static class ScrollItemBean{
private String name;
private String price;
private String img;
private String type;
public ScrollItemBean(String name,String price,String img,String type){
this.name = name;
this.price = price;
this.img = img;
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
public String getImg() {
return img;
}
public void setImg(String img) {
this.img = img;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
}
在AndroidManifest.xml中加入权限: