You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于单个RecyclerView实现TabLayout+ViewPager的数据切换需求

实现TabLayout+ViewPager联动并复用RecyclerView切换数据

1. 编写布局文件

主布局(activity_main.xml)

顶部放置TabLayout,下方是承载RecyclerView的ViewPager:

<?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="match_parent"
    android:orientation="vertical">

    <com.google.android.material.tabs.TabLayout
        android:id="@+id/tabLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:tabMode="fixed"
        app:tabGravity="fill"/>

    <androidx.viewpager.widget.ViewPager
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>

ViewPager的页面容器(item_recycler_container.xml)

仅包含一个RecyclerView,用于后续复用:

<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/recyclerView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

2. 实现ViewPager适配器

核心逻辑是只初始化一次RecyclerView,切换Tab时仅更新数据:

public class RecyclerPagerAdapter extends PagerAdapter {
    private Context mContext;
    private List<String> mTabTitles;
    private RecyclerView mRecyclerView;
    private RecyclerAdapter mAdapter;
    private List<List<String>> mDataList;
    private ViewPager mViewPager;

    public RecyclerPagerAdapter(Context context, List<String> tabTitles, List<List<String>> dataList) {
        mContext = context;
        mTabTitles = tabTitles;
        mDataList = dataList;
    }

    @Override
    public int getCount() {
        return mTabTitles.size();
    }

    @Override
    public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
        return view == object;
    }

    @NonNull
    @Override
    public Object instantiateItem(@NonNull ViewGroup container, int position) {
        // 仅初始化一次RecyclerView实例
        if (mRecyclerView == null) {
            View view = LayoutInflater.from(mContext).inflate(R.layout.item_recycler_container, container, false);
            mRecyclerView = view.findViewById(R.id.recyclerView);
            mRecyclerView.setLayoutManager(new LinearLayoutManager(mContext));
            mAdapter = new RecyclerAdapter();
            mRecyclerView.setAdapter(mAdapter);

            // 监听RecyclerView滑动,到达边界时切换ViewPager页面
            mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
                @Override
                public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                    super.onScrolled(recyclerView, dx, dy);
                    LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
                    if (layoutManager == null) return;

                    // 滑到顶部,切换上一个Tab
                    if (dy < 0 && layoutManager.findFirstCompletelyVisibleItemPosition() == 0) {
                        if (mViewPager.getCurrentItem() > 0) {
                            mViewPager.setCurrentItem(mViewPager.getCurrentItem() - 1, true);
                        }
                    }
                    // 滑到底部,切换下一个Tab
                    else if (dy > 0 && layoutManager.findLastCompletelyVisibleItemPosition() == mAdapter.getItemCount() - 1) {
                        if (mViewPager.getCurrentItem() < getCount() - 1) {
                            mViewPager.setCurrentItem(mViewPager.getCurrentItem() + 1, true);
                        }
                    }
                }
            });
            container.addView(view);
            return view;
        }
        // 复用已有RecyclerView,直接更新数据
        updateData(position);
        return mRecyclerView;
    }

    @Override
    public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
        // 因需要复用,此处不执行销毁操作
    }

    @Nullable
    @Override
    public CharSequence getPageTitle(int position) {
        return mTabTitles.get(position);
    }

    // 更新RecyclerView数据的方法
    public void updateData(int position) {
        if (mAdapter != null && position < mDataList.size()) {
            mAdapter.setData(mDataList.get(position));
        }
    }

    public void setViewPager(ViewPager viewPager) {
        mViewPager = viewPager;
    }
}

3. 实现RecyclerView适配器

简单的列表适配器,支持数据刷新:

public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> {
    private List<String> mData = new ArrayList<>();

    public void setData(List<String> data) {
        mData.clear();
        mData.addAll(data);
        notifyDataSetChanged();
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_list_item_1, parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        holder.tvContent.setText(mData.get(position));
    }

    @Override
    public int getItemCount() {
        return mData.size();
    }

    static class ViewHolder extends RecyclerView.ViewHolder {
        TextView tvContent;
        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            tvContent = itemView.findViewById(android.R.id.text1);
        }
    }
}

4. 主Activity绑定逻辑

初始化控件,完成联动配置和数据填充:

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TabLayout tabLayout = findViewById(R.id.tabLayout);
        ViewPager viewPager = findViewById(R.id.viewPager);

        // 模拟Tab标题和对应数据集合
        List<String> tabTitles = Arrays.asList("Tab1", "Tab2", "Tab3");
        List<List<String>> dataList = new ArrayList<>();
        dataList.add(generateData("Tab1数据"));
        dataList.add(generateData("Tab2数据"));
        dataList.add(generateData("Tab3数据"));

        RecyclerPagerAdapter adapter = new RecyclerPagerAdapter(this, tabTitles, dataList);
        adapter.setViewPager(viewPager);
        viewPager.setAdapter(adapter);
        tabLayout.setupWithViewPager(viewPager);

        // 监听ViewPager页面切换,更新数据并将RecyclerView滚到顶部
        viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}

            @Override
            public void onPageSelected(int position) {
                adapter.updateData(position);
                if (adapter.mRecyclerView != null) {
                    adapter.mRecyclerView.scrollToPosition(0);
                }
            }

            @Override
            public void onPageScrollStateChanged(int state) {}
        });
    }

    // 生成模拟数据的工具方法
    private List<String> generateData(String prefix) {
        List<String> data = new ArrayList<>();
        for (int i = 1; i <= 20; i++) {
            data.add(prefix + " - " + i);
        }
        return data;
    }
}

核心逻辑说明

  • 复用RecyclerView:ViewPager适配器仅创建一次RecyclerView实例,切换Tab时只更新列表数据,避免重复创建视图浪费资源。
  • Tab与ViewPager联动:通过tabLayout.setupWithViewPager(viewPager)快速实现点击Tab切换页面、滑动ViewPager同步Tab选中状态的效果。
  • 滑动RecyclerView切数据:给RecyclerView添加滑动监听,当滑到列表顶部/底部时,自动触发ViewPager切换页面,进而更新RecyclerView展示的数据。

内容的提问来源于stack exchange,提问作者mobin jafari

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 08:35:29