【问题标题】:How to use TabLayout with ViewPager2 in Android如何在 Android 中使用 TabLayout 和 ViewPager2
【发布时间】:2019-08-17 17:28:49
【问题描述】:

我想将com.google.android.material.tabs.TabLayout 组件与Android 的新ViewPager 实现androidx.viewpager2.widget.ViewPager2 一起使用。但是,TabLayout 提供的setupWithViewPager(..) 方法只支持旧的ViewPager 实现。有没有办法轻松地将TabLayout 绑定到ViewPager2 组件?

【问题讨论】:

标签: java android androidx android-tablayout android-viewpager2


【解决方案1】:

您的布局已准备好,片段已准备好,适配器已准备好。 你现在只需要设置一个事件监听器来

tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener(){

        @Override
        public void onTabSelected(TabLayout.Tab tab) {
            viewPager.setCurrentItem(tab.getPosition());
        }

        @Override
        public void onTabUnselected(TabLayout.Tab tab) {

        }

        @Override
        public void onTabReselected(TabLayout.Tab tab) {

        }
    });

这应该将选项卡布局绑定到您的 ViewPager2。

【讨论】:

    【解决方案2】:

    您必须使用 this TabLayoutMediator 模仿 tabLayout.setupWithViewPager() 并设置 ViewPager2Tablayout。否则,您将不得不编写自己的适配器来结合双方。

    它的代码在 Kotlin 中会是这样的

    TabLayoutMediator(tabLayout, viewPager) { tab, position ->
      tab.text = tabTitles[position]
    }.attach()
    

    【讨论】:

    • 使用这个TabLayoutMediator的代码如下:TabLayoutMediator(tabLayout, viewPager2) { tab, position -> viewPager2.setCurrentItem(tab.position, true) if (position == 1) tab.setText("Test2") if (position == 0) tab.setText("Test1") }.attach()
    • 任何阅读本文的人都应该仔细检查他们应用程序的材料库版本。 TabLayoutMediator 存在于implementation 'com.google.android.material:material:1.1.0-alpha08' 中,但android studio 默认为我导入了1.0.0 版本,它没有这个。
    • 如何在 TabLayout 上设置点(如轮播),而不是选项卡中的数字?
    • viewPager.setCurrentItem(tab.position, true) 是不必要的,会导致选择第二个选项卡并始终滑动页面!
    • @ericn 你是对的兄弟,设置当前项目是自己完成的。
    【解决方案3】:

    很简单:

    java代码:

    tabLayout=findViewById(R.id.tabLayout);
        viewPager=findViewById(R.id.viewPager);
        viewPager.setAdapter(new ViewPagerAdapter(this));
    
        new TabLayoutMediator(tabLayout, viewPager, new TabLayoutMediator.TabConfigurationStrategy() {
            @Override
            public void onConfigureTab(@NonNull TabLayout.Tab tab, int position) {
                if (position==0){
                    tab.setText(R.string.photos);
                    tab.view.setBackground(getResources().getDrawable(R.drawable.ic_rectangle_1345));
                }
                else {
                    tab.setText(R.string.videos);
                }
            }
        }).attach();
    
        tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                tab.view.setBackground(getResources().getDrawable(R.drawable.ic_rectangle_1345));
            }
    
            @Override
            public void onTabUnselected(TabLayout.Tab tab) {
                tab.view.setBackgroundColor(Color.TRANSPARENT);
            }
    
            @Override
            public void onTabReselected(TabLayout.Tab tab) {
    
            }
        });
    

    适配器:

    public class ViewPagerAdapter extends FragmentStateAdapter {
    public ViewPagerAdapter(@NonNull FragmentActivity fragmentActivity) {
        super(fragmentActivity);
    }
    
    @NonNull
    @Override
    public Fragment createFragment(int position) {
        if (position==0) {
            return new PhotosFragment();
        }
        else {
            return new VideosFragment();
        }
    }
    
    @Override
    public int getItemCount() {
        return 2;
    }}
    

    XML:

    <com.google.android.material.tabs.TabLayout
        android:id="@+id/tabLayout"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:background="@color/tool_bar_bg"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/collection_bar" />
    
    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/tabLayout" />
    

    【讨论】:

      【解决方案4】:

      确保使用 TabLayoutMediator after your set adapter to view_pager2

      TabLayoutMediator(tab_layout, view_pager2) { tab, position ->
                      tab.text = fragmentList[position].second  // here u can modify you text..
                  }.attach()
      

      【讨论】:

        【解决方案5】:

        如果您使用 JAVA 编码。您可以为 viewPager2 使用以下适配器:

        public class ViewPagerAdapter extends FragmentStateAdapter {
          private static final int CARD_ITEM_SIZE = 10;
          public ViewPagerAdapter(@NonNull FragmentActivity fragmentActivity) {
            super(fragmentActivity);
          }
          @NonNull @Override public Fragment createFragment(int position) {
            return CardFragment.newInstance(position);
          }
          @Override public int getItemCount() {
            return CARD_ITEM_SIZE;
          }
        }
        

        在 mainActivity 上,您需要有以下内容:

        @Override
          protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            viewPager = findViewById(R.id.view_pager);
            tabLayout = findViewById(R.id.tabs);
            viewPager.setAdapter(new ViewPagerAdapter(this));
            new TabLayoutMediator(tabLayout, viewPager,
                new TabLayoutMediator.TabConfigurationStrategy() {
                  @Override public void onConfigureTab(@NonNull TabLayout.Tab tab, int position) {
                    tab.setText("Tab " + (position + 1));
                  }
                }).attach();
          }
        }
        

        【讨论】:

        • 谢谢!我喜欢随机的代码片段,没有明确的方向来放置它们,就像下一个人一样,但这个答案对我来说是缺失的部分。
        • 好的。只要你开心。我很高兴。关于全程辅导,我们可以安排上课。给我留言!
        【解决方案6】:

        如果您的标签标题来自string.xml
        您可以将fragmenttitle 放在List 中,然后通过TabLayoutMediator 设置标题。它可以帮助您轻松地重新排序、删除或添加新片段

        class MyFragment : Fragment() {
        
            override fun onCreateView(...): View? {
                ...
        
                TabLayoutMediator(tabLayout, viewPager) { tab, position ->
                    tab.text = pagerAdapter.getTabTitle(position)
                }.attach()
            }
        
            private inner class PagerAdapter(fa: FragmentActivity) : FragmentStateAdapter(fa) {
                val pages = listOf(
                    Pair(HomeFragment.newInstance(), R.string.home),
                    Pair(GraphFragment.newInstance(), R.string.graph),
                    Pair(SettingFragment.newInstance(), R.string.setting),
                )
        
                override fun createFragment(position: Int): Fragment {
                    return pages[position].first
                }
        
                override fun getItemCount(): Int {
                    return pages.count()
                }
        
                fun getTabTitle(position: Int): String {
                    return getString(pages[position].second)
                }
            }
        }
        

        【讨论】:

          【解决方案7】:

          我在实现 'com.google.android.material:material:1.2.1' 上运行我的,也没有使用 tabLayoutMediator。对于初学者,https://developer.android.com/jetpack/androidx/migrate/class-mappings 已针对 androidX 中的 TabLayout 进行了更改,因此请确保在导入语句中使用 com.google.android.material.tabs.TabLayout。 下面是我实现解决方案的其余部分: viewPager和TabLayout的xml布局声明

          <?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"
              xmlns:app="http://schemas.android.com/apk/res-auto"
              android:background="@color/tan_background"
              android:orientation="vertical">
          
              <com.google.android.material.tabs.TabLayout
                  android:id="@+id/tabs"
                  android:layout_width="match_parent"
                  android:layout_height="wrap_content"/>
          
              <androidx.viewpager2.widget.ViewPager2
                  android:id="@+id/viewpager"
                  app:layout_anchor="@id/tabs"
                  app:layout_anchorGravity="bottom"
                  android:layout_width="match_parent"
                  android:layout_height="match_parent"/>
          
          </LinearLayout>
          

          和活动文件

          @Override
              protected void onCreate(Bundle savedInstanceState) {
                  super.onCreate(savedInstanceState);
          
                  // Set the content of the activity to use the activity_main.xml layout file
                  setContentView(layout.activity_main);
          
                  // Find the view pager that will allow the user to swipe between fragments
                  ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
          
                  // Create an adapter that knows which fragment should be shown on each page
                  SimpleFragmentPagerAdapter adapter = new SimpleFragmentPagerAdapter(this,getSupportFragmentManager());
          
                  // Set the adapter onto the view pager
                  viewPager.setAdapter(adapter);
          
                  // Find the tab layout that shows the tabs
                  TabLayout tabLayout = findViewById(R.id.tabs);
          
                  // Connect the tab layout with the view pager. This will
                  //   1. Update the tab layout when the view pager is swiped
                  //   2. Update the view pager when a tab is selected
                  //   3. Set the tab layout's tab names with the view pager's adapter's titles
                  //      by calling onPageTitle()
                  tabLayout.setupWithViewPager(viewPager);
              }
          }
          

          我也在不同的类中使用了片段适配器设置,我将上下文传递给不同选项卡的构造函数

          【讨论】:

            【解决方案8】:

            没有 hack、没有扩展、没有 TabLayoutMediator

            我在implementation 'com.google.android.material:material:1.2.0-alpha02' 上并执行以下操作而不需要 TabLayoutMediator。 相反,我使用here 描述的方法将 TabLayout 与 ViewPager2 链接起来。我还向 github here 添加了一个工作示例。我想我已经将解决​​方案最小化为一个最小的工作示例。我将解释重要的部分。

            将元素添加到模板中

            首先,我们需要将 TabLayout 和 ViewPager2 添加到布局中。我在这里将它们放置在 LinearLayout 和 CoordinatorLayout 中,当然你可以做任何你喜欢的事情。

            <!-- activity_main.xml -->
            <?xml version="1.0" encoding="utf-8"?>
            <androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
                android:layout_height="match_parent"
                tools:context=".MainActivity">
            
                <androidx.coordinatorlayout.widget.CoordinatorLayout
                    android:layout_width="match_parent"
                    android:layout_height="match_parent">
            
                    <LinearLayout
                        android:orientation="vertical"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content">
            
                        <com.google.android.material.tabs.TabLayout
                            android:id="@+id/tabLayout"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"/>
                        <androidx.viewpager2.widget.ViewPager2
                            android:id="@+id/pager"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"/>
            
                    </LinearLayout>
            
                </androidx.coordinatorlayout.widget.CoordinatorLayout>
            
            </androidx.constraintlayout.widget.ConstraintLayout>
            

            将适配器连接到 viewpager

            因此适配器负责为活动提供正确的片段。 您必须扩展FragmentStateAdapter,我在下面非常简单地完成了它(它是一个私有类,因为它在我的 MainActivity.java 中声明):

                private class ViewStateAdapter extends FragmentStateAdapter {
            
                    public ViewStateAdapter(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle) {
                        super(fragmentManager, lifecycle);
                    }
            
                    @NonNull
                    @Override
                    public Fragment createFragment(int position) {
                        // Hardcoded in this order, you'll want to use lists and make sure the titles match
                        if (position == 0) {
                            return new BarFragment();
                        }
                        return new FooFragment();
                    }
            
                    @Override
                    public int getItemCount() {
                        // Hardcoded, use lists
                        return 2;
                    }
                }
            

            然后我可以将我自己的适配器连接到 ViewPager,如下所示:

            FragmentManager fm = getSupportFragmentManager();
            ViewStateAdapter sa = new ViewStateAdapter(fm, getLifecycle());
            final ViewPager2 pa = findViewById(R.id.pager);
            pa.setAdapter(sa);
            

            我已将片段添加到我的浏览器中。 (因为我在适配器中对 Fragments 进行了硬编码,所以您应该使用列表和类似“addFragment”方法之类的东西)

            标签布局

            然后用

            TabLayout tabLayout = findViewById(R.id.tabLayout);
            tabLayout.addTab(tabLayout.newTab().setText("Bar"));
            tabLayout.addTab(tabLayout.newTab().setText("Foo"));
            

            我在我的 TabLayout 中添加了两个选项卡,显示标题但还没有让我切换到片段。

            将 TabLayout 连接到适配器

            tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
                        @Override
                        public void onTabSelected(TabLayout.Tab tab) {
                            pa.setCurrentItem(tab.getPosition());
                        }
            
                        @Override
                        public void onTabUnselected(TabLayout.Tab tab) {
            
                        }
            
                        @Override
                        public void onTabReselected(TabLayout.Tab tab) {
            
                        }
                    });
            

            这应该很简单。用户点击一个选项卡,我在回调中获得了位置,然后我只需将适配器的当前项目设置为该位置。

            滑动时切换标签

            最后,当用户滑动片段以将正确的选项卡项设置为选中时,我们会返回

            pa.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
                @Override
                public void onPageSelected(int position) {
                    tabLayout.selectTab(tabLayout.getTabAt(position));
                }
            });
            

            【讨论】:

            • 不错的解决方案!按预期工作。
            • 干得好。欣赏 GitHub 上的项目。谢谢!
            • 感谢您的回答,您能告诉我在选项卡之间滑动会导致片段被重新创建吗?
            【解决方案9】:

            使用TabLayoutViewPager2autoRefresh 的对象初始化TabLayoutMediator 对象——布尔类型和OnConfigurationChangeCallback 的对象。

            TabLayoutMediator tabLayoutMediator = new TabLayoutMediator(tabLayout, viewPager2, true, new TabLayoutMediator.OnConfigureTabCallback() {
              @Override
              public void onConfigureTab(TabLayout.Tab tab, int position) {
                // position of the current tab and that tab  
              }
            });
            

            最后只需调用attach()TabLayoutMediator 对象将tablayout 连接到viewpager :-

             tabLayoutMediator.attach();
            

            autoRefresh - 如果设置为 true 则为键 - (默认设置为 true )

            RECREATES 如果notifyDataSetChanged 被调用到viewpager adapter,则tabLayout 的所有选项卡。

            使用TabLayoutMediator.java的内容

            【讨论】:

              【解决方案10】:

              更新

              检查这个Create swipe views with tabs using ViewPager2

              这是更新的答案如何在 Android 中使用 TabLayout 和 ViewPager2

              现在我们不需要从 TabLayoutMediator 创建一个类

              在下面使用dependencies

              implementation 'com.google.android.material:material:1.1.0-alpha08'
              implementation 'androidx.viewpager2:viewpager2:1.0.0-beta02'
              

              示例代码

              XML 布局

              <?xml version="1.0" encoding="utf-8"?>
              <androidx.coordinatorlayout.widget.CoordinatorLayout
                      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:layout_width="match_parent"
                      android:layout_height="match_parent">
              
                  <com.google.android.material.appbar.AppBarLayout
                          android:layout_width="match_parent"
                          android:layout_height="wrap_content"
                          android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
              
                      <androidx.appcompat.widget.Toolbar
                              android:id="@+id/toolbar"
                              android:layout_width="match_parent"
                              android:layout_height="?attr/actionBarSize"
                              android:background="?attr/colorPrimary"
                              app:layout_scrollFlags="scroll|enterAlways"
                              app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
              
                      <com.google.android.material.tabs.TabLayout
                              android:id="@+id/tabs"
                              android:layout_width="match_parent"
                              android:layout_height="wrap_content"/>
                  </com.google.android.material.appbar.AppBarLayout>
              
                  <androidx.viewpager2.widget.ViewPager2
                          android:id="@+id/viewpager"
                          app:layout_anchor="@id/tabs"
                          app:layout_anchorGravity="bottom"
                          android:layout_width="match_parent"
                          android:layout_height="match_parent"
                  />
              
              
              </androidx.coordinatorlayout.widget.CoordinatorLayout>
              

              活动

              import androidx.appcompat.app.AppCompatActivity
              import android.os.Bundle
              import kotlinx.android.synthetic.main.activity_main.*
              import com.google.android.material.tabs.TabLayoutMediator
              
              import com.google.android.material.tabs.TabLayout
              
              
              class MainActivity : AppCompatActivity() {
              
                  override fun onCreate(savedInstanceState: Bundle?) {
                      super.onCreate(savedInstanceState)
                      setContentView(R.layout.activity_main)
              
              //        setSupportActionBar(toolbar)
                      viewpager.adapter = AppViewPagerAdapter(supportFragmentManager, lifecycle)
              
                      TabLayoutMediator(tabs, viewpager, object : TabLayoutMediator.OnConfigureTabCallback {
                          override fun onConfigureTab(tab: TabLayout.Tab, position: Int) {
                              // Styling each tab here
                              tab.text = "Tab $position"
                          }
                      }).attach()
              
              
                  }
              }
              

              更新

              如果您使用implementation 'com.google.android.material:material:1.1.0-alpha10',请使用以下代码

                      TabLayoutMediator(tabs, viewpage,
                      TabLayoutMediator.TabConfigurationStrategy { tab, position ->
                          when (position) {
                              0 -> { tab.text = "TAB ONE"}
                              1 -> { tab.text = "TAB TWO"}
                          }
                      }).attach()
              

              输出

              【讨论】:

              • 任何阅读本文的人都应该仔细检查他们应用程序的材料库版本。这个版本对我有用,但是android studio默认导入了1.0.0版本,没有这个
              • @anshsachdeva 相同,我在 com.google.android.material:material:1.0.0-alpha08、com.google.android.material:material:1.0.0-alpha09 中找不到 TabLayoutMediator 类。
              • @Seyid-KananBagirov 它存在于实现 'com.google.android.material:material:1.1.0-alpha08' 中(注意版本 1.1.0-alpha08 而不是 1.0.0)
              • 在 1.1.0-alpha10 中,他们将 TabLayoutMediator.OnConfigureTabCallback 重命名为 TabLayoutMediator.TabConfigurationStrategy
              • @androiddeveloper 是的,请查看更新后的答案
              【解决方案11】:

              您可以使用 Kotlin 扩展功能:

              fun TabLayout.setupWithViewPager(viewPager: ViewPager2, labels: List<String>) {
              
                  if (labels.size != viewPager.adapter?.itemCount)
                      throw Exception("The size of list and the tab count should be equal!")
              
                  TabLayoutMediator(this, viewPager,
                      TabLayoutMediator.TabConfigurationStrategy { tab, position ->
                          tab.text = labels[position]
                      }).attach()
              }
              

              然后称呼它:

               tabLayout.setupWithViewPager(viewPager, listOf("Tab A", "Tab B"))
              

              【讨论】:

              • 我需要添加什么依赖才能使用这个扩展乐趣?
              • 为了使用扩展功能,除了 Kotlin 没有任何依赖 :)
              • 是的,我知道。我的意思是我必须添加什么 Android KTX 工件才能使用此扩展功能。我也没有setupWithViewPager(ViewPager2, List) 可用——我只有setupWithViewPager(ViewPager)
              • 您应该实现 ViewPager2 (androidx.viewpager2:1.0.0) 和 matarial 组件 (com.google.android.material:material:1.2.0-alpha03) 作为能够使用此扩展功能的工件.
              • 而且我还建议使用 ViewPager2 而不是旧的 ViewPager 组件。
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2021-01-12
              • 1970-01-01
              • 1970-01-01
              • 2022-12-21
              • 1970-01-01
              • 2022-01-07
              相关资源
              最近更新 更多