TabLayout+Viewpager加载动态多个fragment

  • 废话不多说,直接上图
代码展示
  1. 布局

    <?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的布局就不贴出来了

  2. 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()

  3. 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状态等
在这里插入图片描述

总结:
  1. 关键方法:mTab.setupWithViewPager(mViewPager);这句代码让Tab与Viewpager绑定。如果Viewpager页数变化,相应的tab的个数和标题也会变化。TabLayout在addTab时就会调用getPageTitle(int position)获取标题内容;
  2. viewpager数据变化 —> viewpager adapter 更新 —>Tab更新
  3. 如果remove当前页面,有可能导致后续的页面内容错乱;可能是ViewPager缓存导致的。可能需要换用适配器FragmentStatePagerAdapter
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值