一、需求
页面顶部添加Tab条,类似微博首页的关注和热门两个Tab,如下图:
二、方案
三个实现要点:
- TabLayout+FrameLayout
- 两个Tab对应两个Fragment,根据TabLayout.OnTabSelectedListener的回调切换Fragment
- 不使用ViewPager
三、问题
两个下划线样式问题:
- 不支持自定义宽度
- 不支持导圆角
四、解决
有两种方案,最终采用了第二种:
- 使用开源库
MagicIndicator
FlycoTabLayout
NavigationTabStrip
上面三个开源库均支持多种形式的Tab条,其中MagicIndicator支持在非ViewPager场景使用,另两个库目前不支持。 - 自定义下划线
思路:给TabLayout的mTabStrip设置背景实现自定义下划线
优点:可以绘制任意样式的下划线,线条、三角等,只要你想得到
Step1:创建背景Drawable,在onDraw方法中完成自定义的下划线绘制:
public class IndicatorDrawable extends Drawable {
private static final int INDICATOR_MARGIN = ScreenUtils.dp2px(24);
private static final int INDICATOR_HEIGHT = ScreenUtils.dp2px(3);
private static final int INDICATOR_RADIUS = ScreenUtils.dp2px(1.5f);
private View view;
private Paint paint;
public IndicatorDrawable(View view) {
this.view = view;
this.paint = new Paint();
paint.setColor(view.getContext().getResources().getColor(R.color.main_color));
}
@Override
public void draw(@NonNull Canvas canvas) {
int mIndicatorLeft = getIntValue("mIndicatorLeft");
int mIndicatorRight = getIntValue("mIndicatorRight");
int radius = INDICATOR_RADIUS;
if (mIndicatorLeft >= 0 && mIndicatorRight > mIndicatorLeft) {
canvas.drawRoundRect(new RectF(mIndicatorLeft + INDICATOR_MARGIN, view.getHeight() - INDICATOR_HEIGHT, mIndicatorRight - INDICATOR_MARGIN, view.getHeight()), radius, radius, paint);
}
}
private int getIntValue(String name) {
try {
Field f = view.getClass().getDeclaredField(name);
f.setAccessible(true);
Object obj = f.get(view);
return (Integer) obj;
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
@Override
public void setAlpha(@IntRange(from = 0, to = 255) int alpha) {
}
@Override
public void setColorFilter(@Nullable ColorFilter colorFilter) {
}
@Override
public int getOpacity() {
return PixelFormat.UNKNOWN;
}
}
Step2:xml中隐藏掉TabLayout原有的下划线:
<android.support.design.widget.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_gravity="center_horizontal"
android:gravity="center"
android:visibility="gone"
app:tabBackground="@null"
app:tabGravity="center"
app:tabIndicatorColor="@color/main_color"
app:tabIndicatorHeight="0dp"//隐藏原下划线
app:tabMode="fixed"
app:tabPaddingEnd="24dp"
app:tabPaddingStart="24dp"
app:tabTextAppearance="@style/TabTextStyle"//自定义Tab文本样式
app:tabTextColor="@color/light_text_color" />
Step3:代码里使用自定义下划线,即给mStripView设置背景:
private void initTabLayout(FeedHotVideoConfig config) {
tabLayout.removeAllTabs();
tabLayout.clearOnTabSelectedListeners();
View view = LayoutInflater.from(getContext()).inflate(R.layout.feed_tab, null);
tvFollow = (TextView) view.findViewById(R.id.tv_tab);
noticeFollow = view.findViewById(R.id.view_notice);
tabLayout.addTab(tabLayout.newTab().setCustomView(view).setTag(TAG_FOLLOW));//自定义Tab样式
tabLayout.addTab(tabLayout.newTab().setText(config.info.name).setTag(TAG_VIDEO));
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
//Tab点击处理
int tag = (int) tab.getTag();
if (listener != null) {
listener.onTabSelected(tag);
}
refreshTab(tag);
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
View tabStripView = tabLayout.getChildAt(0);
tabStripView.setBackground(new IndicatorDrawable(tabStripView));//设置背景 添加自定义下划线
tabLayout.setVisibility(VISIBLE);
}
五、遇到的问题
- java.lang.NoSuchFieldException: mIndicatorLeft | mIndicatorRight
问题:通过反射获取SlidingTabStrip的两个私有变量值,debug包正常运行,release包报错找不到变量。
解决办法:在混淆文档中去掉对widget包的混淆,即加上
-keep class android.support.design.widget.** { *; }