美文网首页
TabLayout 自定义下划线

TabLayout 自定义下划线

作者: Summer舒舒 | 来源:发表于2017-11-02 22:00 被阅读1646次

    一、需求

    页面顶部添加Tab条,类似微博首页的关注和热门两个Tab,如下图:


    Screenshot_2017-11-02-21-47-09-751_com.sina.weibo.png

    二、方案

    三个实现要点:

    • 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.** { *; }

    相关文章

      网友评论

          本文标题:TabLayout 自定义下划线

          本文链接:https://www.haomeiwen.com/subject/sscapxtx.html