二、TabLayout自定义图片指示器
最近项目需求,多个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自定义图片指示器相关推荐
- TabLayout自定义指示器及样式
一,自定义指示器下标 效果图如下: 1,新建一个名为:layer_tab_indicator的layer-list文件,然后定义想要的样式,其中bitmap 设置成需要的图片格式,也可以根据需求在it ...
- Android自定义ViewPager图片指示器,兼容实现底部横线指示器
前言 记得以前自己使用过的ViewPager Indicator有JakeWharton大神的开源库ViewPagerIndicator,v4包自带的PagerTitleStrip以及Android ...
- 安卓Tablayout自定义文字、指示器长度和颜色
安卓Tablayout自定义文字.指示器长度和颜色 废话不多说,先上效果图.没有效果图的文章都是扯淡: 安卓Tablayout自定义文字.指示器长度和颜色 新的改变 以上就是所有的代码 附上demo源 ...
- (简单详细)uniapp实现自定义海报内容并生成海报二维码图片(可拖拽,可调节大小)
实现效果 应用场景 公司遇到一个需要实现自定义海报才可以满足客户需求的问题,实现自定义海报内容,同时上传的二维码可以自动调节,需要用到canvans的知识,如果没有,那么可以直接使用我的这个案例即可 ...
- vue使用qrcodejs2生成带log的二维码图片,vue生成二维码图片中间带log,自定义log
安装插件 npm install qrcodejs2 --save 在页面中引入 import QRcode from 'qrcodejs2' 普通的二维码 此处的id就是页面中要展示二维码容器的id ...
- Android绘图机制(二)——自定义View绘制形, 圆形, 三角形, 扇形, 椭圆, 曲线,文字和图片的坐标讲解
Android绘图机制(二)--自定义View绘制形, 圆形, 三角形, 扇形, 椭圆, 曲线,文字和图片的坐标讲解 我们要想画好一些炫酷的View,首先我们得知道怎么去画一些基础的图案,比如矩形,圆 ...
- Java渐变进度条_Android ProgressBar自定义图片进度,自定义渐变色进度条
java.lang.Object ↳android.view.View ↳android.widget.ProgressBar 直接子类 AbsSeekBar 间接子类 RatingBar, Seek ...
- 自定义图片字段调用的问题出现{dede:img ..}
要解决这个问题,我们必须得创建一个自定义函数,其实现方式为: 一.实现方法1)创建自定义函数 打开 /include/extend.func.php 文件(注:这个文件就是系统预留的自定义函数接口文件 ...
- 织梦自定义图片字段和缩略图一样_DedeCMS系统自定义字段的图片调用
实现方法及步骤 1)创建自定义函数 打开 /include/extend.func.php 文件(注:这个文件就是织梦系统预留的自定义函数接口文件,主要用于二次开发用的.如果你是老版本,默认没有这个文 ...
最新文章
- asp.net实现在网页上自动显示超链接以及Email地址
- Python的C/C++扩展
- 机器人编程与python语言的区别_儿童编程和机器人编程有啥区别?
- 佰腾科技:专利大数据的云上裂变之路
- 利用对象存储多种方式 保障OSS数据安全
- 在Altium Designer中利用阵列粘贴功能快速绘制元器件封装
- shell md5sum
- 360浏览器下载|360安全浏览器下载
- python中ttk和tkinter_Python Tkinter ttk组件及用法(附带实例)
- 利用支付宝短信服务接口 实现手机号 验证码登录Demo
- 币圈投资必败的5种“韭菜”人格
- UVALive4987(dp+贪心)
- altium designer 绘制pcb时如何检查漏线
- CentOS6 安装mist.io
- 什么是SaaS平台?SaaS软件平台有什么优势
- MSP-EXP430F5529LP_GPIO
- linux最大文件名,linux和windows文件名长度限制
- 文件路径问题解决方案
- 计算机学院教师老带新总结,教师“以老带新”工作总结
- 什么是系统的可扩展性?
热门文章
- 首先实现立即执行轮询函数,然后setInterval再间隔执行轮询函数,实现方法
- Android11对比IOS14,iPhone11升级至iOS14,对比苹果iOS13,迎来3大新变化
- python求梯形面积_pythonocc 求一条直线与一个梯形的交点的横坐标
- 凸优化第三章凸函数 3.1基本性质和例子
- UOJ224/洛谷P1737 【NOI2016】旷野大计算 造计算机
- 单片机右移c语言程序,51单片机+点阵8*8上、下、左、右移显示C程序(原创)
- AI开源的硬核战场:领军者百度如何亮剑?
- javascript国际化_如何在JavaScript中实现国际化(i18n)
- ofo 共享单车的问题
- vue ui创建项目 连接断开(errno:-4058,syscall: ‘scandir‘,code:’ ENOENT’,path: ‘C: ....../locales)