TabLayout显示固定的标签数

时间:2024-03-13 16:01:11

转载自https://blog.csdn.net/wanglaohushiwo/article/details/72857691

    TabLayout是Android Design Support Library库中的控件,利用TabLayout可以实现类似网易或者今日头条的效果,但是因为TabLayout不能设置界面显示的固定标签数,所以一直将它将她打入冷宫,未曾临幸于她。但是这么好的一个妃子,仅仅因为这点缺点就不用她,未免有点可惜。所以今天有时间我又看了下TabLayout的源码。


/**
     * Create and return a new {@link Tab}. You need to manually add this using
     * {@link #addTab(Tab)} or a related method.
     *
     * @return A new Tab
     * @see #addTab(Tab)
     */
    @NonNull
    public Tab newTab() {
        Tab tab = sTabPool.acquire();
        if (tab == null) {
            tab = new Tab();
        }
        tab.mParent = this;
        tab.mView = createTabView(tab);
        return tab;
    }
可以看到tabView是在createTabView里创建,再看下createTabView的源码:

    private TabView createTabView(@NonNull final Tab tab) {
        TabView tabView = mTabViewPool != null ? mTabViewPool.acquire() : null;
        if (tabView == null) {
            tabView = new TabView(getContext());
        }
        tabView.setTab(tab);
        tabView.setFocusable(true);
        tabView.setMinimumWidth(getTabMinWidth());
        return tabView;
    }
TabView的高度是在getTabMinWidth方法里设置,再看下getTabMinWidth方法:

private int getTabMinWidth() {
        if (mRequestedTabMinWidth != INVALID_WIDTH) {
            // If we have been given a min width, use it
            return mRequestedTabMinWidth;
        }
        // Else, we'll use the default value
        return mMode == MODE_SCROLLABLE ? mScrollableTabMinWidth : 0;
    }
有两种设置TabVIew宽度的方式,在这里我们没必要设置app:tabMinWidth这个属性,因为屏幕的宽度是不固定的,我们不可能将tabView的宽度设死。所以就跑到else的方法里。在这里mMode的模式有两种MODE_SCROLLABLE和MODE_FIXED,MODE_FIXED是一下子展示所有的TabView,MODE_SCROLLABLE是展示部分的TabView,其他的TabView通过滑动来实现,说着可能不明白,来看效果图:

TabLayout显示固定的标签数

TabLayout显示固定的标签数TabLayout显示固定的标签数


代码如下所示:


package wujf.easemob.com.donnaotest;
 
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
 
import java.util.ArrayList;
import java.util.List;
 
import wujf.easemob.com.donnaotest.fragment.MyFragment;
 
public class TabLayoutActivity extends AppCompatActivity {
    private TabLayout tabLayout;
    private ViewPager vp;
    private List<String> mDatas;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tab_layout);
        tabLayout=(TabLayout) findViewById(R.id.tablayout);
        initData();
        vp=(ViewPager) findViewById(R.id.vp);
        vp.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {
            @Override
            public Fragment getItem(int position) {
                Bundle bundle=new Bundle();
                bundle.putString("title",mDatas.get(position));
                Fragment fragment=new MyFragment();
                fragment.setArguments(bundle);
                return fragment;
            }
 
            @Override
            public int getCount() {
                return mDatas.size();
            }
 
            @Override
            public CharSequence getPageTitle(int position) {
                return mDatas.get(position);
            }
        });
        tabLayout.setupWithViewPager(vp);
 
 
    }
 
    private void initData() {
        mDatas=new ArrayList<>();
        mDatas.add("推荐");
        mDatas.add("热点");
        mDatas.add("南通");
        mDatas.add("视频");
        mDatas.add("社会");
        mDatas.add("娱乐");
        mDatas.add("科技");
        mDatas.add("问答");
        mDatas.add("汽车");
 
    }
}
package wujf.easemob.com.donnaotest.fragment;
 
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
 
/**
 * Created by my on 2017/6/4.
 */
 
public class MyFragment extends Fragment{
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        TextView view=new TextView(getActivity());
        Bundle bundle=getArguments();
        String title=bundle.getString("title");
        view.setText(title);
        return view;
    }
}
<LinearLayout android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    xmlns:android="http://schemas.android.com/apk/res/android">
    <android.support.design.widget.TabLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/tablayout"
        app:tabMode="scrollable"
        >
    </android.support.design.widget.TabLayout>
<android.support.v4.view.ViewPager
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/vp"></android.support.v4.view.ViewPager>
</LinearLayout>
所以要实现类似网易新闻或者今日头条的效果,mMode得设置成MODE_SCROLLABLE,所以决定TabView的宽度的是这个值:mScrollableTabMinWidth,再看一下mScrollableTabMinWidth是在哪里设置的:


private final int mScrollableTabMinWidth;
mScrollableTabMinWidth = res.getDimensionPixelSize(R.dimen.design_tab_scrollable_min_width);
<dimen name="design_tab_scrollable_min_width">72dp</dimen>
那很明白了,TabView的宽度是系统设置死的72dp,因为我的模拟器屏幕宽度是360dp,所以一个屏幕刚好显示5个TabView,那我们想设置4个或者6个怎么办呢。因为mScrollableTabMinWidth这个字段是private final类型的,所以我们无法修改它的值,但不是有反射吗?何不尝试一下。  (修改TabViewNumber的值 需要显示4个就改为4 显示6个就改为6)
自定义MyTabLayout:


package wujf.easemob.com.donnaotest.widgt;
 
import android.content.Context;
import android.support.design.widget.TabLayout;
import android.util.AttributeSet;
 
import java.lang.reflect.Field;
 
/**
 * Created by my on 2017/6/4.
 */
 
public class MyTabLayout extends TabLayout{
    private static final int TabViewNumber = 6;
    private static final String SCROLLABLE_TAB_MIN_WIDTH = "mScrollableTabMinWidth";
    public MyTabLayout(Context context) {
        super(context);
        initTabMinWidth();
    }
 
    public MyTabLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        initTabMinWidth();
    }
 
    public MyTabLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initTabMinWidth();
    }
    private void initTabMinWidth() {
        int screenWidth=getResources().getDisplayMetrics().widthPixels;
        int tabMinWidth = screenWidth / TabViewNumber;
 
        Field field;
        try {
            field = TabLayout.class.getDeclaredField(SCROLLABLE_TAB_MIN_WIDTH);
            field.setAccessible(true);
            field.set(this, tabMinWidth);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}
效果图如下:下图分别对应TabView个数为4个和6个的情况:

TabLayout显示固定的标签数TabLayout显示固定的标签数
so easy,以后可以尽情的享用TabLayout了。




原文:https://blog.csdn.net/wanglaohushiwo/article/details/72857691