先上图:
Demo解释
demo使用的是双列表展示(准确的说是三个,二级分类那里嵌套了一个),点击左边的条目,右边的列表会跳转相应的条目,滑动右边的列表,左边的列表也会相应的滑动。
代码
主页面布局
这个很简单,就是两个RecyclerView
<?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: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"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/two"
android:layout_weight="3"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
适配器
因为有三个列表RecyclerView,所以有三个适配器:
OneTypeAdapter
public class OneTypeAdapter extends RecyclerView.Adapter<OneTypeAdapter.OneTypeHolder> {
private final Context context;
private final List<String> list;
public int selectedPosition = 0;//当前选择的下标
private OnItemClickListener onItemClickListener;
public OneTypeAdapter(Context context, List<String> 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_main_left,parent,false);
return new OneTypeHolder(view);
}
@Override
public void onBindViewHolder(@NonNull OneTypeHolder holder, @SuppressLint("RecyclerView") int position) {
holder.type.setText(list.get(position));
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (onItemClickListener!=null){
onItemClickListener.onItemClickListener(v,position);
}
}
});
if (position==selectedPosition){
holder.itemView.setBackgroundColor(context.getColor(R.color.white));
holder.type.setTextColor(context.getColor(R.color.colorAccent));
holder.type.setTextSize(32);
}
else {
holder.itemView.setBackgroundColor(context.getColor(R.color.flow));
holder.type.setTextColor(context.getColor(R.color.black));
holder.type.setTextSize(24);
}
}
@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<String> name;
private List<String> detail;
public TwoTypeAdapter(Context context, List<String> name, List<String> detail) {
this.context = context;
this.name = name;
this.detail = detail;
}
@NonNull
@Override
public TwoTypeHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view= LayoutInflater.from(context).inflate(R.layout.item_main_right,parent,false);
return new TwoTypeHolder(view);
}
@Override
public void onBindViewHolder(@NonNull TwoTypeHolder holder, int position) {
holder.type.setText(name.get(position));
holder.more.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(context, "更多", Toast.LENGTH_SHORT).show();
}
});
holder.recyclerView.setAdapter(new DetailAdapter(context, detail));
holder.recyclerView.setLayoutManager(new GridLayoutManager(context,3));
}
@Override
public int getItemCount() {
return name.size();
}
public static class TwoTypeHolder extends RecyclerView.ViewHolder{
TextView type,more;
RecyclerView recyclerView;
public TwoTypeHolder(@NonNull View itemView) {
super(itemView);
type = itemView.findViewById(R.id.type);
more = itemView.findViewById(R.id.more);
recyclerView = itemView.findViewById(R.id.right_recycle);
}
}
}
DetailAdapter
public class DetailAdapter extends RecyclerView.Adapter<DetailAdapter.ThreeTYpeHolder> {
private final Context context;
private final List<String> list;
public DetailAdapter(Context context, List<String> 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_main_details,parent,false);
return new ThreeTYpeHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ThreeTYpeHolder holder, int position) {
holder.type.setText(list.get(position));
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(context, list.get(position), Toast.LENGTH_SHORT).show();
}
});
}
@Override
public int getItemCount() {
return list.size();
}
public static class ThreeTYpeHolder extends RecyclerView.ViewHolder{
TextView type;
ImageView icon;
public ThreeTYpeHolder(@NonNull View itemView) {
super(itemView);
type = itemView.findViewById(R.id.type);
icon = itemView.findViewById(R.id.icon);
}
}
}
条目布局
item_main_left
<?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_main_right
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:background="#fff"
android:padding="10dp">
<TextView
android:id="@+id/type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#333"
android:textSize="18sp" />
<TextView
android:id="@+id/more"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="查看更多 >"
android:layout_alignParentEnd="true"
android:textColor="#999"
android:textSize="14sp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/right_recycle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/type"/>
</RelativeLayout>
item_main_details
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ffffff"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/icon"
android:layout_width="70dp"
android:layout_height="70dp" />
<TextView
android:id="@+id/type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp" />
</LinearLayout>
主页面代码
左边条目点击事件回调
oneTypeAdapter.setOnItemClickListener(new OneTypeAdapter.OnItemClickListener() {
@Override
public void onItemClickListener(View v, int position) {
LinearLayoutManager twoRecyclerLayoutManager = ((LinearLayoutManager) twoRecycler.getLayoutManager());
if (twoRecyclerLayoutManager!=null){
/**
这里有个问题,可能因为字号等问题,左边最后n个条目可能出现点击了但是颜色没渲染上的问题,不知道啥原因
然后我就是最后n个点击事件手动处理,比如我这就是最后3个点击有问题
*/
if (position>= oneList.size()-3){
oneTypeAdapter.selectedPosition=position;
oneTypeAdapter.notifyDataSetChanged();
twoRecyclerLayoutManager.scrollToPositionWithOffset(position,0);
}
else {
twoRecyclerLayoutManager.scrollToPositionWithOffset(position,0);
}
}
}
});
右边列表滑动监听
twoRecycler.setOnScrollChangeListener(new View.OnScrollChangeListener() {
@Override
public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
LinearLayoutManager twoRecyclerLayoutManager = (LinearLayoutManager) twoRecycler.getLayoutManager();
LinearLayoutManager oneRecyclerLayoutManager = ((LinearLayoutManager) oneRecycler.getLayoutManager());
if (twoRecyclerLayoutManager!=null&&oneRecyclerLayoutManager!=null){
/**
获取第一个可见的item的position
*/
currentPosition = twoRecyclerLayoutManager.findFirstVisibleItemPosition();
Log.e("TAG", "onScrollChange: "+currentPosition );
/**
这地方需要进行判断,如果右边的Recycle在移动的时候,左边的RecyclerView也是需要进行移动的
左边的recyclerview有可能会不可见,这时候,我们必须去判断一下,左边最后的一个item是不是
小于右边滑动的位置,或左边第一个item是不是大于右边滑动的位置
*/
if (oneRecyclerLayoutManager.findFirstVisibleItemPosition() > currentPosition) {
oneRecyclerLayoutManager.scrollToPositionWithOffset(currentPosition, 0);
} else if (oneRecyclerLayoutManager.findFirstVisibleItemPosition() < currentPosition) {
oneRecyclerLayoutManager.scrollToPositionWithOffset(currentPosition, 0);
}
/**
判断右边是否滑动到最后一个item,是的话,也将左边移动到最后一个item
canScrollVertically(1)表示是否能向上滚动,false表示已经滚动到底部
*/
if (!twoRecycler.canScrollVertically(1)) {
currentPosition = oneList.size() - 1;
}
oneTypeAdapter.selectedPosition=currentPosition;
oneTypeAdapter.notifyDataSetChanged();
}
}
});
完整代码
public class MainActivity extends AppCompatActivity {
private RecyclerView oneRecycler;
private RecyclerView twoRecycler;
private OneTypeAdapter oneTypeAdapter;
private TwoTypeAdapter twoTypeAdapter;
private List<String> oneList = new ArrayList<>();
private List<String> twoList = new ArrayList<>();
private int currentPosition = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
oneRecycler = findViewById(R.id.one);
twoRecycler = findViewById(R.id.two);
oneRecycler.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
twoRecycler.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
oneTypeAdapter=new OneTypeAdapter(this, oneList);
twoTypeAdapter=new TwoTypeAdapter(this, oneList,twoList);
oneRecycler.setAdapter(oneTypeAdapter);
twoRecycler.setAdapter(twoTypeAdapter);
oneTypeAdapter.setOnItemClickListener(new OneTypeAdapter.OnItemClickListener() {
@Override
public void onItemClickListener(View v, int position) {
LinearLayoutManager twoRecyclerLayoutManager = ((LinearLayoutManager) twoRecycler.getLayoutManager());
if (twoRecyclerLayoutManager!=null){
/**
这里有个问题,可能因为字号等问题,左边最后n个条目可能出现点击了但是颜色没渲染上的问题,不知道啥原因
然后我就是最后n个点击事件手动处理,比如我这就是最后3个点击有问题
*/
if (position>= oneList.size()-3){
oneTypeAdapter.selectedPosition=position;
oneTypeAdapter.notifyDataSetChanged();
twoRecyclerLayoutManager.scrollToPositionWithOffset(position,0);
}
else {
twoRecyclerLayoutManager.scrollToPositionWithOffset(position,0);
}
}
}
});
twoRecycler.setOnScrollChangeListener(new View.OnScrollChangeListener() {
@Override
public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
LinearLayoutManager twoRecyclerLayoutManager = (LinearLayoutManager) twoRecycler.getLayoutManager();
LinearLayoutManager oneRecyclerLayoutManager = ((LinearLayoutManager) oneRecycler.getLayoutManager());
if (twoRecyclerLayoutManager!=null&&oneRecyclerLayoutManager!=null){
/**
获取第一个可见的item的position
*/
currentPosition = twoRecyclerLayoutManager.findFirstVisibleItemPosition();
Log.e("TAG", "onScrollChange: "+currentPosition );
/**
这地方需要进行判断,如果右边的Recycle在移动的时候,左边的RecyclerView也是需要进行移动的
左边的recyclerview有可能会不可见,这时候,我们必须去判断一下,左边最后的一个item是不是
小于右边滑动的位置,或左边第一个item是不是大于右边滑动的位置
*/
if (oneRecyclerLayoutManager.findFirstVisibleItemPosition() > currentPosition) {
oneRecyclerLayoutManager.scrollToPositionWithOffset(currentPosition, 0);
} else if (oneRecyclerLayoutManager.findFirstVisibleItemPosition() < currentPosition) {
oneRecyclerLayoutManager.scrollToPositionWithOffset(currentPosition, 0);
}
/**
判断右边是否滑动到最后一个item,是的话,也将左边移动到最后一个item
canScrollVertically(1)表示是否能向上滚动,false表示已经滚动到底部
*/
if (!twoRecycler.canScrollVertically(1)) {
currentPosition = oneList.size() - 1;
}
oneTypeAdapter.selectedPosition=currentPosition;
oneTypeAdapter.notifyDataSetChanged();
}
}
});
}
private void initData() {
for (int i = 0; i < 20; i++) {
oneList.add("一级类型"+i);
}
for (int i=0;i<10;i++){
twoList.add("二级类型"+i);
}
}
}
源码地址:
github:Categorydemo
gitee:Categorydemo