我想在Android的新com.google.android.material.tabs.TabLayout
实现ViewPager
中使用androidx.viewpager2.widget.ViewPager2
组件。但是,setupWithViewPager(..)
提供的TabLayout
方法仅支持旧的ViewPager
实现。有没有一种方法可以轻松地将TabLayout
绑定到ViewPager2
组件?
答案 0 :(得分:13)
我在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>
因此,适配器负责为活动提供正确的片段。 您必须扩展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);
我已将片段添加到我的viewpager中。 (由于我在适配器中对片段进行了硬编码,因此应使用列表以及类似“ addFragment”方法之类的东西)
然后使用
TabLayout tabLayout = findViewById(R.id.tabLayout);
tabLayout.addTab(tabLayout.newTab().setText("Bar"));
tabLayout.addTab(tabLayout.newTab().setText("Foo"));
我在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));
}
});
答案 1 :(得分:9)
您必须使用模仿TabLayoutMediator
的{{3}} tabLayout.setupWithViewPager()
并将ViewPager2
设置为Tablayout
。否则,您将必须编写自己的适配器,以结合双方。
答案 2 :(得分:2)
使用对象TabLayoutMediator
,TabLayout
,ViewPager2
(布尔类型)和对象autoRefresh
初始化OnConfigurationChangeCallback
对象。
TabLayoutMediator tabLayoutMediator = new TabLayoutMediator(tabLayout, viewPager2, true, new TabLayoutMediator.OnConfigureTabCallback() {
@Override
public void onConfigureTab(@NotNull TabLayout.Tab tab, int position) {
// position of the current tab and that tab
}
});
最后,只需向attach()
对象调用TabLayoutMediator
,即可将标签布局连接到viewpager :-
tabLayoutMediator.attach();
autoRefresh
-如果设置为true
,则为键-(默认情况下,其设置为true)
的内容
RECREATES
(如果调用了tabLayout
到视图分页器notifyDataSetChanged
,则adapter
的所有标签。
答案 3 :(得分:2)
如果您使用 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();
}
}
答案 4 :(得分:0)
这里是更新答案如何在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()
}
}
输出
答案 5 :(得分:0)
您可以使用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"))
答案 6 :(得分:0)
我正在实现'com.google.android.material:material:1.2.1'上运行我的搜索,也没有使用tabLayoutMediator。对于初学者来说,https://developer.android.com/jetpack/androidx/migrate/class-mappings在androidX中已更改为TabLayout,因此请确保在import语句中使用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);
}
}
我在另一个类中也使用了片段适配器设置,在那里我将上下文传递给了不同Tab的构造器
答案 7 :(得分:0)
如果您的标签标题来自string.xml
。
您可以将 fragment
和 title
放在一个 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)
}
}
}
答案 8 :(得分:0)
确保使用 TabLayoutMediator get_text(strip=True)
after your set adapter to view_pager2