最近项目需求,多个tab切换显示不同的页面,但是tab的下划线是一个带有圆角阴影的下划线,看过Tablayout源码的小伙伴可能会知道,通过原生的TabLayout是无法实现的,想了解的可以看我的另一篇文章:https://blog.csdn.net/weixin_41882065/article/details/89352460

刚开始参考了几位大佬的方法:

1、Android TabLayout的Indicator如何设置为图片

https://www.jianshu.com/p/0eb4e09b3944

第一种方法经过实线,发现当tab较多,超出屏幕范围,需要滑动的时候,指示器的位置就会出错;

2、可自定义图片指示器并支持自定义Tab宽度的TabLayout

https://blog.csdn.net/qq_27258799/article/details/78413926

第二种方法,大佬把每个tab的宽度固定死了,这样如果每个tab的文字数量不一样的话,显示效果就会比较差。

所以综合上面两种方法,我的解决办法是:

1、自己写一个View,继承TabLayout,然后重写dispatchDraw方法,绘制图片,然后根据源码里面指示器的处理,放在我新绘制的图片这里,就OK。

下面贴出代码:

public class SlidingTabLayout extends TabLayout {private static final String TAG = "SlidingTabLayout";/*** 指示器左边坐标*/private float mIndicatorLeft = -1;/*** 指示器右边坐标*/private int mIndicatorRight = -1;/*** 选中tab的位置*/private int mSelectedPosition = -1;/*** 选中tab的偏移量*/private float mSelectionOffset;// private LinearLayout mTabStrip;private Paint mSelectedIndicatorPaint = new Paint();/*** 自定义指示器*/private Bitmap mSlideIcon;/*** 指示器初始X偏移量*/private int mInitTranslationX;/*** 指示器初始Y偏移量*/private int mInitTranslationY;public SlidingTabLayout(Context context) {super(context);}public SlidingTabLayout(Context context, AttributeSet attrs) {super(context, attrs);this.mSlideIcon = BitmapFactory.decodeResource(getResources(), R.mipmap.m_guide_tab_video_service_selected);this.mInitTranslationY = (getBottom() - getTop() - this.mSlideIcon.getHeight());}public void setIndicatorPositionFromTabPosition(int position, float positionOffset) {mSelectedPosition = position;mSelectionOffset = positionOffset;updateIndicatorPosition();}/*** 计算滑动杆位置*/private void updateIndicatorPosition() {LinearLayout mTabStrip = getTabStrip();if (mTabStrip == null) {return;}final View selectedTitle = mTabStrip.getChildAt(mSelectedPosition);int left, right;if (selectedTitle != null && selectedTitle.getWidth() > 0) {left = selectedTitle.getLeft();right = selectedTitle.getRight();if (mSelectionOffset > 0f && mSelectedPosition < mTabStrip.getChildCount() - 1) {View nextTitle = mTabStrip.getChildAt(mSelectedPosition + 1);left = (int) (mSelectionOffset * nextTitle.getLeft() +(1.0f - mSelectionOffset) * left);right = (int) (mSelectionOffset * nextTitle.getRight() +(1.0f - mSelectionOffset) * right);}} else {left = right = -1;}setIndicatorPosition(left, right);}void setIndicatorPosition(int left, int right) {if (left != mIndicatorLeft || right != mIndicatorRight) {mIndicatorLeft = left;mIndicatorRight = right;/*通知view重绘*/ViewCompat.postInvalidateOnAnimation(this);}}/*** 绘制指示器*/@Overrideprotected void dispatchDraw(Canvas canvas) {if (mSlideIcon == null) {return;}//绘制指示器canvas.save();if (mIndicatorLeft >= 0 && mIndicatorRight > mIndicatorLeft) {// 平移到正确的位置,修正tabs的平移量canvas.translate(mIndicatorLeft, getBottom() - getTop() - this.mSlideIcon.getHeight());Matrix matrix = new Matrix();//设置指示器的长度与tab文字长度相同matrix.postScale((mIndicatorRight - mIndicatorLeft) / mSlideIcon.getWidth(), 1);canvas.drawBitmap(mSlideIcon, matrix, mSelectedIndicatorPaint);}canvas.restore();super.dispatchDraw(canvas);}/*** tab的父容器,注意空指针*/@Nullablepublic LinearLayout getTabStrip() {Class<?> tabLayout = TabLayout.class;Field tabStrip = null;try {//这里是通过反射的获取SlidingTabStrip实例对象,不同的api,这里映射的方法名可能不一样tabStrip = tabLayout.getDeclaredField("mTabStrip");// API 28// tabStrip = tabLayout.getDeclaredField("slidingTabIndicator");} catch (NoSuchFieldException e) {LogUtils.e(TAG, "NoSuchFieldException of mTabStrip", e);}LinearLayout mTabStripLLayout = null;if (tabStrip != null) {tabStrip.setAccessible(true);try {mTabStripLLayout = (LinearLayout) tabStrip.get(this);if (mTabStripLLayout != null) {mTabStripLLayout.setClipChildren(false);}} catch (IllegalAccessException e) {LogUtils.e(TAG, "IllegalAccessException", e);}}return mTabStripLLayout;}}

布局配置:

 <com.guahao.android.wyt.moduleguide.videoservice.widget.SlidingTabLayoutandroid:id="@+id/m_guide_fragment_video_service_tl"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_gravity="start"android:paddingTop="@dimen/m_guide_20dp"android:paddingBottom="@dimen/m_guide_10dp"app:tabIndicatorColor="@color/m_guide_23CBD6"app:tabIndicatorHeight="@dimen/m_guide_0dp"app:tabMode="scrollable"app:tabSelectedTextColor="@color/m_guide_23CBD6"app:tabTextAppearance="@style/TabLayoutTextAppearance"app:tabTextColor="@color/m_guide_9AA5BB"app:tabMaxWidth="@dimen/m_guide_200dp"app:tabMinWidth="@dimen/m_guide_20dp"app:tabPaddingStart="@dimen/m_guide_20dp"app:tabPaddingEnd="@dimen/m_guide_20dp"/>

代码中的使用,这里主要是设置PageChangeListener监听,然后在onPageScrolled方法中将移动位置和移动偏移量传递给SliddingTabLayout。

 @Overridepublic void onViewCreated(View view, Bundle savedInstanceState) {super.onViewCreated(view, savedInstanceState);mViewPager = bindView(R.id.m_fragment_vp);mTabLayout = bindView(R.id.m_fragment_tl);....//将tabLayout与viewPager关联起来mTabLayout.setupWithViewPager(mViewPager, true);mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(mTabLayout) {@Overridepublic void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {super.onPageScrolled(position, positionOffset, positionOffsetPixels);//关键点mTabLayout.setIndicatorPositionFromTabPosition(position, positionOffset);}@Overridepublic void onPageScrollStateChanged(int state) {super.onPageScrollStateChanged(state);}});.....}

到这里就结束了,

注意点:

2、代码中将图片写死了,如果想替换图片的话将SliddingTabLayout中mSlideIcon的值改成自己的就可以了,或者自己添加一个设置图片的方法也可以的。

3、     这里tabStrip = tabLayout.getDeclaredField("mTabStrip");如果获取不到的话,请用下面的这句
            // API 28
            // tabStrip = tabLayout.getDeclaredField("slidingTabIndicator");

因为不同的API可能会有不同

其它就没有什么,比较简单,大部分的计算都是从源码中拷过来的,如果读者有什么问题欢迎来提问?

二、TabLayout自定义图片指示器相关推荐

  1. TabLayout自定义指示器及样式

    一,自定义指示器下标 效果图如下: 1,新建一个名为:layer_tab_indicator的layer-list文件,然后定义想要的样式,其中bitmap 设置成需要的图片格式,也可以根据需求在it ...

  2. Android自定义ViewPager图片指示器,兼容实现底部横线指示器

    前言  记得以前自己使用过的ViewPager Indicator有JakeWharton大神的开源库ViewPagerIndicator,v4包自带的PagerTitleStrip以及Android ...

  3. 安卓Tablayout自定义文字、指示器长度和颜色

    安卓Tablayout自定义文字.指示器长度和颜色 废话不多说,先上效果图.没有效果图的文章都是扯淡: 安卓Tablayout自定义文字.指示器长度和颜色 新的改变 以上就是所有的代码 附上demo源 ...

  4. (简单详细)uniapp实现自定义海报内容并生成海报二维码图片(可拖拽,可调节大小)

    实现效果 应用场景 公司遇到一个需要实现自定义海报才可以满足客户需求的问题,实现自定义海报内容,同时上传的二维码可以自动调节,需要用到canvans的知识,如果没有,那么可以直接使用我的这个案例即可 ...

  5. vue使用qrcodejs2生成带log的二维码图片,vue生成二维码图片中间带log,自定义log

    安装插件 npm install qrcodejs2 --save 在页面中引入 import QRcode from 'qrcodejs2' 普通的二维码 此处的id就是页面中要展示二维码容器的id ...

  6. Android绘图机制(二)——自定义View绘制形, 圆形, 三角形, 扇形, 椭圆, 曲线,文字和图片的坐标讲解

    Android绘图机制(二)--自定义View绘制形, 圆形, 三角形, 扇形, 椭圆, 曲线,文字和图片的坐标讲解 我们要想画好一些炫酷的View,首先我们得知道怎么去画一些基础的图案,比如矩形,圆 ...

  7. Java渐变进度条_Android ProgressBar自定义图片进度,自定义渐变色进度条

    java.lang.Object ↳android.view.View ↳android.widget.ProgressBar 直接子类 AbsSeekBar 间接子类 RatingBar, Seek ...

  8. 自定义图片字段调用的问题出现{dede:img ..}

    要解决这个问题,我们必须得创建一个自定义函数,其实现方式为: 一.实现方法1)创建自定义函数 打开 /include/extend.func.php 文件(注:这个文件就是系统预留的自定义函数接口文件 ...

  9. 织梦自定义图片字段和缩略图一样_DedeCMS系统自定义字段的图片调用

    实现方法及步骤 1)创建自定义函数 打开 /include/extend.func.php 文件(注:这个文件就是织梦系统预留的自定义函数接口文件,主要用于二次开发用的.如果你是老版本,默认没有这个文 ...

最新文章

  1. asp.net实现在网页上自动显示超链接以及Email地址
  2. Python的C/C++扩展
  3. 机器人编程与python语言的区别_儿童编程和机器人编程有啥区别?
  4. 佰腾科技:专利大数据的云上裂变之路
  5. 利用对象存储多种方式 保障OSS数据安全
  6. 在Altium Designer中利用阵列粘贴功能快速绘制元器件封装
  7. shell md5sum
  8. 360浏览器下载|360安全浏览器下载
  9. python中ttk和tkinter_Python Tkinter ttk组件及用法(附带实例)
  10. 利用支付宝短信服务接口 实现手机号 验证码登录Demo
  11. 币圈投资必败的5种“韭菜”人格
  12. UVALive4987(dp+贪心)
  13. altium designer 绘制pcb时如何检查漏线
  14. CentOS6 安装mist.io
  15. 什么是SaaS平台?SaaS软件平台有什么优势
  16. MSP-EXP430F5529LP_GPIO
  17. linux最大文件名,linux和windows文件名长度限制
  18. 文件路径问题解决方案
  19. 计算机学院教师老带新总结,教师“以老带新”工作总结
  20. 什么是系统的可扩展性?

热门文章

  1. 首先实现立即执行轮询函数,然后setInterval再间隔执行轮询函数,实现方法
  2. Android11对比IOS14,iPhone11升级至iOS14,对比苹果iOS13,迎来3大新变化
  3. python求梯形面积_pythonocc 求一条直线与一个梯形的交点的横坐标
  4. 凸优化第三章凸函数 3.1基本性质和例子
  5. UOJ224/洛谷P1737 【NOI2016】旷野大计算 造计算机
  6. 单片机右移c语言程序,51单片机+点阵8*8上、下、左、右移显示C程序(原创)
  7. AI开源的硬核战场:领军者百度如何亮剑?
  8. javascript国际化_如何在JavaScript中实现国际化(i18n)
  9. ofo 共享单车的问题
  10. vue ui创建项目 连接断开(errno:-4058,syscall: ‘scandir‘,code:’ ENOENT’,path: ‘C: ....../locales)