前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >TabLayout-Android M新控件

TabLayout-Android M新控件

作者头像
小小工匠
发布2021-08-16 10:20:09
4360
发布2021-08-16 10:20:09
举报
文章被收录于专栏:小工匠聊架构

概述

官方API

Tabs are now best implemented by leveraging the ViewPager with a custom “tab indicator” on top. In this guide, we will be using Google’s new TabLayout included in the support design library release for Android “M”.

Prior to Android “M”, the easiest way to setup tabs with Fragments was to use ActionBar Tabs as described in ActionBar Tabs with Fragments guide. However, all methods related to navigation modes in the ActionBar class (such as setNavigationMode(), addTab(), selectTab(), etc.) are now deprecated.


Design Support Library

To implement Google Play style sliding tabs, make sure to follow the Design Support Library setup instructions first.


Sliding Tabs Layout

Simply add android.support.design.widget.TabLayout, which will be used for rendering(呈现) the different tab options. The android.support.v4.view.ViewPager component will be used to page between the various fragments we will create.

代码语言:javascript
复制
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.design.widget.TabLayout
        android:id="@+id/sliding_tabs"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:tabMode="scrollable" />

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="0px"
        android:layout_weight="1"
        android:background="@android:color/white" />

LinearLayout>

create-fragment

Now that we have the ViewPager and our tabs in our layout, we should start defining the content of each of the tabs. Since each tab is just a fragment being displayed, we need to create and define the Fragment to be shown. You may have one or more fragments in your application depending on your requirements.

In res/layout/fragment_page.xml define the XML layout for the fragment which will be displayed on screen when a particular tab is selected:

代码语言:javascript
复制
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center" />

In PageFragment.java define the inflation logic for the fragment of tab content:

代码语言:javascript
复制
// In this case, the fragment displays simple text based on the page
public class PageFragment extends Fragment {
    public static final String ARG_PAGE = "ARG_PAGE";

    private int mPage;

    public static PageFragment newInstance(int page) {
        Bundle args = new Bundle();
        args.putInt(ARG_PAGE, page);
        PageFragment fragment = new PageFragment();
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mPage = getArguments().getInt(ARG_PAGE);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_page, container, false);
        TextView textView = (TextView) view;
        textView.setText("Fragment #" + mPage);
        return view;
    }
}

Implement FragmentPagerAdapter

The next thing to do is to implement the adapter for your ViewPager which controls the order of the tabs, the titles and their associated content. The most important methods to implement here are getPageTitle(int position) which is used to get the title for each tab and getItem(int position) which determines the fragment for each tab.

代码语言:javascript
复制
public class SampleFragmentPagerAdapter extends FragmentPagerAdapter {
    final int PAGE_COUNT = 3;
    private String tabTitles[] = new String[] { "Tab1", "Tab2", "Tab3" };
    private Context context;

    public SampleFragmentPagerAdapter(FragmentManager fm, Context context) {
        super(fm);
        this.context = context;
    }

    @Override
    public int getCount() {
        return PAGE_COUNT;
    }

    @Override
    public Fragment getItem(int position) {
        return PageFragment.newInstance(position + 1);
    }

    @Override
    public CharSequence getPageTitle(int position) {
        // Generate title based on item position
        return tabTitles[position];
    }
}

Setup Sliding Tabs

Finally, we need to attach our ViewPager to the SampleFragmentPagerAdapter and then configure the sliding tabs with a two step process:

  • In the onCreate() method of your activity, find the ViewPager and connect the adapter.
  • Set the ViewPager on the TabLayout to connect the pager with the tabs.
代码语言:javascript
复制
public class MainActivity extends AppCompatActivity {

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

        // Get the ViewPager and set it's PagerAdapter so that it can display items
        ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
        viewPager.setAdapter(new SampleFragmentPagerAdapter(getSupportFragmentManager(), 
            MainActivity.this));

        // Give the TabLayout the ViewPager
        TabLayout tabLayout = (TabLayout) findViewById(R.id.sliding_tabs);
        tabLayout.setupWithViewPager(viewPager);
    }

}

Heres the output:

这里写图片描述
这里写图片描述

Styling the TabLayout

Normally, the tab indicator color chosen is the accent color defined for your Material Design theme. We can override this color by defining a custom style in styles.xml and then applying the style to your TabLayout:

代码语言:javascript
复制
<style name="MyCustomTabLayout" parent="Widget.Design.TabLayout">
    <item name="tabIndicatorColor">#0000FFitem>
style>

You can then override this style for your TabLayout:

代码语言:javascript
复制
.support.design.widget.TabLayout
        android:id="@+id/tabs"
        style="@style/MyCustomTabLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
.support.design.widget.TabLayout>

There are several other styles that can be configured for the TabLayout:

代码语言:javascript
复制
name</span>=<span class="hljs-string">"MyCustomTabLayout"</span> parent=<span class="hljs-string">"Widget.Design.TabLayout"</span>>
    <<span class="hljs-property">item</span> <span class="hljs-property">name</span>=<span class="hljs-string">"tabMaxWidth"</span>>@dimen/tab_max_width</<span class="hljs-property">item</span>>
    <<span class="hljs-property">item</span> <span class="hljs-property">name</span>=<span class="hljs-string">"tabIndicatorColor"</span>>?attr/colorAccent</<span class="hljs-property">item</span>>
    <<span class="hljs-property">item</span> <span class="hljs-property">name</span>=<span class="hljs-string">"tabIndicatorHeight"</span>><span class="hljs-number">2</span>dp</<span class="hljs-property">item</span>>
    <<span class="hljs-property">item</span> <span class="hljs-property">name</span>=<span class="hljs-string">"tabPaddingStart"</span>><span class="hljs-number">12</span>dp</<span class="hljs-property">item</span>>
    <<span class="hljs-property">item</span> <span class="hljs-property">name</span>=<span class="hljs-string">"tabPaddingEnd"</span>><span class="hljs-number">12</span>dp</<span class="hljs-property">item</span>>
    <<span class="hljs-property">item</span> <span class="hljs-property">name</span>=<span class="hljs-string">"tabBackground"</span>>?attr/selectableItemBackground</<span class="hljs-property">item</span>>
    <<span class="hljs-property">item</span> <span class="hljs-property">name</span>=<span class="hljs-string">"tabTextAppearance"</span>>@style/MyCustomTabTextAppearance</<span class="hljs-property">item</span>>
    <<span class="hljs-property">item</span> <span class="hljs-property">name</span>=<span class="hljs-string">"tabSelectedTextColor"</span>>?android:textColorPrimary</<span class="hljs-property">item</span>>

name</span>=<span class="hljs-string">"MyCustomTabTextAppearance"</span> parent=<span class="hljs-string">"TextAppearance.Design.Tab"</span>>
    <<span class="hljs-property">item</span> <span class="hljs-property">name</span>=<span class="hljs-string">"android:textSize"</span>><span class="hljs-number">14</span>sp</<span class="hljs-property">item</span>>
    <<span class="hljs-property">item</span> <span class="hljs-property">name</span>=<span class="hljs-string">"android:textColor"</span>>?android:textColorSecondary</<span class="hljs-property">item</span>>
    <<span class="hljs-property">item</span> <span class="hljs-property">name</span>=<span class="hljs-string">"textAllCaps"</span>><span class="hljs-constant">true</span></<span class="hljs-property">item</span>>

Add Icons to TabLayout

Currently, the TabLayout class does not provide a clean abstraction model that allows for icons in your tab. There are many posted workarounds, one of which is to return a SpannableString, containing your icon in an ImageSpan, from your PagerAdapter’s getPageTitle(position) method as shown in the code snippet below:

Code

代码语言:javascript
复制
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];

    // getDrawable(int i) is deprecated, use getDrawable(int i, Theme theme) for min SDK >=21
    // or ContextCompat.getDrawable(Context context, int id) if you want support for older versions.
    // Drawable image = context.getResources().getDrawable(iconIds[position], context.getTheme());
    // Drawable image = context.getResources().getDrawable(imageResId[position]);

    Drawable image = ContextCompat.getDrawable(context, 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;
}

By default, the tab created by TabLayout sets the textAllCaps property to be true, which prevents ImageSpans from being rendered. You can override this behavior by changing the tabTextAppearance property.

代码语言:javascript
复制
name</span>=<span class="hljs-string">"MyCustomTabLayout"</span> parent=<span class="hljs-string">"Widget.Design.TabLayout"</span>>
      <<span class="hljs-property">item</span> <span class="hljs-property">name</span>=<span class="hljs-string">"tabTextAppearance"</span>>@style/MyCustomTextAppearance</<span class="hljs-property">item</span>>


name</span>=<span class="hljs-string">"MyCustomTextAppearance"</span> parent=<span class="hljs-string">"TextAppearance.Design.Tab"</span>>
      <<span class="hljs-property">item</span> <span class="hljs-property">name</span>=<span class="hljs-string">"textAllCaps"</span>><span class="hljs-constant">false</span></<span class="hljs-property">item</span>>

Sliding tabs with images:

这里写图片描述
这里写图片描述

Add Icons+Text to TabLayout

Since we are using SpannableString to add icons to TabLayout, it becomes easy to have text next to the icons by manipulating the SpannableString object.

Code

代码语言:javascript
复制
@Override
public CharSequence getPageTitle(int position) {
    // Generate title based on item position
    Drawable image = context.getResources().getDrawable(imageResId[position]);
    image.setBounds(0, 0, image.getIntrinsicWidth(), image.getIntrinsicHeight());
    // Replace blank spaces with image icon
    SpannableString sb = new SpannableString("   " + tabTitles[position]);
    ImageSpan imageSpan = new ImageSpan(image, ImageSpan.ALIGN_BOTTOM);
    sb.setSpan(imageSpan, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    return sb;
}

Note the additional spaces that are added before the tab title while instantiating SpannableString class. The blank spaces are used to place the image icon so that the actual title is displayed completely. Depending on where you want to position your icon, you can specify the range start…end of the span in setSpan() method.

Sliding tabs with text and images:

这里写图片描述
这里写图片描述

add-custom-view-to-tablayout

In certain cases, instead of the default tab view we may want to apply a custom XML layout for each tab. To achieve this, iterate over all the TabLayout.TabS after attaching the sliding tabs to the pager:

Code

代码语言:javascript
复制
public class MainActivity extends AppCompatActivity {

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

        // Get the ViewPager and set it's PagerAdapter so that it can display items
        ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
        SampleFragmentPagerAdapter pagerAdapter = 
            new SampleFragmentPagerAdapter(getSupportFragmentManager(), MainActivity.this);
        viewPager.setAdapter(pagerAdapter);

        // Give the TabLayout the ViewPager
        TabLayout tabLayout = (TabLayout) findViewById(R.id.sliding_tabs);
        tabLayout.setupWithViewPager(viewPager);

        // Iterate over all tabs and set the custom view
        for (int i = 0; i < tabLayout.getTabCount(); i++) {
            TabLayout.Tab tab = tabLayout.getTabAt(i);
            tab.setCustomView(pagerAdapter.getTabView(i));
        }
    }

    //...
}

Next, we add the getTabView(position) method to the SampleFragmentPagerAdapter class:

代码语言:javascript
复制
public class SampleFragmentPagerAdapter extends FragmentPagerAdapter {
   private String tabTitles[] = new String[] { "Tab1", "Tab2" };
   private int[] imageResId = { R.drawable.ic_one, R.drawable.ic_two };

    public View getTabView(int position) {
        // Given you have a custom layout in `res/layout/custom_tab.xml` with a TextView and ImageView
        View v = LayoutInflater.from(context).inflate(R.layout.custom_tab, null);
        TextView tv = (TextView) v.findViewById(R.id.textView);
        tv.setText(tabTitles[position]);
        ImageView img = (ImageView) v.findViewById(R.id.imgView);
        img.setImageResource(imageResId[position]);
        return v;
    }

}

or

代码语言:javascript
复制
    /**
     * 自定义tab
     * 如果需要每个TAB都需要指定成单独的布局,switch即可,如果是相同的,写一个即可
     * 这里自定义的不是Fragment的布局,不要搞混了,仅仅是TAB的样式
     * @param
     * @return
     */
    public View getTabView(int position) {
        View view  = null;
        Log.d("getTabView", String.valueOf(position));
        switch (position) {
            case 0:
                // Given you have a custom layout in `res/layout/custom_tab.xml` with a TextView and ImageView
                view = LayoutInflater.from(context).inflate(R.layout.custom_tab, null);
//                TextView tv = (TextView) view.findViewById(R.id.textView);
//                tv.setText(tabTitles[position]);
//                ImageView img = (ImageView) view.findViewById(R.id.imageView);
//                img.setImageResource(imageResId[position]);
                break;
            case 1:
                // Given you have a custom layout in `res/layout/custom_tab1.xml` with a TextView and ImageView
                view = LayoutInflater.from(context).inflate(R.layout.custom_tab1, null);
//                TextView tv2 = (TextView) view.findViewById(R.id.textView);
//                tv2.setText(tabTitles[position]);
//                ImageView img2 = (ImageView) view.findViewById(R.id.imageView);
//                img2.setImageResource(imageResId[position]);
                break;
            case 2:
                // Given you have a custom layout in `res/layout/custom_tab2.xml` with a TextView and ImageView
                view = LayoutInflater.from(context).inflate(R.layout.custom_tab2, null);
//                TextView tv3 = (TextView) view.findViewById(R.id.textView);
//                tv3.setText(tabTitles[position]);
//                ImageView img3 = (ImageView) view.findViewById(R.id.imageView);
//                img3.setImageResource(imageResId[position]);
                break;
            default:
                break;
        }


        return view;
    }

With this you can setup any custom tab content for each page in the adapter.

Sliding tabs with custom view

这里写图片描述
这里写图片描述

Getting or Selected the Current Page

当屏幕旋转或者配置改变的时候,我们需要保存当前的状态。

With the recent updates to the design support library, you can also get the selected tab position by calling getSelectedTabPosition(). If you need to save or restore the selected tab position during screen rotation or other configuration changes, this method is helpful for restoring the original tab position.

First, move your tabLayout and viewPager as member variables of your main activity:

代码语言:javascript
复制
public class MainActivity extends AppCompatActivity {
    TabLayout tabLayout;
    ViewPager viewPager;

Next, we can save and restore the last known tab position by implementing methods on onSaveInstanceState() and onRestoreInstanceState() to persist this data. When the view is recreated, we can use this data and set the current tab to the last selected tab value.

代码语言:javascript
复制
 public static String POSITION = "POSITION";

  @Override
  public void onSaveInstanceState(Bundle outState) {
      super.onSaveInstanceState(outState);
      outState.putInt(POSITION, tabLayout.getSelectedTabPosition());
  }

  @Override
  protected void onRestoreInstanceState(Bundle savedInstanceState) {
      super.onRestoreInstanceState(savedInstanceState);
      viewPager.setCurrentItem(savedInstanceState.getInt(POSITION));
  }

References

https://android.googlesource.com/platform/frameworks/support.git/+/master/design/src/android/support/design/widget/TabLayout.java https://android.googlesource.com/platform/frameworks/support.git/+/master/design/res/values/styles.xml

英文原文: https://guides.codepath.com/android/google-play-style-tabs-using-tablayout

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2016/03/08 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 概述
  • Design Support Library
  • Sliding Tabs Layout
  • create-fragment
  • Implement FragmentPagerAdapter
  • Setup Sliding Tabs
  • Heres the output:
  • Styling the TabLayout
  • Add Icons to TabLayout
    • Code
      • Sliding tabs with images:
      • Add Icons+Text to TabLayout
        • Code
          • Sliding tabs with text and images:
          • add-custom-view-to-tablayout
            • Code
              • Sliding tabs with custom view
              • Getting or Selected the Current Page
              • References
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档