转载自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通过滑动来实现,说着可能不明白,来看效果图:
代码如下所示:
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个的情况:
so easy,以后可以尽情的享用TabLayout了。
原文:https://blog.csdn.net/wanglaohushiwo/article/details/72857691