赞
踩
本demo基于二级分类双列表联动Demo进行了改进,高仿实现了京东的三级类型列表。
京东的如图:

本demo的:

实现了三级列表联动,二三级列表之间的滑动监听优化了一下,将二级类型选中交予自身的点击事件,不再完全依靠三级列表的滑动回调。
//ShapeView
implementation 'com.github.getActivity:ShapeView:9.0'
//Gson解析
implementation 'com.google.code.gson:gson:2.10.1'
ShapeView主要是美化一下二级条目,Gson是为了解析本地的类型json数据
item_type_one
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/item_main_left_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal"
android:padding="5dp">
<TextView
android:id="@+id/type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:layout_marginVertical="15dp" />
</LinearLayout>
item_type_two
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:background="@color/flow"> <com.hjq.shape.view.ShapeButton android:id="@+id/type" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginHorizontal="10dp" android:gravity="center" android:paddingHorizontal="10dp" android:paddingVertical="5dp" android:textSize="18sp" app:shape_radius="10dp" app:shape_solidColor="@android:color/transparent" app:shape_strokeColor="@color/common_accent_color" app:shape_strokeSize="1dp" app:shape_textColor="@color/common_accent_color" app:shape_textPressedColor="@android:color/white" app:shape_type="rectangle" /> </LinearLayout>
item_type_three
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:background="@drawable/radius_white" android:layout_margin="10dp" android:padding="10dp"> <TextView android:id="@+id/type" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="@color/black" android:paddingHorizontal="10dp" app:drawableEndCompat="@drawable/arrows_right_ic" /> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recycler" android:layout_width="match_parent" android:layout_height="wrap_content"/> </LinearLayout>
item_type_four(其实这个才是类型三,上面的是类型三的外围包裹,但是不想改了)
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@color/white" android:gravity="center" android:orientation="vertical"> <ImageView android:id="@+id/icon" android:src="@mipmap/ic_logo" android:layout_margin="5dp" android:layout_width="60dp" android:layout_height="60dp" /> <TextView android:id="@+id/type" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:textSize="14sp" android:text="男鞋" /> </LinearLayout>
由两个列表变成了三个列表
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:background="@color/flow" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/one" android:layout_weight="7" android:layout_width="match_parent" android:layout_height="match_parent"/> <LinearLayout android:layout_weight="3" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/two" android:layout_width="match_parent" android:layout_height="wrap_content"/> <androidx.recyclerview.widget.RecyclerView android:id="@+id/three" android:layout_weight="1" android:layout_marginTop="10dp" android:layout_width="match_parent" android:layout_height="0dp"/> </LinearLayout> </LinearLayout>
OneTypeAdapter
public class OneTypeAdapter extends RecyclerView.Adapter<OneTypeAdapter.OneTypeHolder> { private final Context context; private final List<GoodsTypeBN> list; public int selectedPosition = 0;//当前选择的下标 private OnItemClickListener onItemClickListener; public OneTypeAdapter(Context context, List<GoodsTypeBN> list) { this.context = context; this.list = list; } @NonNull @Override public OneTypeHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view= LayoutInflater.from(context).inflate(R.layout.item_type_one,parent,false); return new OneTypeHolder(view); } @Override public void onBindViewHolder(@NonNull OneTypeHolder holder, @SuppressLint("RecyclerView") int position) { holder.type.setText(list.get(position).getType_name()); holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (selectedPosition != holder.getAdapterPosition()) { //点击了新的 item,更新状态 selectedPosition = holder.getAdapterPosition(); } if (onItemClickListener!=null){ onItemClickListener.onItemClickListener(v,position); } notifyDataSetChanged(); } }); if (position==selectedPosition){ holder.type.setTextColor(context.getColor(R.color.red)); holder.type.setTextSize(30); } else { holder.type.setTextColor(context.getColor(R.color.black)); holder.type.setTextSize(18); } } @Override public int getItemCount() { return list.size(); } public static class OneTypeHolder extends RecyclerView.ViewHolder{ TextView type; public OneTypeHolder(@NonNull View itemView) { super(itemView); type = itemView.findViewById(R.id.type); } } public void setOnItemClickListener(OnItemClickListener onItemClickListener) { this.onItemClickListener = onItemClickListener; } public interface OnItemClickListener { void onItemClickListener(View v, int position); } }
TwoTypeAdapter
public class TwoTypeAdapter extends RecyclerView.Adapter<TwoTypeAdapter.TwoTypeHolder> { private Context context; private List<GoodsTypeBN> list; private OnItemClickListener onItemClickListener; public int selectPosition=0; public TwoTypeAdapter(Context context, List<GoodsTypeBN> list) { this.context = context; this.list = list; } @NonNull @Override public TwoTypeHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view= LayoutInflater.from(context).inflate(R.layout.item_type_two,parent,false); return new TwoTypeHolder(view); } @Override public void onBindViewHolder(@NonNull TwoTypeHolder holder, int position) { holder.type.setText(list.get(position).getType_name()); holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { selectPosition=position; notifyDataSetChanged(); if (onItemClickListener!=null){ onItemClickListener.onItemClickListener(view,position); } } }); if (position==selectPosition){ holder.type.setTextColor(context.getColor(R.color.common_accent_color)); holder.type.getShapeDrawableBuilder() .setStrokeColor(context.getColor(R.color.common_accent_color)) .intoBackground(); } else { holder.type.setTextColor(context.getColor(R.color.grey)); holder.type.getShapeDrawableBuilder() .setStrokeColor(context.getColor(R.color.grey)) .intoBackground(); } } @Override public int getItemCount() { return list.size(); } public static class TwoTypeHolder extends RecyclerView.ViewHolder{ ShapeButton type; public TwoTypeHolder(@NonNull View itemView) { super(itemView); type = itemView.findViewById(R.id.type); } } public void setOnItemClickListener(OnItemClickListener onItemClickListener) { this.onItemClickListener = onItemClickListener; } public interface OnItemClickListener { void onItemClickListener(View v, int position); } }
注意这里,这里二级条目的点击事件下,会将自身选中,自己来选中自己,然后更新,不再交由列表的滑动来更新。


之前的是这样。因为后面的几个条目点击存在一些问题。


ThreeTypeAdapter
public class ThreeTypeAdapter extends RecyclerView.Adapter<ThreeTypeAdapter.ThreeTYpeHolder> { private final Context context; private final List<GoodsTypeBN> list; public ThreeTypeAdapter(Context context, List<GoodsTypeBN> list) { this.context = context; this.list = list; } @NonNull @Override public ThreeTYpeHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view= LayoutInflater.from(context).inflate(R.layout.item_type_three,parent,false); return new ThreeTYpeHolder(view); } @Override public void onBindViewHolder(@NonNull ThreeTYpeHolder holder, int position) { holder.type.setText(list.get(position).getType_name()); holder.recyclerView.setAdapter(new FourAdapter(context,list.get(position).getNextType())); holder.recyclerView.setLayoutManager(new GridLayoutManager(context,3)); } @Override public int getItemCount() { return list.size(); } public static class ThreeTYpeHolder extends RecyclerView.ViewHolder{ TextView type; RecyclerView recyclerView; public ThreeTYpeHolder(@NonNull View itemView) { super(itemView); type = itemView.findViewById(R.id.type); recyclerView = itemView.findViewById(R.id.recycler); } } }
FourAdapter
public class FourAdapter extends RecyclerView.Adapter<FourAdapter.FourHolder> { private final Context context; private final List<GoodsTypeBN> list; public FourAdapter( Context context,List<GoodsTypeBN> list) { this.context = context; this.list = list; } @NonNull @Override public FourHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view= LayoutInflater.from(context).inflate(R.layout.item_type_four,parent,false); return new FourHolder(view); } @Override public void onBindViewHolder(@NonNull FourHolder holder, int position) { GoodsTypeBN goodsTypeBN=list.get(position); holder.type.setText(goodsTypeBN.getType_name()); holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Toast.makeText(context, "点击了"+goodsTypeBN.getType_name(), Toast.LENGTH_SHORT).show(); } }); } @Override public int getItemCount() { return list.size(); } public static class FourHolder extends RecyclerView.ViewHolder{ TextView type; ImageView icon; public FourHolder(@NonNull View itemView) { super(itemView); type = itemView.findViewById(R.id.type); icon = itemView.findViewById(R.id.icon); } } }
GoodsTypeBN类
public class GoodsTypeBN { private String type_id; private String type_name; private String parent_id; private String type_lv; private List<GoodsTypeBN> nextType; public String getType_id() { return type_id; } public void setType_id(String type_id) { this.type_id = type_id; } public String getType_name() { return type_name; } public void setType_name(String type_name) { this.type_name = type_name; } public String getParent_id() { return parent_id; } public void setParent_id(String parent_id) { this.parent_id = parent_id; } public String getType_lv() { return type_lv; } public void setType_lv(String type_lv) { this.type_lv = type_lv; } public List<GoodsTypeBN> getNextType() { return nextType; } public void setNextType(List<GoodsTypeBN> nextType) { this.nextType = nextType; } @Override public String toString() { return "GoodsTypeBN{" + "type_id='" + type_id + '\'' + ", type_name='" + type_name + '\'' + ", parent_id='" + parent_id + '\'' + ", type_lv='" + type_lv + '\'' + ", nextType=" + nextType + '}'; } }
主页面逻辑
//一级类型条目点击 oneTypeAdapter.setOnItemClickListener(new OneTypeAdapter.OnItemClickListener() { @Override public void onItemClickListener(View v, int position) { //更换二级三级类型的数据 typeTwo.clear(); typeTwo.addAll(typeOne.get(position).getNextType()); twoTypeAdapter.selectPosition=0; twoTypeAdapter.notifyDataSetChanged(); threeTypeAdapter.notifyDataSetChanged(); } }); //二级类型条目点击 twoTypeAdapter.setOnItemClickListener(new TwoTypeAdapter.OnItemClickListener() { @Override public void onItemClickListener(View v, int position) { //将三级类型滑动到相应位置 LinearLayoutManager threeLayoutManager = ((LinearLayoutManager) three.getLayoutManager()); if (threeLayoutManager!=null){ threeLayoutManager.scrollToPositionWithOffset(position,0); } } }); //添加三级类型滑动监听 three.addOnScrollListener(onScrollListener);
添加滑动监听
RecyclerView.OnScrollListener onScrollListener = new RecyclerView.OnScrollListener() { /** 获取第一个可见的item的position */ int currentPosition = 0; @Override public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { LinearLayoutManager twoLayoutManager = (LinearLayoutManager) two.getLayoutManager(); LinearLayoutManager threeLayoutManager = ((LinearLayoutManager) three.getLayoutManager()); if (twoLayoutManager!=null&&threeLayoutManager!=null){ currentPosition = threeLayoutManager.findFirstCompletelyVisibleItemPosition(); /** 这地方需要进行判断,如果下面的Recycle在移动的时候,上面的RecyclerView也是需要进行移动的 上面的recyclerview有可能会不可见,这时候,我们必须去判断一下,上面最后的一个item是不是 小于下面滑动的位置,或上面第一个item是不是大于下面滑动的位置 */ if (twoLayoutManager.findFirstCompletelyVisibleItemPosition() > currentPosition) { twoLayoutManager.scrollToPositionWithOffset(currentPosition, 0); } else if (twoLayoutManager.findFirstCompletelyVisibleItemPosition() < currentPosition) { twoLayoutManager.scrollToPositionWithOffset(currentPosition, 0); } // 判断滚动的方向和位置,判断是否触发了回弹效果 if (dy < 0 && !recyclerView.canScrollVertically(-1)) { // 触发了上拉的回弹效果 Log.e("TAG", "onScrolled: 触发了上拉的回弹效果" ); } else if (dy > 0 && !recyclerView.canScrollVertically(1)) { // 触发了下拉的回弹效果 currentPosition = typeTwo.size() - 1; Log.e("TAG", "onScrolled: 触发了下拉的回弹效果" ); } twoTypeAdapter.selectPosition=currentPosition; twoTypeAdapter.notifyDataSetChanged(); } } };
全部代码
public class MainActivity extends AppCompatActivity { private OneTypeAdapter oneTypeAdapter; private TwoTypeAdapter twoTypeAdapter; private ThreeTypeAdapter threeTypeAdapter; private List<GoodsTypeBN> typeOne; private List<GoodsTypeBN> typeTwo=new ArrayList<>(); private List<GoodsTypeBN> typeThree=new ArrayList<>(); private RecyclerView one,two,three; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); one=findViewById(R.id.one); two=findViewById(R.id.two); three=findViewById(R.id.three); init(); } private void init(){ String json = getJson(this, "category.json"); if (!TextUtils.isEmpty(json)){ //解析数据 List<GoodsTypeBN> typeBNBaseEN=new Gson().fromJson(json, new TypeToken<List<GoodsTypeBN>>(){}.getType()); if (typeBNBaseEN!=null){ typeOne=typeBNBaseEN; //设置一级类型 oneTypeAdapter=new OneTypeAdapter(this,typeOne); one.setLayoutManager(new LinearLayoutManager(this)); one.setAdapter(oneTypeAdapter); //设置初始二级类型 typeTwo.clear(); typeTwo.addAll(typeOne.get(0).getNextType()); twoTypeAdapter=new TwoTypeAdapter(this,typeTwo); LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this); linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); two.setLayoutManager(linearLayoutManager); two.setAdapter(twoTypeAdapter); //设置初始三级类型 typeThree.clear(); typeThree.addAll(typeTwo.get(0).getNextType()); threeTypeAdapter=new ThreeTypeAdapter(this,typeTwo); three.setLayoutManager(new LinearLayoutManager(this)); three.setAdapter(threeTypeAdapter); //一级类型条目点击 oneTypeAdapter.setOnItemClickListener(new OneTypeAdapter.OnItemClickListener() { @Override public void onItemClickListener(View v, int position) { //更换二级三级类型的数据 typeTwo.clear(); typeTwo.addAll(typeOne.get(position).getNextType()); twoTypeAdapter.selectPosition=0; twoTypeAdapter.notifyDataSetChanged(); threeTypeAdapter.notifyDataSetChanged(); } }); //二级类型条目点击 twoTypeAdapter.setOnItemClickListener(new TwoTypeAdapter.OnItemClickListener() { @Override public void onItemClickListener(View v, int position) { //将三级类型滑动到相应位置 LinearLayoutManager threeLayoutManager = ((LinearLayoutManager) three.getLayoutManager()); if (threeLayoutManager!=null){ threeLayoutManager.scrollToPositionWithOffset(position,0); } } }); //添加三级类型滑动监听 three.addOnScrollListener(onScrollListener); } } } RecyclerView.OnScrollListener onScrollListener = new RecyclerView.OnScrollListener() { /** 获取第一个可见的item的position */ int currentPosition = 0; @Override public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { LinearLayoutManager twoLayoutManager = (LinearLayoutManager) two.getLayoutManager(); LinearLayoutManager threeLayoutManager = ((LinearLayoutManager) three.getLayoutManager()); if (twoLayoutManager!=null&&threeLayoutManager!=null){ currentPosition = threeLayoutManager.findFirstCompletelyVisibleItemPosition(); /** 这地方需要进行判断,如果下面的Recycle在移动的时候,上面的RecyclerView也是需要进行移动的 上面的recyclerview有可能会不可见,这时候,我们必须去判断一下,上面最后的一个item是不是 小于下面滑动的位置,或上面第一个item是不是大于下面滑动的位置 */ if (twoLayoutManager.findFirstCompletelyVisibleItemPosition() > currentPosition) { twoLayoutManager.scrollToPositionWithOffset(currentPosition, 0); } else if (twoLayoutManager.findFirstCompletelyVisibleItemPosition() < currentPosition) { twoLayoutManager.scrollToPositionWithOffset(currentPosition, 0); } // 判断滚动的方向和位置,判断是否触发了回弹效果 if (dy < 0 && !recyclerView.canScrollVertically(-1)) { // 触发了上拉的回弹效果 Log.e("TAG", "onScrolled: 触发了上拉的回弹效果" ); } else if (dy > 0 && !recyclerView.canScrollVertically(1)) { // 触发了下拉的回弹效果 currentPosition = typeTwo.size() - 1; Log.e("TAG", "onScrolled: 触发了下拉的回弹效果" ); } twoTypeAdapter.selectPosition=currentPosition; twoTypeAdapter.notifyDataSetChanged(); } } }; public static String getJson(Context context, String fileName) { StringBuilder stringBuilder = new StringBuilder(); //获得assets资源管理器 AssetManager assetManager = context.getAssets(); //使用IO流读取json文件内容 try { BufferedReader bufferedReader = new BufferedReader(new InputStreamReader( assetManager.open(fileName), StandardCharsets.UTF_8)); String line; while ((line = bufferedReader.readLine()) != null) { stringBuilder.append(line); } } catch (IOException e) { e.printStackTrace(); } return stringBuilder.toString(); } }
github:https://github.com/panzhusheng/JDCategorydemo
gitee:https://gitee.com/pan-zs/JDCategorydemo
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。