我们开发一个app,登陆页进去以后基本都是底部一排4个或者5个tab,上面是和tab数量相同的各自对应的fragment,每开发一个app就要写一次或者你从以前的项目里copy过来,那既然这样,我们自己封装一下,搞一个组合layout会不会省点事……
⚠️注意:我们这里使用的是design包里面的tablayout,在app下build里添加
implementation 'com.android.support:design:27.1.1'
先看下项目结构:
首先我们先看下TabViewPagerLayout:
public class TabViewPagerLayout extends LinearLayout {
}
因为页面上只有两部分,一部分tablayout,另一部分viewpager,所以这个地方我选择继承自LinearLayout,然后设置Orientation为VERTICAL
//初始化
private void init(Context context) {
this.setOrientation(LinearLayout.VERTICAL);
titleList = new ArrayList<>();
viewList = new ArrayList<>();
viewPager = new ViewPager(context);
tabLayout = new TabLayout(context);
}
接下来就是去初始化tablayout:
前两行代码之所以这么写,是因为当使用addTab()方法给tablayout动态添加文字时可能会出现不显示标题文字的问题,而真实情况并不是不显示文字,而是ViewPager又给TabLayout加了许多空的标题,导致之前手动添加的标题被挤到后面,不信你多往后翻一翻是不是就出来了。那么这些空的标题是如何产生的呢,通过分析TabLayout源码很快就查出这个问题,其中有个方法的代码是这样的:
private 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));
}
}
} else {
removeAllTabs();
}
}
我们注意看这一行:
for (int i = 0; i < adapterCount; i++) {
addTab(newTab().setText(mPagerAdapter.getPageTitle(i)), false);
}
恍然大悟了吧,可以看到在TabLayout里面调用了PageAdapter的方法来添加标题,而添加标题的个数就是在PageAdapter的getCount()方法中设置的,标题的文字是在PageAdapter的getPageTitle()方法中设置。所以我就想:既然它多添加了这么多,那我在它们关联后移除掉所有的tab,然后再添加自己想要的tab不就好了吗,试一试,果然成功了。
tabLayout.setupWithViewPager(viewPager);
tabLayout.removeAllTabs();
for (int i = 0; i < titleList.size(); i++) {
tabLayout.addTab(tabLayout.newTab().setText(titleList.get(i)));
}
/**
* 初始化TabLayout
*/
private void initTabLayout() {
tabLayout.setupWithViewPager(viewPager);
tabLayout.removeAllTabs();
//设置高度
LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, 200);
tabLayout.setLayoutParams(params);
//设置tab的模式
tabLayout.setTabMode(TabLayout.MODE_FIXED);
//tab的字体选择器,默认黑色,选择时红色
tabLayout.setTabTextColors(Color.BLACK, Color.RED);
//tab的下划线颜色,默认是粉红色,如果要自定义选中效果,则可以将下划线设置为和背景色一样.
tabLayout.setSelectedTabIndicatorColor(Color.RED);
for (int i = 0; i < titleList.size(); i++) {
tabLayout.addTab(tabLayout.newTab().setText(titleList.get(i)));
}
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
//将默认位置选中为false
isSelected(tabLayout.getTabAt(initPosition), false);
//选中当前位置
isSelected(tab, true);
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
//tab未选中
isSelected(tab, false);
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
//tab重新选中
isSelected(tab, true);
}
});
//进来默认选中位置第0个item
isSelected(tabLayout.getTabAt(initPosition), true);
}
/**
* 设置选中的tab是否带缩放效果
*
* @param tab
* @param isSelected
*/
private void isSelected(TabLayout.Tab tab, boolean isSelected) {
View view = tab.getCustomView();
if (null != view) {
view.setScaleX(isSelected ? 1.3f : 1.0f);
view.setScaleY(isSelected ? 1.3f : 1.0f);
}
}
isSelected我设置了如果是传入tav的view是自定义view的时候才会有缩放效果,你也可以取消if(null != view)这层判断,就可以实现任何类型都能缩放。
接下来是初始化viewpager:
/**
* 初始化ViewPager
*/
private void initViewP() {
TabViewPAdapter tabViewPAdapter = new TabViewPAdapter<>(viewList);
viewPager.setAdapter(tabViewPAdapter);
if (isNeedAnimation) {
//添加动画
switch (animationType) {
case AnimationType.ZOOM_OUT:
transformer = new ZoomOutPageTransformer();
break;
case AnimationType.DEPTH:
transformer = new DepthPagerTransformer();
break;
}
viewPager.setPageTransformer(false, transformer);
}
}
初始化viewpager里面设置了是否使用动画,目前只添加了两个,有兴趣的朋友自己可以添加哇,
最后是将tablayout和viewpager都添加到父布局中:
/**
* 将tablayout和viewpager添加到当前view中
*/
private void addViews() {
this.addView(tabLayout);
this.addView(viewPager);
}
结束。一个简单的tablayout+viewpager(里面只有textview)的组合就写好了。
这个小组合我已经上传到github,以后会慢慢把其他类型写完整些:
该组合我也上传到jitPack仓库里了,使用方式:在工程build里allprojects添加如下代码:
allprojects {
repositories {
...
maven{url 'https://jitpack.io'}
}
}
然后在app下的build里添加如下代码:
dependencies {
...
implementation 'com.github.gzy760486540:CustomTabVp:1.0'
}
至此就可以在自己的项目里引用这个小组合了,举个例子:
activity_main:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="gzy.customtabvp.MainActivity">
<gzy.customtabviewpager.view.TabViewPagerLayout
android:id="@+id/tabViewPagerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.constraint.ConstraintLayout>
MainActivity.java:
public class MainActivity extends AppCompatActivity {
private gzy.customtabviewpager.view.TabViewPagerLayout tabViewPagerLayout;
private List<String> stringList;
private List<View> viewList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tabViewPagerLayout = findViewById(R.id.tabViewPagerLayout);
initData();
initTab();
}
private void initData() {
stringList = new ArrayList<>();
viewList = new ArrayList<>();
for (int i = 0; i < 5; i++) {
stringList.add(String.valueOf(i));
TextView textView = new TextView(this);
textView.setWidth(ViewGroup.LayoutParams.MATCH_PARENT);
textView.setHeight(ViewGroup.LayoutParams.MATCH_PARENT);
textView.setBackgroundColor(getResources().getColor(R.color.colorAccent));
textView.setText(String.valueOf(i));
textView.setGravity(Gravity.CENTER);
textView.setTextColor(Color.parseColor("#FFFFFF"));
viewList.add(textView);
}
}
private void initTab() {
tabViewPagerLayout.setTitleList(stringList)
.setViewList(viewList)
.isNeedAnimation(true, AnimationType.DEPTH)
.build();
}
}
效果如下:
这里只上传一个图片了,上传gif的时候总是报上传失败。