zoukankan      html  css  js  c++  java
  • TabLayout与ViewPager同步后Tab的标题不显示

    一、概述

    1.1 问题描述

    TabLayout+ViewPager后,TabLayout的TabItem不显示的问题:

    1.2 截图

    tablayout_no_text.png

    二、结论

    mTabs.setupWithViewPager(mViewPager); 语句的功能是:

    • 将 TabLayout、ViewPager 的监听事件同步
    • 对 TabLayout 的适配器进行重置
    • 对 TabLayout 的 TabItem 进行重置
    • 从 ViewPager 的 Adapter 中读取到每一页的标题,并为之创建 TabItem 添加到 TabLayout 中

    解决方案是:
    重写在 mViewPager 的 Adapter 中的如下方法,将每页的 Title 设置好:

    	mViewPager.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {
            @Override
            public Fragment getItem(int position) {
    			return mFragmentList.get(position);
    		}
    
    		@Override
    		public int getCount() {
    			return mFragmentList.size();
    		}
    
    		@Override
    		public CharSequence getPageTitle(int position) {
    			return mTitle[position];
    		}
    	});
    

    tablayout_no_text_solved.png

    三、问题探究

    3.1 设置的代码

    mFragmentList.add(longFragment);
    mFragmentList.add(shortFragment);
    mViewPager.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {
    	@Override
    	public Fragment getItem(int position) {
    		return mFragmentList.get(position);
    	}
    
    	@Override
    	public int getCount() {
    		return mFragmentList.size();
    	}
    });
    mTabs.setupWithViewPager(mViewPager);
    

    上面是非常常见的一段代码,主要逻辑是,将承载两个Fragment的ViewPager与TabLayout同步起来。
    其中,核心语句是:

    	mTabs.setupWithViewPager(mViewPager);
    

    3.2 查看 TabLayout 的相关源码

    进入源码查看到:

    	public void setupWithViewPager(@Nullable final ViewPager viewPager) {
            if (mViewPager != null && mPageChangeListener != null) {
                // If we've already been setup with a ViewPager, remove us from it
                mViewPager.removeOnPageChangeListener(mPageChangeListener);
            }
    
            if (viewPager != null) {
                final PagerAdapter adapter = viewPager.getAdapter();
                if (adapter == null) {
                    throw new IllegalArgumentException("ViewPager does not have a PagerAdapter set");
                }
    
                mViewPager = viewPager;
    
                // Add our custom OnPageChangeListener to the ViewPager
                if (mPageChangeListener == null) {
                    mPageChangeListener = new TabLayoutOnPageChangeListener(this);
                }
                mPageChangeListener.reset();
                viewPager.addOnPageChangeListener(mPageChangeListener);
    
                // Now we'll add a tab selected listener to set ViewPager's current item
                setOnTabSelectedListener(new ViewPagerOnTabSelectedListener(viewPager));
    
                // Now we'll populate ourselves from the pager adapter
                setPagerAdapter(adapter, true);
            } else {
                // We've been given a null ViewPager so we need to clear out the internal state,
                // listeners and observers
                mViewPager = null;
                setOnTabSelectedListener(null);
                setPagerAdapter(null, true);
            }
        }
    

    也比较明了,无非是先做一系列的判断,然后修改 TabLayout与ViewPager的各种监听事件。

    进入 setPagerAdapter 查看到如下方法:

    	private void setPagerAdapter(@Nullable final PagerAdapter adapter, final boolean addObserver) {
            if (mPagerAdapter != null && mPagerAdapterObserver != null) {
                // If we already have a PagerAdapter, unregister our observer
                mPagerAdapter.unregisterDataSetObserver(mPagerAdapterObserver);
            }
    
            mPagerAdapter = adapter;
    
            if (addObserver && adapter != null) {
                // Register our observer on the new adapter
                if (mPagerAdapterObserver == null) {
                    mPagerAdapterObserver = new PagerAdapterObserver();
                }
                adapter.registerDataSetObserver(mPagerAdapterObserver);
            }
    
            // Finally make sure we reflect the new adapter
            populateFromPagerAdapter();
        }
    

    该方法的主要功能是设置TabLayout的适配器,populateFromPagerAdapter();方法引人注目。

    	private void populateFromPagerAdapter() {
            removeAllTabs();
    
            if (mPagerAdapter != null) {
                final int adapterCount = mPagerAdapter.getCount();
                for (int i = 0; i < adapterCount; i++) {
    				// 从 PagerAdapter 中获取到标题,并新建 Tab 加入到空的 TabLayout 中
                    addTab(newTab().setText(mPagerAdapter.getPageTitle(i)), false);
                }
    
                // Make sure we reflect the currently set ViewPager item
                if (mViewPager != null && adapterCount > 0) {
                    final int curItem = mViewPager.getCurrentItem();
                    if (curItem != getSelectedTabPosition() && curItem < getTabCount()) {
                        selectTab(getTabAt(curItem));
                    }
                }
            } else {
                removeAllTabs();
            }
        }
    

    该方法中removeAllTabs();将所有的Tabs移除了,找到问题的关键!
    同时,addTab(newTab().setText(mPagerAdapter.getPageTitle(i)), false);给了我们答案。

    3.4 跳转到 PagerAdapter 的源码

    再仔细看看 getPageTitle 这个方法:

    	public CharSequence getPageTitle(int position) {
            return null;
        }
    

    所以,知道为什么为空了吧!

    3.4 结论

    综上,mTabs.setupWithViewPager(mViewPager);语句的功能是:

    • 将 TabLayout、ViewPager 的监听事件同步
    • 对 TabLayout 的适配器进行重置
    • 对 TabLayout 的 TabItem 进行重置
    • 从 ViewPager 的 Adapter 中读取到每一页的标题,并为之创建 TabItem 添加到 TabLayout 中

    3.5 解决方案

    重写 getPageTitle 方法:

    	mViewPager.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {
            @Override
            public Fragment getItem(int position) {
    			return mFragmentList.get(position);
    		}
    
    		@Override
    		public int getCount() {
    			return mFragmentList.size();
    		}
    
    		@Override
    		public CharSequence getPageTitle(int position) {
    			return mTitle[position];
    		}
    	});
    

    此文在我的 Github Pages 上同步发布,地址为:TabLayout与ViewPager同步后Tab的标题不显示

  • 相关阅读:
    CodeForces 522B 手速题
    mybatis多数据源报错
    as依赖解决报错
    As 400错
    maven直接饮用jar包的写法
    测试一下多线程同时往list中添加元素会不会出问题
    jmeter中判断数据库是否存在相应的记录
    jmeter打开图形化界面时指定代理
    wz
    初阳胜阴
  • 原文地址:https://www.cnblogs.com/neillee/p/7001976.html
Copyright © 2011-2022 走看看