Android---TabLayout很好的操作教程,指示器下划线设置图片与传统流行的XtabLayout对比

话不多说,先看图

这个采用的是

这个采用的是渐变的图片,TabLayout采用的是自定义的。

-----------------------------------------------------------------------------------------------

这个采用的是纯色color,TabLayout采用的是 implementation 'com.androidkun:XTabLayout:1.1.3'

-----------------------------------------------------------------------------------------------

对比。二者都可以达到切换字体方法,点击或者滑动切换,指示器均可以含有动画的移动过渡。

下面贴一下用法。

方法一:带自定义指示器图片的,为drawable资源下的图片

①采用SlidingTabLayout自定义控件

/**
 * ================================================
 *
 * @author :Vip
 * @version :V 1.0.0
 * @date :2019/6/21 17:38
 * 描    述:支持自定义下标,自定义tab宽度
 * 修订历史:
 * ================================================
 */
public class SlidingTabLayout extends TabLayout {
    /**
     * 每个tab的宽度
     */
    private int tabWidth;
    /**
     * 屏幕宽度
     */
    private int mScreenWidth;
    /**
     * 自定义指示器
     */
    private Bitmap mSlideIcon;
    /**
     * 滑动过程中指示器的水平偏移量
     */
    private int mTranslationX;
    /**
     * 指示器初始X偏移量
     */
    private int mInitTranslationX;
    /**
     * 指示器初始Y偏移量
     */
    private int mInitTranslationY;
    /**
     * 默认的页面可见的tab数量
     */
    private static final int COUNT_DEFAULT_VISIBLE_TAB = 4;
    /**
     * 页面可见的tab数量,默认4个
     */
    private int mTabVisibleCount = COUNT_DEFAULT_VISIBLE_TAB;

    public SlidingTabLayout(Context context) {
        super(context);
    }

    public SlidingTabLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        //核心:指示器自定义的图片线条
        this.mSlideIcon = BitmapFactory.decodeResource(getResources(), R.drawable.ic_indicator_yellow);
        this.mScreenWidth = getResources().getDisplayMetrics().widthPixels;
        @SuppressLint({"Recycle", "CustomViewStyleable"}) TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TabLayoutLine);
        //指示器数量
        mTabVisibleCount = ta.getInteger(R.styleable.TabLayoutLine_selectedNum, 2);
        //异步修改Tab宽度
        post(new Runnable() {
            @Override
            public void run() {
                resetTabParams();
            }
        });
    }

    /**
     * 重绘下标
     */
    public void redrawIndicator(int position, float positionOffset) {
        mTranslationX = (int) ((position + positionOffset) * tabWidth);
        invalidate();
    }

    /**
     * 动态设图
     **/

    public void setmSlideIcon(Bitmap mSlideIcon) {
        this.mSlideIcon = mSlideIcon;
    }

    /**
     * tab的父容器,注意空指针
     */
    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
    @Nullable
    public LinearLayout getTabStrip() {
        Class<?> tabLayout = TabLayout.class;
        Field tabStrip = null;
        try {
            tabStrip = tabLayout.getDeclaredField("mTabStrip");
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

        assert tabStrip != null;
        tabStrip.setAccessible(true);
        LinearLayout llTab = null;
        try {
            llTab = (LinearLayout) tabStrip.get(this);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        assert llTab != null;
        llTab.setClipChildren(false);
        return llTab;
    }

    /**
     * 绘制指示器
     */
    @Override
    protected void dispatchDraw(Canvas canvas) {
        if (mSlideIcon == null) {
            return;
        }
        canvas.save();
        // 平移到正确的位置,修正tabs的平移量
        canvas.translate(mInitTranslationX + mTranslationX, this.mInitTranslationY);
        canvas.drawBitmap(this.mSlideIcon, 0, 0, null);
        canvas.restore();
        super.dispatchDraw(canvas);
    }

    /**
     * 重设tab宽度
     */
    private void resetTabParams() {
        LinearLayout tabStrip = getTabStrip();
        if (tabStrip == null) {
            return;
        }
        for (int i = 0; i < tabStrip.getChildCount(); i++) {
            LinearLayout tabView = (LinearLayout) tabStrip.getChildAt(i);
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams((mScreenWidth / (mTabVisibleCount)), LinearLayout.LayoutParams
                    .WRAP_CONTENT);
            tabView.setLayoutParams(params);
            //tab中的图标可以超出父容器
            tabView.setClipChildren(false);
            tabView.setClipToPadding(false);

            tabView.setPadding(0, 30, 0, 30);
        }
        initTranslationParams(tabStrip, mScreenWidth);
    }

    /**
     * 初始化三角下标的坐标参数
     */
    private void initTranslationParams(LinearLayout llTab, int screenWidth) {
        if (mSlideIcon == null) {
            return;
        }
        tabWidth = (screenWidth / (mTabVisibleCount));
        View firstView = llTab.getChildAt(0);
        if (firstView != null) {
            this.mInitTranslationX = (firstView.getLeft() + tabWidth / 2 - this.mSlideIcon.getWidth() / 2);
            this.mInitTranslationY = (getBottom() - getTop() - this.mSlideIcon.getHeight());
        }
    }
}

补充:

在attrs.xml文件下,设置这个自定义控件的一个属性。设置默认数量,方便在你布局引用的地方,提前设置你想显示几个。

 

②布局引用:

<!--有数据-->
<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_below="@+id/include_top_base"
    tools:ignore="UselessParent">
    <!--标签-->
    <com.yc.stscf.widget.SlidingTabLayout
        android:id="@+id/tab_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/white"
        app:selectedNum="2"
        app:tabGravity="fill"
        app:tabSelectedTextColor="@color/cs_F88441"
        app:tabTextColor="@color/cs_999999"
        app:tabIndicatorHeight="0dp"
        app:tabMaxWidth="0dp"
        app:tabMode="fixed" />
    <View
        android:id="@+id/view_line"
        style="@style/App_RootView_H"
        android:layout_below="@+id/tab_layout" />

    <com.yc.stscf.widget.TabViewPager
        android:id="@+id/vp_all"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/view_line"
        android:layout_marginTop="@dimen/ds_10dp" />
</RelativeLayout>

③在java代码中写:

/**
 * ================================================
 *
 * @author :Vip
 * @version :V 1.0.0
 * @date :2019/6/12 9:31
 * 描    述:全部审批
 * 修订历史:
 * ================================================
 */

public class MyTabApprovalFragment extends BaseFragment {
    @BindView(R.id.iv_back)
    ImageView ivBack;
    @BindView(R.id.tv_tittle)
    TextView tvTittle;
    @BindView(R.id.tv_base_some)
    TextView tvBaseSome;
    @BindView(R.id.iv_white_search)
    ImageButton ivWhiteSearch;
    @BindView(R.id.tv_add)
    TextView tvAdd;
    @BindView(R.id.tv_commit)
    TextView tvCommit;
    @BindView(R.id.vp_all)
    TabViewPager vpAll;
    @BindView(R.id.tab_layout)
    SlidingTabLayout tabLayout;
    @BindView(R.id.iv_triangle_white)
    ImageView ivTriangleWhite;
    @BindView(R.id.rl_title_all)
    RelativeLayout rlTitleAll;
    Unbinder unbinder;
    /**
     * 总布局
     **/
    private View view = null;
    /**
     * 标志位,标志已经初始化完成
     **/
    private boolean isPrepared;
    private List<String> strings = new ArrayList<String>();
    private List<Fragment> fragments = new ArrayList<>();
    private String[] tabTitles = {"待审批", "已审批"};
 
    @SuppressLint("InflateParams")
    @Override
    protected View initLayout(LayoutInflater inflater, ViewGroup container, boolean b) {
        view = inflater.inflate(R.layout.fragment_tab_my_approval, null);
        isPrepared = true;
        return view;
    }

    @Override
    protected void initView(Bundle savedInstanceState) {
        initFragments();
        vpAll.setAdapter(new TabFragmentAdapter(fragments, strings, getSupportFragmentManager(), getActivity()));
        tabLayout.setupWithViewPager(vpAll);
        vpAll.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                // 将滑动偏移量传给Indicator
                tabLayout.redrawIndicator(position, positionOffset);
            }

            @Override
            public void onPageSelected(int position) {
            }

            @Override
            public void onPageScrollStateChanged(int i) {

            }
        });

    }

    private void initFragments() {
        for (String tabTitle : tabTitles) {
            ShowApprovalFragment fragment = new ShowApprovalFragment();
            fragments.add(fragment);
            strings.add(tabTitle);
        }
    }

    @Override
    protected void lazyLoad() {
        if (!isPrepared || !isVisible) {
            return;
        }
    }
}

④用的的viewPager

/**
 * ================================================
 *
 * @author:vip 版    本:V 1.0.0
 * 创建日期:2019/06/12
 * 描    述:Tab控件采用的适配器(防止卡顿)
 * 修订历史:
 * ================================================
 */
public class TabFragmentAdapter extends FragmentPagerAdapter {
    private Context context;
    private List<Fragment> fragments;
    private List<String> strings;

    public TabFragmentAdapter(List<Fragment> fragments, List<String> strings, FragmentManager fragmentManager, Context context) {
        super(fragmentManager);
        this.strings = strings;
        this.context = context;
        this.fragments = fragments;
    }

    @Override
    public Fragment getItem(int position) {
        return fragments.get(position);
    }

    @Override
    public int getCount() {
        return strings.size();
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return strings.get(position);
    }

    /**
     * 重写该方法,取消调用父类该方法 * 可以避免在viewpager切换
     * fragment不可见时执行到onDestroyView,可见时又从onCreateView重新加载视图
     * * 因为父类的destroyItem方法中会调用detach方法,将fragment与view分离,
     * (detach()->onPause()->onStop()->onDestroyView())
     * 然后在instantiateItem方法中又调用attach方法,此方法里判断如果fragment与view分离了,
     ** 那就重新执行onCreateView,再次将view与fragment绑定(attach()->onCreateView()->onActivityCreated()->onStart()->onResume()) *
     */
    @Override
    public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
        // super.destroyItem(container, position, object); }

    }
}

 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------

方法二:原始常用的XTabLayout

①引入依赖

implementation 'com.androidkun:XTabLayout:1.1.3'

②引入布局

<!--有数据-->
<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_below="@+id/include_top_base"
    tools:ignore="UselessParent">
    <!--标签-->
    <com.androidkun.xtablayout.XTabLayout
        android:id="@+id/tab_layout"
        android:layout_width="match_parent"
        android:layout_height="@dimen/ds_42dp"
        android:background="@color/white"
        app:tabBackground="@null"
        app:xTabDividerWidthWidthText="false"
        app:xTabIndicatorColor="@color/load_red"
        app:xTabSelectedTextColor="@color/load_red"
        app:xTabSelectedTextSize="14sp"
        app:xTabTextBold="false"
        app:xTabTextColor="@color/cs_727272"
        app:xTabTextSelectedBold="true"
        app:xTabTextSize="@dimen/ds_12sp"
        tools:ignore="RtlHardcoded" />
    <View
        android:id="@+id/view_line"
        style="@style/App_RootView_H"
        android:layout_below="@+id/tab_layout" />

    <com.yc.stscf.widget.TabViewPager
        android:id="@+id/vp_all"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/view_line"
        android:layout_marginTop="@dimen/ds_10dp" />
</RelativeLayout>

 

③ 代码部分

/**
 * ================================================
 *
 * @author :Vip
 * @version :V 1.0.0
 * @date :2019/6/12 9:31
 * 描    述:我的申请
 * 修订历史:
 * ================================================
 */

public class MyTabApplyFragment extends BaseFragment {

    @BindView(R.id.iv_back)
    ImageView ivBack;
    @BindView(R.id.tv_tittle)
    TextView tvTittle;
    @BindView(R.id.iv_triangle_white)
    ImageView ivTriangleWhite;
    @BindView(R.id.rl_title_all)
    RelativeLayout rlTitleAll;
    @BindView(R.id.tv_base_some)
    TextView tvBaseSome;
    @BindView(R.id.iv_white_search)
    ImageButton ivWhiteSearch;
    @BindView(R.id.tv_add)
    TextView tvAdd;
    @BindView(R.id.tv_commit)
    TextView tvCommit;
    @BindView(R.id.tab_layout)
    XTabLayout tabLayout;
    @BindView(R.id.view_line)
    View viewLine;
    @BindView(R.id.vp_all)
    TabViewPager vpAll;
    /**
     * 总布局
     **/
    private View view = null;
    /**
     * 标志位,标志已经初始化完成
     **/
    private boolean isPrepared;

    @SuppressLint("InflateParams")
    @Override
    protected View initLayout(LayoutInflater inflater, ViewGroup container, boolean b) {
        view = inflater.inflate(R.layout.fragment_tab_my_apply, null);
        isPrepared = true;
        return view;
    }

    @Override
    protected void initView(Bundle savedInstanceState) {
        ivBack.setVisibility(View.GONE);
        tvTittle.setText("全部申请");
        //系统默认
        tabLayout.setTabMode(TabLayout.MODE_FIXED);
        //添加完所有tab后调用!!
        final List<String> tabList = new ArrayList<>();
        tabList.clear();
        tabList.add("未完成");
        tabList.add("已完成");
        tabLayout.removeAllTabs();
        for (int i = 0; i < tabList.size(); i++) {
            tabLayout.addTab(tabLayout.newTab().setText(tabList.get(i)));
        }
        List<Fragment> fragments = new ArrayList<Fragment>();
        for (int i = 0; i < tabList.size(); i++) {
            Fragment fragment = new ShowApprovalFragment();
            Bundle bundle = new Bundle();
            bundle.putString("text", tabList.get(i));
            fragment.setArguments(bundle);
            fragments.add(fragment);
        }
        vpAll.setAdapter(new TabFragmentAdapter(fragments, tabList, getSupportFragmentManager(), getActivity()));
        tabLayout.setupWithViewPager(vpAll);
        tabLayout.setTabTextColors(getResources().getColor(R.color.cs_999999), getResources().getColor(R.color.cs_F88441));
        //点击
        tabLayout.setOnTabSelectedListener(new XTabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(XTabLayout.Tab tab) {
                Tt.showShort(mContext, tab.getPosition() + "点击的页");
                vpAll.setCurrentItem(tab.getPosition());

            }

            @Override
            public void onTabUnselected(XTabLayout.Tab tab) {

            }

            @Override
            public void onTabReselected(XTabLayout.Tab tab) {

            }
        });
        vpAll.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int i, float v, int i1) {

            }

            @Override
            public void onPageSelected(int position) {
//                Tt.showShort(mContext, position + "滑动的页");
            }

            @Override
            public void onPageScrollStateChanged(int i) {

            }
        });
    }


    @Override
    protected void lazyLoad() {
        if (!isPrepared || !isVisible) {
            return;
        }
    }

} 

总结:

没什么好总结的了,这俩都挺好的,方法一能有效的解决以图片为指示器的效果,美工提供好图片,比如三角形,或者是圆点,再或者是如图我展示的渐变图片,不需要使用点9图片,也可以通过算法进行自行拉伸。我觉得是很好用。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

土狗的想法

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值