TabLayout-Android M新控件

简介: TabLayout-Android M新控件

概述


官方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.

<?xml version="1.0" encoding="utf-8"?>
<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:

<?xml version="1.0" encoding="utf-8"?>
<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:

// 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.

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.

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:

20160308214356543.jpg


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:

<style name="MyCustomTabLayout" parent="Widget.Design.TabLayout">
    <item name="tabIndicatorColor">#0000FF</item>
</style>

You can then override this style for your TabLayout:

<android.support.design.widget.TabLayout
        android:id="@+id/tabs"
        style="@style/MyCustomTabLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
</android.support.design.widget.TabLayout>


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

<style name="MyCustomTabLayout" parent="Widget.Design.TabLayout">
    <item name="tabMaxWidth">@dimen/tab_max_width</item>
    <item name="tabIndicatorColor">?attr/colorAccent</item>
    <item name="tabIndicatorHeight">2dp</item>
    <item name="tabPaddingStart">12dp</item>
    <item name="tabPaddingEnd">12dp</item>
    <item name="tabBackground">?attr/selectableItemBackground</item>
    <item name="tabTextAppearance">@style/MyCustomTabTextAppearance</item>
    <item name="tabSelectedTextColor">?android:textColorPrimary</item>
</style>
<style name="MyCustomTabTextAppearance" parent="TextAppearance.Design.Tab">
    <item name="android:textSize">14sp</item>
    <item name="android:textColor">?android:textColorSecondary</item>
    <item name="textAllCaps">true</item>
</style>


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


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.

<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>

Sliding tabs with images:


20160308214837189.jpg


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

@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:


20160308215059021.jpg


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

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:

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

    /**
     * 自定义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


20160308215451843.gif


Getting or Selected the Current Page

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


With the recent updates to the design support library, you can also get the seleselected 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:

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.

 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

相关文章
|
9月前
|
XML Java Android开发
Android Studio App开发中改造已有的控件实战(包括自定义支付宝月份选择器、给翻页栏添加新属性、不滚动的列表视图 附源码)
Android Studio App开发中改造已有的控件实战(包括自定义支付宝月份选择器、给翻页栏添加新属性、不滚动的列表视图 附源码)
161 1
|
5月前
|
XML 编解码 Android开发
安卓开发中的自定义视图控件
【9月更文挑战第14天】在安卓开发中,自定义视图控件是一种高级技巧,它可以让开发者根据项目需求创建出独特的用户界面元素。本文将通过一个简单示例,引导你了解如何在安卓项目中实现自定义视图控件,包括创建自定义控件类、处理绘制逻辑以及响应用户交互。无论你是初学者还是有经验的开发者,这篇文章都会为你提供有价值的见解和技巧。
80 3
|
4月前
|
XML 存储 Java
浅谈Android的TextView控件
浅谈Android的TextView控件
61 0
|
6月前
|
前端开发 Android开发 开发者
安卓开发中的自定义视图:构建你的第一个控件
【8月更文挑战第26天】在安卓开发的浩瀚海洋中,自定义视图是一块充满魔力的乐土。它不仅是开发者展示创造力的舞台,更是实现独特用户体验的关键。本文将带你步入自定义视图的世界,从基础概念到实战应用,一步步教你如何打造自己的第一个控件。无论你是初学者还是有经验的开发者,这篇文章都将为你的开发之旅增添新的风景。
|
8月前
|
Java Android开发
18. 【Android教程】图片控件 ImageView
18. 【Android教程】图片控件 ImageView
140 4
|
8月前
|
前端开发 API Android开发
25. 【Android教程】列表控件 ListView
25. 【Android教程】列表控件 ListView
291 2
|
8月前
|
Java Android开发 开发者
17. 【Android教程】开关控件ToggleButton/Switch
17. 【Android教程】开关控件ToggleButton/Switch
114 2
|
7月前
|
XML 数据格式
Android-自定义三角形评分控件
Android-自定义三角形评分控件
64 0
|
8月前
|
XML Android开发 数据格式
Android基础控件介绍
Android基础控件介绍
|
8月前
|
Android开发
Android 自定义View 测量控件宽高、自定义viewgroup测量
Android 自定义View 测量控件宽高、自定义viewgroup测量
187 0

热门文章

最新文章

  • 1
    【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
  • 2
    Android历史版本与APK文件结构
  • 3
    【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
  • 4
    当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
  • 5
    APP-国内主流安卓商店-应用市场-鸿蒙商店上架之必备前提·全国公安安全信息评估报告如何申请-需要安全评估报告的资料是哪些-优雅草卓伊凡全程操作
  • 6
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
  • 7
    【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
  • 8
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
  • 9
    Cellebrite UFED 4PC 7.71 (Windows) - Android 和 iOS 移动设备取证软件
  • 10
    escrcpy:【技术党必看】Android开发,Escrcpy 让你无线投屏新体验!图形界面掌控 Android,30-120fps 超流畅!🔥
  • 1
    android FragmentManager 删除所有Fragment 重建
    15
  • 2
    Android实战经验之Kotlin中快速实现MVI架构
    21
  • 3
    即时通讯安全篇(一):正确地理解和使用Android端加密算法
    24
  • 4
    escrcpy:【技术党必看】Android开发,Escrcpy 让你无线投屏新体验!图形界面掌控 Android,30-120fps 超流畅!🔥
    39
  • 5
    【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
    122
  • 6
    Cellebrite UFED 4PC 7.71 (Windows) - Android 和 iOS 移动设备取证软件
    40
  • 7
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    55
  • 8
    Android历史版本与APK文件结构
    149
  • 9
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    46
  • 10
    【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
    40