澳门威利斯人_威利斯人娱乐「手机版」

来自 办公软件 2020-03-12 03:51 的文章
当前位置: 澳门威利斯人 > 办公软件 > 正文

TabLayout之自定义样式,TabLayout系列之进阶使用

第一张开系统TabLayout源码,查看所在的包

本篇首要介绍TabLayout在支付中有的广泛的用法,不习贯简书代码风格的,也得以在 Android_Note查看.

1 前言

上篇 TabLayout类别之大致利用履新也是有一段时间了,由于专门的学业职分超多且遇上国庆出去玩,就比较久没做改善了。还也是有一点点有关TabLayout的应用未有介绍完,集团的事忙得大概了,几近些日子来三回九转介绍那几个体系。再啰嗦下,前两篇文章介绍了TabLayout的 属性 和 轻便易行利用,需求的惠及能够先去纯熟熟知。那篇小说首借使粗略利用的二个增加补充,以至对自定义TabItem的多个证实。废话非常的少说,我们直接奔向大旨。

图片 1TabLayout类

TabLayout的私下认可样式:

    app:theme="@style/Widget.Design.TabLayout"

从系统定义的该样式继续深刻:

    <style name="Widget.Design.TabLayout" parent="Base.Widget.Design.TabLayout">
        <item name="tabGravity">fill</item>
        <item name="tabMode">fixed</item>
    </style>

    <style name="Base.Widget.Design.TabLayout" parent="android:Widget">
        <item name="tabMaxWidth">264dp</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/TextAppearance.Design.Tab</item>
        <item name="tabSelectedTextColor">?android:textColorPrimary</item>
    </style>

进而,看看系统定义Tab文本的体制(注意textAllcaps那天特性卡塔尔国:

    <style name="TextAppearance.Design.Tab" parent="TextAppearance.AppCompat.Button">
        <item name="android:textSize">14dp</item>
        <item name="android:textColor">?android:textColorSecondary</item>
        <item name="textAllCaps">true</item>
    </style>

从系统定义TabLayout的暗许样式能够见到,大家能够更改TabLayout对应的类别样式的属性值来适配大家团结的要求.

2 TabLayout默认Style

    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TabLayout,
    defStyleAttr, R.style.Widget_Design_TabLayout);

    <style name="Base.Widget.Design.TabLayout" parent="android:Widget">
        <item name="tabMaxWidth">@dimen/design_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/TextAppearance.Design.Tab</item>
        <item name="tabSelectedTextColor">?android:textColorPrimary</item>
    </style>

    <style name="TextAppearance.Design.Tab" parent="TextAppearance.AppCompat.Button">
        <item name="android:textSize">@dimen/design_tab_text_size</item>
        <item name="android:textColor">?android:textColorSecondary</item>
        <item name="textAllCaps">true</item>
    </style>

地点三段代码片段,能够驾驭TabLayout默许使用Base.Widget.Design.TabLayout,里面有预设好的片段个性。此中tabTextAppearance在 Android TabLayout连串之简明利用中早已介绍到了,通过一而再三番五次它来改造暗许立陶宛共和国语字母大写与字体大小意思,由此大家也得以自定义本人的style来兑现团结的要求。

将TabLayout类复制到自身所建的包中,这时候类中所引用的类因为是包权限关系会找不到

TabLayout的主导用法

TabLayout独立使用应用时,能够xml布局中静态增添tab个数及其样式,也足以动态增添Tab的个数及其样式,如:

     <android.support.design.widget.TabLayout
        android:id="@ id/tablayout"
        android:background="@color/colorPrimary"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <android.support.design.widget.TabItem
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Android"/>

        <android.support.design.widget.TabItem
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:icon="@mipmap/ic_launcher"/>
    </android.support.design.widget.TabLayout>

那边写图片描述

或者:

    <android.support.design.widget.TabLayout
        android:id="@ id/tablayout"
        android:background="@color/colorPrimary"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    private int[] images = new int[]{
                    R.drawable.ic_account_balance_wallet_black,
                    R.drawable.ic_android_black,
                    R.drawable.ic_account_box_black};
    private String[] tabs = new String[]{"小说", "电影", "相声"};
    TabLayout tabLayout = (TabLayout) findViewById(R.id.tablayout);
    tabLayout.addTab(tabLayout.newTab().setIcon(images[0]).setText(tabs[0]),true);
    tabLayout.addTab(tabLayout.newTab().setIcon(images[1]).setText(tabs[1]),false);
    tabLayout.addTab(tabLayout.newTab().setIcon(images[2]).setText(tabs[2]),false);

此间写图片描述

TabLayout在实质上支付中最多的是与ViewPager联合使用,达成TabLayout与ViewPager的联动:

    <android.support.design.widget.TabLayout
        android:id="@ id/tablayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/colorPrimary"
        app:tabGravity="fill"
        app:tabIndicatorColor="@android:color/holo_orange_dark"
        app:tabIndicatorHeight="2dp"
        app:tabMode="fixed"
        app:tabSelectedTextColor="@android:color/holo_orange_dark"
        app:tabTextAppearance="@style/CustomTabTextAppearanceStyle"
        app:tabTextColor="@android:color/white"
        app:theme="@style/Widget.Design.TabLayout"/>

    <android.support.v4.view.ViewPager
        android:id="@ id/view_pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    TabLayout tabLayout = (TabLayout) findViewById(R.id.tablayout);
    ViewPager viewPager = (ViewPager) findViewById(R.id.view_pager);
    viewPager.setAdapter(new TabPagerAdapter(getSupportFragmentManager()));
    tabLayout.setupWithViewPager(viewPager);

此处写图片描述

值得注意的是:

在TabPagerAdapter中须求达成getPagerTitle(卡塔尔不然,TabLayout的Tab将不显得,先看TabLayout#setupWithPager(卡塔尔源码,发现Tab的充裕是在populateFromPager艾达pter(卡塔尔国中贯彻,完毕源码如下,能够看出该方法调用了PagerAdpater#getPagerTitle(卡塔尔国为Tab设置文本消息,假如我们自定义的Adapter未有贯彻getPagerTitle(卡塔尔将会促成Tab不展现文本消息.

    void populateFromPagerAdapter() {
        removeAllTabs();

        if (mPagerAdapter != null) {
            final int adapterCount = mPagerAdapter.getCount();
            for (int i = 0; i < adapterCount; i  ) {
                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));
                }
            }
        }
    }

别的, 我们开掘getPagerTitle(卡塔尔(قطر‎方法的回到值CharSequence并不是String,那么Tab的文件新闻的安装将变得进一层灵敏,比如设置三个SpanableString,将图片和文件设置Tab的文本.

        @Override
        public CharSequence getPageTitle(int position) {
            Drawable image = TablayoutActivity.this.getResources().getDrawable(images[position]);
            image.setBounds(0, 0, image.getIntrinsicWidth()/2, image.getIntrinsicHeight()/2);
            ImageSpan imageSpan = new ImageSpan(image, ImageSpan.ALIGN_BOTTOM);
            SpannableString ss = new SpannableString(" " tabs[position]);
            ss.setSpan(imageSpan, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            return ss;
        }   

而是Tab却没将image显示出来,从地点提到的TabLayout的种类默许样式中大家开掘: <item name="textAllCaps">true</item>,那会堵住ImageSpan渲染出来,大家只供给将textAllCaps改为false就可以,如下概念,再一次启动,成功展现

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

此间写图片描述

3 带图片的Tab

Android TabLayout体系之简明利用中,介绍到了TabLayout的施用,但多数都以纯文本的TabItem,并不曾兑现带图片的TabItem。本次就闲来撸贰个带图片的TabItem,依然老办法先上代码(码注释卡塔尔-> 效果图 -> 深入分析。

    public class MainActivity extends BaseActivity {

        private TabLayout mTabLayout;
        private ViewPager mViewPager;
        private MainPagerAdapter mAdapter;

        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            AppStatusTracker.init(getApplication());
            super.onCreate(savedInstanceState);
        }

        @Override
        protected void initContentView() {
            setContentView(R.layout.activity_main);
        }

        @Override
        protected void initView() {
            mTabLayout = findView(R.id.tabLayout);
            mViewPager = findView(R.id.viewPager);
            mAdapter = new MainPagerAdapter(getSupportFragmentManager());
            mViewPager.setAdapter(mAdapter);
            //官方推荐的绑定ViewPager方式
            mTabLayout.setupWithViewPager(mViewPager);
            int tabCount = mTabLayout.getTabCount();
            for (int i = 0; i < tabCount; i  ) {
                //这里tab可能为null 根据实际情况处理吧
                mTabLayout.getTabAt(i).setText("Tab"   i);
                //设置图片icon
                mTabLayout.getTabAt(i).setIcon(R.mipmap.ic_launcher);
            }
        }

        @Override
        protected void initData(@Nullable Bundle savedInstanceState) {

        }

        //ViewPager适配器  10个Fragment
        private class MainPagerAdapter extends FragmentPagerAdapter {
            public MainPagerAdapter(FragmentManager fm) {
                super(fm);
            }

            @Override
            public Fragment getItem(int position) {
                return BlankFragment.newInstance(position);
            }

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

图片 2

这里的demo代码和Android TabLayout体系之大致利用中的一致,只是增添了 mTabLayout.getTabAt(i卡塔尔国.setIcon(Escort.mipmap.ic_launcher卡塔尔来安装TabView中Tab的图片。这里显示效果是合法提供的暗中认可实现,TabView世襲至Linearlayout且被设置成了竖直方向。这一点能够从TabView的构造器中看见:

        public TabView(Context context) {
            super(context);
            ......
            setGravity(Gravity.CENTER);
            setOrientation(VERTICAL);   //设置成竖直方向
            ......
        }

至于为啥来得在首先个,能够从TabView的update方法精通到:

    final void update() {
            final Tab tab = mTab;
            final View custom = tab != null ? tab.getCustomView() : null;
            ......
            ......
            if (mCustomView == null) {
                // If there isn't a custom view, we'll us our own in-built layouts
                if (mIconView == null) {
                    ImageView iconView = (ImageView) LayoutInflater.from(getContext())
                            .inflate(R.layout.design_layout_tab_icon, this, false);
                    addView(iconView, 0);   //将ImageView放在了LinearLayout的0位
                    mIconView = iconView;
                }
                if (mTextView == null) {
                    TextView textView = (TextView) LayoutInflater.from(getContext())
                            .inflate(R.layout.design_layout_tab_text, this, false);
                    addView(textView);  //添加TextView
                    mTextView = textView;
                    mDefaultMaxLines = TextViewCompat.getMaxLines(mTextView);
                }
                TextViewCompat.setTextAppearance(mTextView, mTabTextAppearance);
                if (mTabTextColors != null) {
                    mTextView.setTextColor(mTabTextColors);
                }
                updateTextAndIcon(mTextView, mIconView); //更新文本和icon
            } else {
                // Else, we'll see if there is a TextView or ImageView present and update them
                if (mCustomTextView != null || mCustomIconView != null) {
                    updateTextAndIcon(mCustomTextView, mCustomIconView);
                }
            }

            // Finally update our selected state
            setSelected(tab != null && tab.isSelected());
    }

那中间的TabView是一直不get方法的,所以大家取不到,能够因此反射获得做一些急需的操作,就不说明了,因为大家这里是需求自定义TabView。

比如:

修改Indicator的长度:

从TabLayout的源码能够见到Indicator的绘图,是在此中间类SlidingTabStrip中绘制,而SlingTabStrip类世襲LinearLayout,源码如下:

    @Override  
    public void draw(Canvas canvas) {  
        super.draw(canvas);  

        // Thick colored underline below the current selection  
        if (mIndicatorLeft >= 0 && mIndicatorRight > mIndicatorLeft) {  
            canvas.drawRect(mIndicatorLeft, getHeight() - mSelectedIndicatorHeight,  
                    mIndicatorRight, getHeight(), mSelectedIndicatorPaint);  
        }  
    }

在onDraw(State of Qatar中首借使就绘制三个Rect,并且宽度是依赖mIndicatorLeft和mIndicatorRight设置的,而mIndicatorLeft等的上涨的幅度来自SlidingTabStrip的child,而Child就一定于四个Tab,那样大家就透过校正Child的margin来设置mIndicatorLeft的值.

    public void setIndicator(TabLayout tabs, int leftDip, int rightDip) {
        Class<?> tabLayout = tabs.getClass();
        Field tabStrip = null;
        try {
            tabStrip = tabLayout.getDeclaredField("mTabStrip");
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

        tabStrip.setAccessible(true);
        LinearLayout llTab = null;
        try {
            llTab = (LinearLayout) tabStrip.get(tabs);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        int left = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, leftDip, Resources.getSystem().getDisplayMetrics());
        int right = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, rightDip, Resources.getSystem().getDisplayMetrics());

        for (int i = 0; i < llTab.getChildCount(); i  ) {
            View child = llTab.getChildAt(i);
            child.setPadding(0, 0, 0, 0);
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.MATCH_PARENT, 1);
            params.leftMargin = left;
            params.rightMargin = right;
            child.setLayoutParams(params);
            child.invalidate();
        }
    }

然后在代码中调用就可以,可是要静心,必需求在Tablayout渲染出来后调用,大家得以选取view.post(卡塔尔(قطر‎方法来达成:

    tabLayout.post(new Runnable() {
            @Override
            public void run() {
                setIndicator(tabLayout, 20, 20);
            }
    });

末段获得效果图如下:

这里写图片描述

4 自定义带图片的Tab

看源码或API的话能够通晓Tab有个setCustomView(@Nullable View view卡塔尔方法,可用来增多自定义的TabItem。

  1. 先是得来个TabItem的Layout Resource文件:
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal">

        <TextView
            android:id="@ id/text_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:text="Tab1"
            android:textSize="14sp"/>

        <ImageView
            android:id="@ id/image_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:layout_marginBottom="0dp"
            android:src="@mipmap/ic_indicator"/>
    </LinearLayout>
  1. 附带在大家的Activity达成大家的功力
    public class MainActivity extends BaseActivity implements TabLayout.OnTabSelectedListener {

        private TabLayout mTabLayout;
        private ViewPager mViewPager;
        private MainPagerAdapter mAdapter;

        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            AppStatusTracker.init(getApplication());
            super.onCreate(savedInstanceState);
        }

        @Override
        protected void initContentView() {
            setContentView(R.layout.activity_main);
        }

        @Override
        protected void initView() {
            mTabLayout = findView(R.id.tabLayout);
            mViewPager = findView(R.id.viewPager);
            mAdapter = new MainPagerAdapter(getSupportFragmentManager());
            mViewPager.setAdapter(mAdapter);
            //官方推荐的绑定ViewPager方式
            mTabLayout.setupWithViewPager(mViewPager);
            int tabCount = mTabLayout.getTabCount();
            for (int i = 0; i < tabCount; i  ) {
                TabLayout.Tab tab = mTabLayout.getTabAt(i);
                if (tab == null) return;
                //设置自定义的View
                tab.setCustomView(mAdapter.getTabView(i));
            }

            //需要自己实现选中监听,来实现自己需要的效果
            mTabLayout.addOnTabSelectedListener(this);
        }

        @Override
        protected void initData(@Nullable Bundle savedInstanceState) {

        }

        @Override
        public void onTabSelected(TabLayout.Tab tab) {
            //Toast.makeText(this, "onTabSelected", Toast.LENGTH_SHORT).show();
            changeTabStatus(tab, true);
        }

        @Override
        public void onTabUnselected(TabLayout.Tab tab) {
            //Toast.makeText(this, "onTabUnselected", Toast.LENGTH_SHORT).show();
            changeTabStatus(tab, false);
        }

        @Override
        public void onTabReselected(TabLayout.Tab tab) {
            //Toast.makeText(this, "onTabReselected", Toast.LENGTH_SHORT).show();
            new AlertDialog.Builder(this)
                    .setMessage("再次选中,显示对话框!")
                    .show();
        }

        private void changeTabStatus(TabLayout.Tab tab, boolean selected) {
            View view = tab.getCustomView();
            TextView txtTitle = (TextView) view.findViewById(R.id.text_title);
            if (selected) {
                txtTitle.setTextColor(Color.parseColor("#03ce97"));
            } else {
                txtTitle.setTextColor(Color.parseColor("#333333"));
            }
        }

        //ViewPager适配器  10个Fragment
        private class MainPagerAdapter extends FragmentPagerAdapter {
            public MainPagerAdapter(FragmentManager fm) {
                super(fm);
            }

            //自定义获取Tab View的方法
            public View getTabView(int position) {
                View view = LayoutInflater.from(MainActivity.this).inflate(R.layout.custom_tab_item, null);
                TextView tv = (TextView) view.findViewById(R.id.text_title);
                tv.setText("Tab "   position);
                return view;
            }

            @Override
            public Fragment getItem(int position) {
                return BlankFragment.newInstance(position);
            }

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

图片 3

从效果与利益图上看,已经落到实处了自定义的TabItem,需求小心的是需求基于Tab的入选状态来,完成自身想要的机能,包罗Tab字体颜色的改换,Logo的转动作效果果,选中Tab放大等等...... 笔者那边只兑现了文字颜色的改换,和重复入选弹出对话框。如若大家只是要求图像和文字显示,大家不自定义TabItem也足以达成相符这种意义,直接在getPageTitle中央银行使ImageSpan让文字和图片一同展现。

        //TabLayout会根据当前page的title自动绑定tab
        @Override
        public CharSequence getPageTitle(int position) {
            Drawable image = ContextCompat.getDrawable(MainActivity.this, R.mipmap.ic_indicator);
            image.setBounds(0, 0, image.getIntrinsicWidth(), image.getIntrinsicHeight());
            ImageSpan imageSpan = new ImageSpan(image, ImageSpan.ALIGN_BOTTOM);
            SpannableString ss = new SpannableString("Tab"   position   " ");
            ss.setSpan(imageSpan, ss.length() - 1, ss.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            return ss;
        }

1:ThemeUtils

自定义TabLayout的TabItem及TabItem的点击事件

在TabLayout的Api是还没提供TabItem点击事件的不二等秘书技,倘使大家想完结如下效果图,如何是好?

此处写图片描述

先自定义一个TabItem:

<?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"
    android:gravity="center"
    android:orientation="horizontal">

    <TextView
        android:id="@ id/txt_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:textSize="14sp" />

    <ImageView
        android:id="@ id/img_title"
        android:src="@drawable/indicator"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="5dp" />

</LinearLayout>

在自定义的Adapter中能够定义贰个getTabView的章程:

    public View getTabView(int position){
        View view = LayoutInflater.from(context).inflate(R.layout.tab_item, 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]);
        return view;
    }

再也设置点击事件:

    viewPager.setAdapter(pagerAdapter);
    tabLayout.setupWithViewPager(viewPager);
    for (int i = 0; i < tabLayout.getTabCount(); i  ) {
        TabLayout.Tab tab = tabLayout.getTabAt(i);
        if (tab != null) {
            tab.setCustomView(pagerAdapter.getTabView(i));
            if (tab.getCustomView() != null) {
                View tabView = (View) tab.getCustomView().getParent();
                tabView.setTag(i);
                tabView.setOnClickListener(mTabOnClickListener);
            }
        }
    }
    viewPager.setCurrentItem(1);

5 源码深入分析达成上述意义

不深入分析波源码都缺乏装13的,其实亦不是本人想分析,只是有的时候见到,然后使用了一下感到并不是很利索,不太通晓官方为何要这么做。英特网有成都百货上千深入解析TabLayout,关于这么些自定义TabItem源码,可是尚未见到解析这一段的。风乐趣的能够跟着看看,直接追踪Tab的setCustomView,找到TabView的update方法,代码不短60来行:

    final void update() {
        final Tab tab = mTab;
        //获取Tab里面的CustomView
        final View custom = tab != null ? tab.getCustomView() : null;
        //根据获取出来的custom做相应操作,得到最终的CustomView
        if (custom != null) {
            final ViewParent customParent = custom.getParent();
            if (customParent != this) {
                if (customParent != null) {
                    ((ViewGroup) customParent).removeView(custom);
                }
                addView(custom);
            }
            mCustomView = custom;
            //custom不为空,且判断和处理系统本身的mTextView、mIconView 
            if (mTextView != null) {
                mTextView.setVisibility(GONE);
            }
            if (mIconView != null) {
                mIconView.setVisibility(GONE);
                mIconView.setImageDrawable(null);
            }
            //注意这里!!!从custom去获取ID为android.R.id.text1
            //我猜想系统是想让我们自定义CustomView的时候使用这个id
            mCustomTextView = (TextView) custom.findViewById(android.R.id.text1);
            if (mCustomTextView != null) {
                mDefaultMaxLines = TextViewCompat.getMaxLines(mCustomTextView);
            }
            //注意这里!!!从custom去获取ID为android.R.id.icon
            //我猜想系统是想让我们自定义CustomView的时候使用这个id
            mCustomIconView = (ImageView) custom.findViewById(android.R.id.icon);
        } else {
            //这里注释很清楚了,就不多说了
            // We do not have a custom view. Remove one if it already exists
            if (mCustomView != null) {
                removeView(mCustomView);
                mCustomView = null;
            }
            mCustomTextView = null;
            mCustomIconView = null;
        }

        //接下来就是判断CustomView做一些操作了
        if (mCustomView == null) {
            //这里的意思是没有自定义的,就创建默认的
            // If there isn't a custom view, we'll us our own in-built layouts
            if (mIconView == null) {
                ImageView iconView = (ImageView) LayoutInflater.from(getContext())
                        .inflate(R.layout.design_layout_tab_icon, this, false);
                addView(iconView, 0);
                mIconView = iconView;
            }
            if (mTextView == null) {
                TextView textView = (TextView) LayoutInflater.from(getContext())
                        .inflate(R.layout.design_layout_tab_text, this, false);
                addView(textView);
                mTextView = textView;
                mDefaultMaxLines = TextViewCompat.getMaxLines(mTextView);
            }
            TextViewCompat.setTextAppearance(mTextView, mTabTextAppearance);
            if (mTabTextColors != null) {
               //设置文本颜色(选中和未选中)
                mTextView.setTextColor(mTabTextColors);
            }
            //更新文本和图标
            updateTextAndIcon(mTextView, mIconView);
        } else {
            // Else, we'll see if there is a TextView or ImageView present and update them
            if (mCustomTextView != null || mCustomIconView != null) {
                //更新文本和图标
                updateTextAndIcon(mCustomTextView, mCustomIconView);
            }
        }

        // Finally update our selected state
        setSelected(tab != null && tab.isSelected());
    }

有关源码的分析都注释在代码里,对应着代码看,特别清晰。通过源码解析,系统好像想让大家采纳那多个id(借使独有TextView和ImageView的话),那样的话是或不是大家就毫无管理局地逻辑了,使用起来尤其easy了吗?答案当然是还是不是认的,作者测量试验的效果是文本的水彩不会基于TabLayout里面安装的同一退换,并且Logo距尾巴部分有叁个8dp的margin值。为啥呢?文本颜色不改变从下边这段代码能够看出来,当大家有CustomView时,并未给大家调用相应的setTextColor。底边距就得继续看updateTextAndIcon方法:

    private void updateTextAndIcon(@Nullable final TextView textView,
            @Nullable final ImageView iconView) {
        //下面一段没什么好说的,就是获取Drawable 和CharSequence并设置显示或隐藏
        final Drawable icon = mTab != null ? mTab.getIcon() : null;
        final CharSequence text = mTab != null ? mTab.getText() : null;
        final CharSequence contentDesc = mTab != null ? mTab.getContentDescription() : null;

        if (iconView != null) {
            if (icon != null) {
                iconView.setImageDrawable(icon);
                iconView.setVisibility(VISIBLE);
                setVisibility(VISIBLE);
            } else {
                iconView.setVisibility(GONE);
                iconView.setImageDrawable(null);
            }
            iconView.setContentDescription(contentDesc);
        }

        final boolean hasText = !TextUtils.isEmpty(text);
        if (textView != null) {
            if (hasText) {
                textView.setText(text);
                textView.setVisibility(VISIBLE);
                setVisibility(VISIBLE);
            } else {
                textView.setVisibility(GONE);
                textView.setText(null);
            }
            textView.setContentDescription(contentDesc);
        }

        if (iconView != null) {
            //获取出layout参数
            MarginLayoutParams lp = ((MarginLayoutParams) iconView.getLayoutParams());
            int bottomMargin = 0;
            if (hasText && iconView.getVisibility() == VISIBLE) {
                 /这里说得很清楚,如果两者都显示,就给icon的bottom加一些底边距
                // If we're showing both text and icon, add some margin bottom to the icon
                bottomMargin = dpToPx(DEFAULT_GAP_TEXT_ICON); //8dp
            }
            //判断它加的一些底边距和布局设置的不一致,就使用它加的,并请求重绘
            if (bottomMargin != lp.bottomMargin) {
                lp.bottomMargin = bottomMargin;
                iconView.requestLayout();
            }
        }

        if (!hasText && !TextUtils.isEmpty(contentDesc)) {
            setOnLongClickListener(this);
        } else {
            setOnLongClickListener(null);
            setLongClickable(false);
        }
    }

实效就不提交了,照旧我们手动测测,关于结构将TextView和ImageView的id改为@android:id/text1和@android:id/icon就OK了。须求留意的是还得手动在代码里安装上文本的颜料和依据需求的MarginLayoutParams,下边直接交给代码。

    public class MainActivity extends BaseActivity implements TabLayout.OnTabSelectedListener {

        private TabLayout mTabLayout;
        private ViewPager mViewPager;
        private MainPagerAdapter mAdapter;

        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            AppStatusTracker.init(getApplication());
            super.onCreate(savedInstanceState);
        }

        @Override
        protected void initContentView() {
            setContentView(R.layout.activity_main);
        }

        @Override
        protected void initView() {
            mTabLayout = findView(R.id.tabLayout);
            mViewPager = findView(R.id.viewPager);
            mAdapter = new MainPagerAdapter(getSupportFragmentManager());
            mViewPager.setAdapter(mAdapter);
            //官方推荐的绑定ViewPager方式
            mTabLayout.setupWithViewPager(mViewPager);
            int tabCount = mTabLayout.getTabCount();
            for (int i = 0; i < tabCount; i  ) {
                TabLayout.Tab tab = mTabLayout.getTabAt(i);
                if (tab == null) return;
                //设置自定义的View
                tab.setCustomView(R.layout.custom_tab_item);
                tab.setText("Tab"   i);
                tab.setIcon(R.mipmap.ic_indicator);
                View customView = tab.getCustomView();
                if (customView == null) return;
                //注意设置了文本颜色和MarginLayoutParams 
                ((TextView) customView.findViewById(android.R.id.text1)).setTextColor(mTabLayout.getTabTextColors());
                View icon = customView.findViewById(android.R.id.icon);
                ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) icon.getLayoutParams();
                layoutParams.bottomMargin = 0;
                icon.setLayoutParams(layoutParams);
            }

            //需要自己实现选中监听,来实现自己需要的效果
            mTabLayout.addOnTabSelectedListener(this);
        }

        @Override
        protected void initData(@Nullable Bundle savedInstanceState) {

        }

        @Override
        public void onTabSelected(TabLayout.Tab tab) {

        }

        @Override
        public void onTabUnselected(TabLayout.Tab tab) {

        }

        @Override
        public void onTabReselected(TabLayout.Tab tab) {
            new AlertDialog.Builder(this)
                    .setMessage("再次选中,显示对话框!")
                    .show();
        }

        //ViewPager适配器  10个Fragment
        private class MainPagerAdapter extends FragmentPagerAdapter {
            public MainPagerAdapter(FragmentManager fm) {
                super(fm);
            }

            @Override
            public Fragment getItem(int position) {
                return BlankFragment.newInstance(position);
            }

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

废话太多了,原生TabLayout使用就那样多,源码中正是变化万千。纵然期望达成更加的多炫耀效果,能够自定义或许GitHub.....

附:

  1. Android TabLayout类别之性质
  2. Android TabLayout种类之大致利用
  3. Android TabLayout类别之进级使用

图片 4ThemeUtils类

2:TabItem

图片 5TabItem类

3:AnimationUtils

图片 6AnimationUtils类

如上八个类如下图

本文由澳门威利斯人发布于办公软件,转载请注明出处:TabLayout之自定义样式,TabLayout系列之进阶使用

关键词: 澳门威利斯人 分割线 下划线 宽度 半栈工程师