- 废话不多说,直接上图

代码展示
-
布局
<?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="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:paddingStart="16dp" android:paddingEnd="16dp"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:text="点击添加" android:onClick="addPage"/> <Space android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:text="点击删除" android:onClick="removePage"/> </LinearLayout> <android.support.design.widget.TabLayout android:id="@+id/tab_titles" android:layout_width="match_parent" android:layout_height="50dp" app:tabSelectedTextColor="#FFF" app:tabTextColor="#3f9" android:background="@color/design_default_color_primary" app:tabIndicatorHeight="10dp" app:tabTextAppearance="@style/TabTextAppearance"/> <android.support.v4.view.ViewPager android:id="@+id/viewpagers_mypager" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>
Tab的字体大小和样式需要使用属性
app:tabTextAppearance
设置
fragment的布局就不贴出来了 -
Activity
public class ActivityViewPagers extends FragmentActivity { private TabLayout mTab; private ViewPager mViewPager; private ViewPagerFragAdapter mPagerAdapter; String[] array = {"Damian", "Madison", "Henry", "Jamey", "Farrell", "Pandora"}; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_viewpagers); mTab = findViewById(R.id.tab_titles); mViewPager = findViewById(R.id.viewpagers_mypager); /**关键方法,使Tab与ViewPager绑定,tab个数同步*/ mTab.setupWithViewPager(mViewPager); mPagerAdapter = new ViewPagerFragAdapter(getSupportFragmentManager()); mViewPager.setAdapter(mPagerAdapter); } public void addPage(View view) { mPagerAdapter.addTitle(array[(int) (Math.random()*array.length)]); int count = mPagerAdapter.getCount(); if (count > 3){ mTab.setTabMode(TabLayout.MODE_SCROLLABLE); } } public void removePage(View view) { mPagerAdapter.removeTitle(); int count = mPagerAdapter.getCount(); if (count <= 3){ mTab.setTabMode(TabLayout.MODE_FIXED); } } }
Activity必须是FragmentActivity才能调用
getSupportFragmentManager()
-
Adapter
public class ViewPagerFragAdapter extends FragmentPagerAdapter { private ArrayList<String> mData = new ArrayList<>(); public ViewPagerFragAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { String title = mData.get(position); FragmentCommon fragment = FragmentCommon.newInstance(title); return fragment; } @Override public int getCount() { return mData.size(); } @Nullable @Override public CharSequence getPageTitle(int position) { //使用首字母作为title return String.valueOf(mData.get(position).charAt(0)); } public void setTitleList(ArrayList<String> strings) { this.mData.clear(); this.mData.addAll(strings); notifyDataSetChanged(); } public void addTitle(String str){ this.mData.add(str); notifyDataSetChanged(); } public void removeTitle() { if (mData.size() <= 0){ return; } this.mData.remove(mData.size() -1); notifyDataSetChanged(); } }
跟BaseAdapter的思路一样,先数据处理,然后
notifyDataSetChanged()
通知适配器更新
关键方法getPageTitle(int position)
, 与Tab有关,tab从这里获取标题的内容,不重写就是空标题了;
说明:
- TabLayout需要的gradle依赖:
implementation 'com.android.support:design:28.0.0'
源码分析
TabLayout 的 setupWithViewPager方法内部实现:
private void setupWithViewPager(@Nullable ViewPager viewPager, boolean autoRefresh, boolean implicitSetup) {
//去除老的监听器
if (this.viewPager != null) {
if (this.pageChangeListener != null) {
this.viewPager.removeOnPageChangeListener(this.pageChangeListener);
}
if (this.adapterChangeListener != null) {
this.viewPager.removeOnAdapterChangeListener(this.adapterChangeListener);
}
}
if (this.currentVpSelectedListener != null) {
this.removeOnTabSelectedListener(this.currentVpSelectedListener);
this.currentVpSelectedListener = null;
}
//更换新的监听器
if (viewPager != null) {
this.viewPager = viewPager;
if (this.pageChangeListener == null) {
this.pageChangeListener = new TabLayout.TabLayoutOnPageChangeListener(this);
}
this.pageChangeListener.reset();
//设置PageChangeListener,监听页面滑动、选中状态,来同步滑动Tab标题
viewPager.addOnPageChangeListener(this.pageChangeListener);
this.currentVpSelectedListener = new TabLayout.ViewPagerOnTabSelectedListener(viewPager);
this.addOnTabSelectedListener(this.currentVpSelectedListener);
PagerAdapter adapter = viewPager.getAdapter();
if (adapter != null) {
this.setPagerAdapter(adapter, autoRefresh);
}
if (this.adapterChangeListener == null) {
this.adapterChangeListener = new TabLayout.AdapterChangeListener();
}
this.adapterChangeListener.setAutoRefresh(autoRefresh);
//监听ViewPager的适配器变化
viewPager.addOnAdapterChangeListener(this.adapterChangeListener);
this.setScrollPosition(viewPager.getCurrentItem(), 0.0F, true);
} else {
this.viewPager = null;
this.setPagerAdapter((PagerAdapter)null, false);
}
this.setupViewPagerImplicitly = implicitSetup;
}
这里对Viewpager的多个参数做监听,这样的话ViewPager就实实在在的与Tab绑定而同步刷新和选中、滑动
TabLayout内部定义了多种监听器:监听Adapter变化、Pager状态、Tab状态等
总结:
- 关键方法:
mTab.setupWithViewPager(mViewPager);
这句代码让Tab与Viewpager绑定。如果Viewpager页数变化,相应的tab的个数和标题也会变化。TabLayout在addTab时就会调用getPageTitle(int position)
获取标题内容; - viewpager数据变化 —> viewpager adapter 更新 —>Tab更新
- 如果remove当前页面,有可能导致后续的页面内容错乱;可能是ViewPager缓存导致的。可能需要换用适配器
FragmentStatePagerAdapter