话不多说,先看图
这个采用的是
这个采用的是渐变的图片,TabLayout采用的是自定义的。
-----------------------------------------------------------------------------------------------
这个采用的是纯色color,TabLayout采用的是 implementation 'com.androidkun:XTabLayout:1.1.3'
-----------------------------------------------------------------------------------------------
对比。二者都可以达到切换字体方法,点击或者滑动切换,指示器均可以含有动画的移动过渡。
下面贴一下用法。
①采用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文件下,设置这个自定义控件的一个属性。设置默认数量,方便在你布局引用的地方,提前设置你想显示几个。
②布局引用:
③在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
strings = new ArrayList (); private List 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
fragments; private List strings; public TabFragmentAdapter(List fragments, List 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); } } }
------------------------------------------------------------------------------------------------------------------------------------------------------------------------
①引入依赖
implementation 'com.androidkun:XTabLayout:1.1.3'
②引入布局
③ 代码部分
/** * ================================================ * * @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
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 fragments = new ArrayList (); 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图片,也可以通过算法进行自行拉伸。我觉得是很好用。