仅带有图标的Tablayout

70

我正在使用设计支持来创建选项卡,同时也在使用ViewPager用于实现可滑动的选项卡。

现在,我不知道如何在选项卡中仅使用图标而不是文本。我尝试了解但没有成功。

我的代码:

Toolbar toolbar;
private TabLayout tabLayout;
private ViewPager viewPager;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    viewPager = (ViewPager) findViewById(R.id.pager);
    setupViewPager(viewPager);
    setupTablayout();
}

private void setupTablayout() {
    tabLayout = (TabLayout) findViewById(R.id.tabLayout);
    tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
    tabLayout.setupWithViewPager(viewPager);
}

class MyPagerAdapter extends FragmentPagerAdapter {

    private final List<Fragment> mFragmentList = new ArrayList<>();
    private final List<String> mFragmentTitleList = new ArrayList<>();

    public MyPagerAdapter(FragmentManager manager) {
        super(manager);
    }

    @Override
    public Fragment getItem(int position) {
        return mFragmentList.get(position);
    }

    @Override
    public int getCount() {
        return mFragmentList.size();
    }

    public void addFrag(Fragment fragment, String title) {
        mFragmentList.add(fragment);
        mFragmentTitleList.add(title);
    }

    @Override
    public CharSequence getPageTitle(int position) {
        mFragmentTitleList.get(position)
    }
}

private void setupViewPager(ViewPager viewPager) {
    MyPagerAdapter adapter = new MyPagerAdapter(getSupportFragmentManager());
    adapter.addFrag(new frag(), "CAT");
    adapter.addFrag(new frag(), "DOG");
    adapter.addFrag(new frag(), "BIRD");
    viewPager.setAdapter(adapter);
}

尝试使用可扩展文本。在这里尝试我的答案(https://dev59.com/IYnda4cB1Zd3GeqPAISS#29535378)。如果有帮助,请投赞成票。 - Harin
13个回答

165

一种方法是在 TabLayout.setupWithViewPager() 方法之后设置图标。

mTabLayout.setupWithViewPager(mViewPager);
for (int i = 0; i < mTabLayout.getTabCount(); i++) {
  mTabLayout.getTabAt(i).setIcon(R.drawable.your_icon);
}

2
谢谢 - 真是太棒了。 - Simon
3
在我的情况下,这个解决方案同时显示图标和文本,这实际上正是我需要的 :-) - Felix
如果您在分页适配器中覆盖了getPageTitle方法,那么将显示文本和图标;否则只会显示图标。 - bkach
1
这个解决方案在 27.1.0 版本中不起作用,但如果我覆盖 getPageTitle 方法,则只会显示标题。 - Zulqurnain Jutt
如果在执行adapter.notifyDataSetChanged()之前进行操作,它就会生效。 - Kibotu

27

以下链接的教程应该涵盖了您想要的内容。https://github.com/codepath/android_guides/wiki/Google-Play-Style-Tabs-using-TabLayout#add-icons-to-tablayout

我在下面复制了相关部分。

将图标添加到TabLayout

目前,TabLayout类没有提供一个干净的抽象模型,允许您在选项卡中使用图标。有很多发布的解决方法,其中之一是从您的PagerAdapter的getPageTitle(position)方法返回一个SpannableString,其中包含您的图标在ImageSpan中,如下面的代码片段所示:

private int[] imageResId = {
        R.drawable.ic_one,
        R.drawable.ic_two,
        R.drawable.ic_three
};

// ...

@Override
public CharSequence getPageTitle(int position) {
    // Generate title based on item position
    // return tabTitles[position];
    Drawable image = context.getResources().getDrawable(imageResId[position]);
    image.setBounds(0, 0, image.getIntrinsicWidth(), image.getIntrinsicHeight());
    SpannableString sb = new SpannableString(" ");
    ImageSpan imageSpan = new ImageSpan(image, ImageSpan.ALIGN_BOTTOM);
    sb.setSpan(imageSpan, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    return sb;
}

默认情况下,TabLayout创建的选项卡将textAllCaps属性设置为true,这会防止ImageSpans被呈现。您可以通过更改tabTextAppearance属性来覆盖此行为。

  <style name="MyCustomTabLayout" parent="Widget.Design.TabLayout">
        <item name="tabTextAppearance">@style/MyCustomTextAppearance</item>
  </style>

  <style name="MyCustomTextAppearance" parent="TextAppearance.Design.Tab">
        <item name="textAllCaps">false</item>
  </style>

5
选项卡不会显示任何图标,即使设置了 textAllCaps = false 也没有任何效果。 - pnavk
1
当我尝试构建我的代码时,出现了这个错误:在'android'包中找不到属性'tabTextAppearance'的资源标识符。 - Akah
1
我注意到这种技术的一个问题是,当图标可见时,文本大小会发生变化。 - ZaBlanc
1
谢谢大家,属性"textAllCaps"解决了我在图标方面的问题。 - tryp

25

在新版本的TabLayout中,谷歌添加了TabItem,您可以通过以下代码轻松地在XML中添加图标:

<android.support.design.widget.TabLayout
         app:tabTextColor="@color/gray"
         app:tabMode="fixed"
         app:tabBackground="@color/red"
         app:tabIndicatorHeight="4dp"
         app:tabIndicatorColor="@color/purple"
         app:tabPadding="2dp"
         app:tabSelectedTextColor="@color/white"
         app:tabMinWidth="64dp"
         android:layout_height="wrap_content"
         android:layout_width="match_parent">

     <!--add height and width to TabItem -->
     <android.support.design.widget.TabItem 
             android:text="@string/tab_text"/>

     <android.support.design.widget.TabItem
             android:icon="@drawable/ic_android"/>

 </android.support.design.widget.TabLayout>

在此处查看更多信息


1
这是添加图标的实际方法 :) - Anand Savjani
6
如果与视图页(view pager)一起使用,视图页会调用 removeAllTabs() 方法,以删除通过布局文件添加的任何选项卡元素。 - JDL
1
当使用 PagerAdapter 时,选项卡会被重置,只显示从适配器中获取的标题。因此无法正常工作。 - ballzak

21

试一试

    public class GlobalActivity extends AppCompatActivity {
    Toolbar toolbar;
    ViewPager viewPager;
    TabLayout tabLayout;
    ViewPagerAdapter adapter;
    private int[] tabIcons = {
            R.drawable.home_ic,
            R.drawable.biz_ic,
            R.drawable.network_ic,
            R.drawable.offers_ic,
            R.drawable.message_ic_b
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_global_hub);
        tab();
    }
    public void tab(){
        viewPager = (ViewPager) findViewById(R.id.viewpager);
        setupViewPager(viewPager);
        tabLayout = (TabLayout) findViewById(R.id.tablayout);
        tabLayout.setupWithViewPager(viewPager);
        setupTabIcons();

    }
    private void setupTabIcons() {
        tabLayout.getTabAt(0).setIcon(tabIcons[0]);
        tabLayout.getTabAt(1).setIcon(tabIcons[1]);
        tabLayout.getTabAt(2).setIcon(tabIcons[2]);
        tabLayout.getTabAt(3).setIcon(tabIcons[3]);
        tabLayout.getTabAt(4).setIcon(tabIcons[4]);

    }
    public void setupViewPager(ViewPager viewPager){
        adapter = new ViewPagerAdapter(getSupportFragmentManager());
        adapter.addFrag(new GlHubFragment(),"HOME");
        adapter.addFrag(new BizForumFragment(), "BIZ FORUM");
        adapter.addFrag(new NetworkFragment(), "NETWORK");
        adapter.addFrag(new MessagesFragment(), "MESSAGEs");
        adapter.addFrag(new OfferFragmentActivity(), "OFFER");
        viewPager.setAdapter(adapter);
    }

    public class ViewPagerAdapter extends FragmentPagerAdapter{
        private final List<Fragment> mfragmentlist =new ArrayList<>();
        private final List<String> mFragmentTitleList = new ArrayList<>();
        public ViewPagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {
            return mfragmentlist.get(position);
        }

        @Override
        public int getCount() {
            return mfragmentlist.size();
        }
        public void addFrag(Fragment fragment,String title){
            mfragmentlist.add(fragment);
            mFragmentTitleList.add(title);
        }
        @Override
        public CharSequence getPageTitle(int position){
            return mFragmentTitleList.get(position);
        }
    }
}

7
TabLayout 中,设置图标很容易:getPageTitle(position) 应该返回 null(如果你不想显示标题)。
接下来:
tabLayout.getTabAt(0).setIcon(resId);

tabLayout.getTabAt(1).setIcon(resId);

......

1
我尝试过这个,图标显示在文本的上方。如何使图标显示在文本的左侧? - HelloSilence
在我的情况下,如果我将getPageTitle()保持不变,那么...图标将显示在标题旁边...也许在你的情况下标题文本太大了。 - Bhuwan

5

当使用TabLayout作为ViewPager的“装饰”场景时,这些方法都不够优雅。 这里提供了TabLayout和PagerAdapter的简单扩展,可以轻松替换TabLayout,并且无需手动添加TabLayout类外的图标并遵循PagerAdapter的用法来获取选项卡信息。 TabLayout文档

/**
 * Created by JDL on 1/18/2017.
 */
public class TabLayoutExt extends TabLayout {

    protected ViewPager mViewPager;

    public abstract static class TabLayoutViewPagerAdapter extends PagerAdapter {
        public TabLayoutViewPagerAdapter() {
        }

        /**
         * This method may be called by the TabLayout to obtain an icon drawable
         * to for the specified tab. This method may return null
         * indicating no tab icon for this page. The default implementation returns
         * null.
         *
         * @param position The position of the title requested
         * @return A drawable icon for the requested page
         */
        public Drawable getPageIcon(Context context, int position) {
            return null;
        }
    }

    public TabLayoutExt(Context context) {
        super(context);
    }

    public TabLayoutExt(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public TabLayoutExt(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onAttachedToWindow() {
        //Cover the implicit setup in TabLayout
        if (mViewPager == null) {
            final ViewParent vp = getParent();
            if (vp instanceof ViewPager) {
                mViewPager = (ViewPager)vp;
            }

        }
        super.onAttachedToWindow();
    }

    public void addTab(@NonNull Tab tab, int position, boolean setSelected) {
        if (mViewPager != null && mViewPager.getAdapter() instanceof TabLayoutViewPagerAdapter) {
            Drawable icon = ((TabLayoutViewPagerAdapter) mViewPager.getAdapter()).getPageIcon(getContext(),position);
            tab.setIcon(icon);
        }
        super.addTab(tab,position,setSelected);

    }

    @Override
    public void setupWithViewPager(@Nullable ViewPager viewPager, boolean autoRefresh) {
        mViewPager = viewPager;
        super.setupWithViewPager(viewPager, autoRefresh);
    }
}

所需做的一切就是扩展TabLayoutViewPagerAdapter而不是PageAdapter,并实现getPageIcon(Context,int)以替换或补充标题。在您的XML文件中使用TabLayoutExt而不是正常的TabLayout。这可以通过自定义视图或其他方式进一步修改选项卡来进行扩展。

5

4

我发现使用Tablayout.Tab.setIcon(drawable)是使用图标最简单的方法,这也使得突出选定的图标变得容易。如果您想要做到这一点,请按照以下步骤进行操作。

第1步。 将图像添加到res.mipmap文件夹中(mipmap-mdpi、hdpi等)。根据其他答案,将它们放在res.drawable文件夹中也是可以的。

第2步。 在设置TabLayout和ViewPager之后,对所有选项卡调用setIcon。我在AdapterTabs中做到了这一点,以保持Activity的整洁。 因此,在您的活动中执行以下操作:

    tablayout = (TabLayout) findViewById(R.id.tab_layout);
    viewPager = (ViewPager) findViewById(R.id.viewPager);
    adapterTabs = new AdapterTabs(this, getSupportFragmentManager(), fragments, tablayout, viewPager);

    viewPager.setAdapter(adapterTabs);
    tablayout.setupWithViewPager(viewPager);
    adapterTabs.setTabIcons();

在您的AdapterTabs中,它应该扩展FragmentPagerAdapter,并放置setTabIcons()方法。
    public void setTabTitlesToIcons() {
    Drawable icon1 = context.getResources().getDrawable(R.mipmap.ic_1);
    Drawable icon2 = context.getResources().getDrawable(R.mipmap.ic_2);
    Drawable icon3 = context.getResources().getDrawable(R.mipmap.ic_3);
    Drawable icon1Hilighted = context.getResources().getDrawable(R.mipmap.ic_1_selected);
    Drawable icon2Hilighted = context.getResources().getDrawable(R.mipmap.ic_2_selected);
    Drawable icon3Hilighted = context.getResources().getDrawable(R.mipmap.ic_3_selected);

    icons.add(icon1);
    icons.add(icon2);
    icons.add(icon3);
    iconsHilighted.add(icon1Hilighted);
    iconsHilighted.add(icon2Hilighted);
    iconsHilighted.add(icon3Hilighted);

    for(int i = 0; i < icons.size(); i++) {
        if(i == 0) {
            //noinspection ConstantConditions
            tabLayout.getTabAt(i).setIcon(iconsSelected.get(i));
        }
        else {
            //noinspection ConstantConditions
            tabLayout.getTabAt(i).setIcon(icons.get(i));
        }
    }
}

请确保存储对列表 'icons' 和 'iconsHilighted' 的引用。您后面会用到它们。同时,也请存储对从活动中传入的TabLayout和ViewPager的引用。

步骤3。 请确保AdapterTabs.getPageTitle()返回null。 此时,如果运行它,您应该看到第一个图标已被突出显示。

步骤4。 在AdapterTabs中实现ViewPager.OnPageChangeListener,并将该侦听器添加到您的viewPager中。

    public AdapterTabs(Context context, FragmentManager fragmentManager, List<Fragment> fragments, TabLayout tabLayout, ViewPager viewPager) {
    super(fragmentManager);
    this.context = context;
    this.tabLayout = tabLayout;
    this.viewPager = viewPager;
    this.viewPager.addOnPageChangeListener(this);

    tabs.add(fragments.get(0));
    tabs.add(fragments.get(1));
    tabs.add(fragments.get(2));
}

步骤五。在 AdapterTabs 的 onPageSelected 回调中更新选项卡中的图标。

    @Override
public void onPageSelected(int position) {
    for (int i = 0; i < tabs.size(); i++) {
        if(i == position) {
            //noinspection ConstantConditions
            tabLayout.getTabAt(i).setIcon(iconsSelected.get(i));
        }
        else {
            //noinspection ConstantConditions
            tabLayout.getTabAt(i).setIcon(icons.get(i));
        }
    }
}

现在,当您切换标签时,应该会看到突出显示的图标正在更新。

1
你可以使用名为"selectors"的特殊drawable来配置不同状态。 - Roel
是的,这是正确的,但为什么一旦您选择一个不在缓存中的新选项卡,图标会被移除?它们没有保留,因此您必须在 .onPageSelected 中重新插入它们。真正愚蠢的解决方案。这是个 Bug 吗? - carl
我认为你需要在软技能方面努力,@carl。因此,我不会再发表任何评论了。 - ninjachippie

2

试试这个,肯定有效。

private TabLayout tabLayout;
private ViewPager viewPager;
private int[] tabIcons = {
        R.drawable.single,
        R.drawable.multiple};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_contact_picker);

    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    toolbar.setTitle("Choose contact");
    setSupportActionBar(toolbar);
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    tab();
}


public void tab(){
    viewPager = (ViewPager) findViewById(R.id.viewpager);
    setupViewPager(viewPager);
    tabLayout = (TabLayout) findViewById(R.id.tabs);
    tabLayout.setupWithViewPager(viewPager);
    setupTabIcons();
}

private void setupTabIcons() {
    tabLayout.getTabAt(0).setIcon(tabIcons[0]);
    tabLayout.getTabAt(1).setIcon(tabIcons[1]);

}

private void setupViewPager(ViewPager viewPager) {
    ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
    adapter.addFragment(new Login());
    adapter.addFragment(new Register());
    viewPager.setAdapter(adapter);
}

class ViewPagerAdapter extends FragmentPagerAdapter {
    private final List<Fragment> mFragmentList = new ArrayList<>();

    public ViewPagerAdapter(FragmentManager manager) {
        super(manager);
    }

    @Override
    public Fragment getItem(int position) {
        return mFragmentList.get(position);
    }

    @Override
    public int getCount() {
        return mFragmentList.size();
    }

    public void addFragment(Fragment fragment) {
        mFragmentList.add(fragment);

    }


}

1

如评论中所述,在使用PagerAdapter时,在TabLayout中定义图标是无效的。对于使用Kotlin的用户,一种解决方法是创建一个像这样的扩展函数:

fun TabLayout.setupWithViewPagerAndKeepIcons(viewPager : ViewPager?) {
    val icons =  mutableListOf<Drawable?>()
    repeat(tabCount) {
        icons.add(getTabAt(it)?.icon)
    }
    setupWithViewPager(viewPager)

    repeat(tabCount) {
        getTabAt(it)?.setIcon(icons.get(it))
    }
}

然后在layout.xml中将您的图标添加到TabLayout:

    <com.google.android.material.tabs.TabLayout
            android:id="@+id/tab_layout">

        <com.google.android.material.tabs.TabItem
                android:icon="@drawable/your_icon"/>

    </com.google.android.material.tabs.TabLayout>

最后,使用扩展函数将TabLayout与ViewPager设置。
tab_layout.setupWithViewPagerAndKeepIcons(view_pager)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接