前言

系统自带的Tablayout用的也不错但是有些功能还不能满足我们这边开发,所以我这边自定义了一个tablayout提供了自定义tab线的长度以及,移动速度,以及禁止某个滑动(tablayout基本功能也提供了)

效果图

QQ20170327-165412-HD(1).gif

实现步骤

  • 构造方法添加子控件

添加一些xml定义的属性

    public MyIndicator(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);this.setGravity(Gravity.CENTER_VERTICAL);this.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.Indicator, 0, 0);mColor = array.getColor(R.styleable.Indicator_indicatorColor, Color.RED);mList = getContext().getResources().getStringArray(array.getResourceId(R.styleable.Indicator_array, 0));mTextNomal = array.getInteger(R.styleable.Indicator_text_nomal_size, 12);mTextPress = array.getInteger(R.styleable.Indicator_text_press_size, 13);mText_Nomal = array.getColor(R.styleable.Indicator_text_nomal_color, Color.GRAY);mText_Press = array.getColor(R.styleable.Indicator_text_press_color, Color.BLACK);mSelected = array.getInteger(R.styleable.Indicator_selected, 0);isFull = array.getBoolean(R.styleable.Indicator_isFull, false);mAnimationTime = array.getInteger(R.styleable.Indicator_speed, 300);mBai = array.getFloat(R.styleable.Indicator_multiply, (float) 1.2);mHeight = array.getInteger(R.styleable.Indicator_line_hegith, 5);for (int i = 0; i < mList.length; i++) {mListTitle.add(mList[i]);}array.recycle();}
  • onLayout初始化布局

添加控件

 @Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {super.onLayout(changed, l, t, r, b);if (!mIsCheck) {mIsCheck = true;initView();}}

添加textview以及线

/*** 初始化布局*/private void initView() {measure(0, 0);//获取每个textview布局所占的宽度mContWidth = getWidth() / mListTitle.size();//添加线mLine = new View(getContext());addView(mLine);int mWeight;if (isFull) {mWeight = mContWidth;} else {mWeight = (int) (setLineLength(mListTitle.get(mSelected)) * mBai);if (mWeight > mContWidth) {mWeight = mContWidth;}}//设置线的基本属性LayoutParams mLayoutParams1 = new LayoutParams(mWeight, mHeight);mLayoutParams1.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);mLine.setLayoutParams(mLayoutParams1);mLine.setBackgroundColor(mColor);//获取上一次所在位置mEndAddress = mContWidth * mSelected + (mContWidth - mWeight) / 2;//添加textviewfor (int i = 0; i < mListTitle.size(); i++) {addTextView(i);}//初始化点击事件setListener();}
 /*** 添加textview*/private void addTextView(int i) {//初始化textviewTextView textView = new TextView(getContext());textView.setText(mListTitle.get(i));//设置textview基本属性LayoutParams mLayoutParams = new LayoutParams(mContWidth, LayoutParams.MATCH_PARENT);mLayoutParams.leftMargin = mContWidth * i;mLayoutParams.addRule(CENTER_VERTICAL);textView.setLayoutParams(mLayoutParams);textView.setGravity(Gravity.CENTER);if (i == mSelected) {textView.setTextColor(mText_Press);textView.setTextSize(mTextPress);} else {textView.setTextColor(mText_Nomal);textView.setTextSize(mTextNomal);}//添加textview到布局mTextList.add(textView);addView(textView);}
  • 动画

动画就简单了直接一个移动动画就好了

 /*** 动画** @param statX 开始位置* @param endX  结束位置*/private void setAnimation(int statX, int endX) {AnimationSet mSet = new AnimationSet(true);TranslateAnimation translate1 = new TranslateAnimation(statX, endX, 0, 0);mSet.addAnimation(translate1);mSet.setFillAfter(true);mSet.setDuration(mAnimationTime);mLine.startAnimation(mSet);}
  • 修改下标位置

计算修改下标的位置

 /*** 改变下标** @param position*/public void setChanger(int position) {//改为默认字体颜色修改选中字体颜色resetColor();mTextList.get(position).setTextColor(mText_Press);mTextList.get(position).setTextSize(mTextPress);mSelected = position;int mWeight;if (isFull) {mWeight = mContWidth;} else {mWeight = (int) (setLineLength(mListTitle.get(mSelected)) * mBai);if (mWeight > mContWidth) {mWeight = mContWidth;}}/*** 计算当前选择textview的X点位置*/int way = mContWidth * mSelected + (mContWidth - mWeight) / 2;LayoutParams mLayoutParams = new LayoutParams(mWeight, mHeight);mLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);mLine.setLayoutParams(mLayoutParams);setAnimation(mEndAddress, way);mEndAddress = way;this.mNowPosition = position;}
  • XML部分属性

线的颜色 : indicatorColor (默认red)
textview显示数组 :array
字体默认颜色:text_nomal_color (默认gray)
字体选中颜色:text_press_color (默认black)
字体默认大小:text_press_color (默认12)
字体选中大小:text_press_size (默认13)
默认选中:selected (默认0)
线是否铺满:isFull (默认false)
移动速度:speed (默认300)
线是字体的倍数:multiply (默认1.2)
线的高度: multiply (默认5)

<declare-styleable name="Indicator"><attr name="indicatorColor" format="color"/><attr name="array" format="integer"/><attr name="text_nomal_color" format="color"/><attr name="text_press_color" format="color"/><attr name="text_nomal_size" format="integer"/><attr name="text_press_size" format="integer"/><attr name="selected" format="integer"/><attr name="isFull" format="boolean"/><attr name="speed" format="integer"/><attr name="multiply" format="float"/><attr name="line_hegith" format="integer"/></declare-styleable>

自定义控件代码献上

  • JAVA代码
/*** Created by huangbo on 17/1/22.* 指示器*/public class MyIndicator extends RelativeLayout {/*** 线的颜色*/private int mColor;/*** 线的高度*/private int mHeight;/*** xml数组*/private String[] mList;/*** textview数组*/private List<TextView> mTextList = new ArrayList<>();/*** string数组*/private List<String> mListTitle = new ArrayList<>();/*** 默认字体大小*/private int mTextNomal;/*** 被选择字体大小*/private int mTextPress;/*** 默认字体颜色*/private int mText_Nomal;/*** 被选择的颜色*/private int mText_Press;/*** 每个格子个长度*/private int mContWidth;/*** 被选择的tab*/private int mSelected;/*** 底线*/private View mLine;/*** 是否或去过*/private boolean mIsCheck;/*** 字体的多少倍*/private float mBai;/*** 记录移动结束位置*/private int mEndAddress;/*** 禁止滑动表情下标*/private int mProhibitPisition = -1;/*** 动画时间*/private int mAnimationTime;/*** 当前选中*/private int mNowPosition;/*** 是否铺满*/private boolean isFull;public MyIndicator(Context context) {this(context, null);}public MyIndicator(Context context, AttributeSet attrs) {this(context, attrs, 0);}public MyIndicator(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);this.setGravity(Gravity.CENTER_VERTICAL);this.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.Indicator, 0, 0);mColor = array.getColor(R.styleable.Indicator_indicatorColor, Color.RED);mList = getContext().getResources().getStringArray(array.getResourceId(R.styleable.Indicator_array, 0));mTextNomal = array.getInteger(R.styleable.Indicator_text_nomal_size, 12);mTextPress = array.getInteger(R.styleable.Indicator_text_press_size, 13);mText_Nomal = array.getColor(R.styleable.Indicator_text_nomal_color, Color.GRAY);mText_Press = array.getColor(R.styleable.Indicator_text_press_color, Color.BLACK);mSelected = array.getInteger(R.styleable.Indicator_selected, 0);isFull = array.getBoolean(R.styleable.Indicator_isFull, false);mAnimationTime = array.getInteger(R.styleable.Indicator_speed, 300);mBai = array.getFloat(R.styleable.Indicator_multiply, (float) 1.2);mHeight = array.getInteger(R.styleable.Indicator_line_hegith, 5);for (int i = 0; i < mList.length; i++) {mListTitle.add(mList[i]);}array.recycle();}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {super.onLayout(changed, l, t, r, b);if (!mIsCheck) {mIsCheck = true;initView();}}/*** 初始化布局*/private void initView() {measure(0, 0);//获取每个textview布局所占的宽度mContWidth = getWidth() / mListTitle.size();//添加线mLine = new View(getContext());addView(mLine);int mWeight;if (isFull) {mWeight = mContWidth;} else {mWeight = (int) (setLineLength(mListTitle.get(mSelected)) * mBai);if (mWeight > mContWidth) {mWeight = mContWidth;}}//设置线的基本属性LayoutParams mLayoutParams1 = new LayoutParams(mWeight, mHeight);mLayoutParams1.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);mLine.setLayoutParams(mLayoutParams1);mLine.setBackgroundColor(mColor);//获取上一次所在位置mEndAddress = mContWidth * mSelected + (mContWidth - mWeight) / 2;//添加textviewfor (int i = 0; i < mListTitle.size(); i++) {addTextView(i);}//初始化点击事件setListener();}/*** 添加textview*/private void addTextView(int i) {//初始化textviewTextView textView = new TextView(getContext());textView.setText(mListTitle.get(i));//设置textview基本属性LayoutParams mLayoutParams = new LayoutParams(mContWidth, LayoutParams.MATCH_PARENT);mLayoutParams.leftMargin = mContWidth * i;mLayoutParams.addRule(CENTER_VERTICAL);textView.setLayoutParams(mLayoutParams);textView.setGravity(Gravity.CENTER);if (i == mSelected) {textView.setTextColor(mText_Press);textView.setTextSize(mTextPress);} else {textView.setTextColor(mText_Nomal);textView.setTextSize(mTextNomal);}//添加textview到布局mTextList.add(textView);addView(textView);}/*** 清空字体颜色*/private void resetColor() {for (int i = 0; i < mTextList.size(); i++) {mTextList.get(i).setTextColor(getContext().getResources().getColor(R.color.text_hint));}}/*** 点击tab事件*/private void setListener() {setAnimation(0, mEndAddress);for (int i = 0; i < mTextList.size(); i++) {final int finalI = i;mTextList.get(i).setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {if (finalI != mSelected && mProhibitPisition != finalI) {setChanger(finalI);}if (mOnIndiacatorClickListener != null)mOnIndiacatorClickListener.onClick(finalI, v);}});}}/*** 动画** @param statX 开始位置* @param endX  结束位置*/private void setAnimation(int statX, int endX) {AnimationSet mSet = new AnimationSet(true);TranslateAnimation translate1 = new TranslateAnimation(statX, endX, 0, 0);mSet.addAnimation(translate1);mSet.setFillAfter(true);mSet.setDuration(mAnimationTime);mLine.startAnimation(mSet);}private OnIndiacatorClickListener mOnIndiacatorClickListener;/*** 计算下划线长度*/private int setLineLength(String mTextView) {return ConvertUtils.dp2px(mTextView.length() * mTextPress);}/*** 添加页面** @param charSequence*/public void add(CharSequence charSequence, int position) {removeAllViews();mTextList.clear();if (mListTitle.size() == position)mListTitle.set(position - 1, charSequence.toString());elsemListTitle.add(charSequence.toString());initView();}/*** 设置是否铺满*/public void setFull() {isFull = true;}/*** 设置监听** @param onIndiacatorClickListener*/public void setIndiacatorListener(OnIndiacatorClickListener onIndiacatorClickListener) {if (onIndiacatorClickListener != null) {this.mOnIndiacatorClickListener = onIndiacatorClickListener;}}/*** 设置禁止滑动页面** @param i*/public void setProhibitPositio(int i) {this.mProhibitPisition = i;}/*** 设置动画时间*/public void setAnimationTime(int time) {this.mAnimationTime = time;}/*** 外部监听*/public interface OnIndiacatorClickListener {void onClick(int position, View view);}/*** 改变下标** @param position*/public void setChanger(int position) {//改为默认字体颜色修改选中字体颜色resetColor();mTextList.get(position).setTextColor(mText_Press);mTextList.get(position).setTextSize(mTextPress);mSelected = position;int mWeight;if (isFull) {mWeight = mContWidth;} else {mWeight = (int) (setLineLength(mListTitle.get(mSelected)) * mBai);if (mWeight > mContWidth) {mWeight = mContWidth;}}/*** 计算当前选择textview的X点位置*/int way = mContWidth * mSelected + (mContWidth - mWeight) / 2;LayoutParams mLayoutParams = new LayoutParams(mWeight, mHeight);mLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);mLine.setLayoutParams(mLayoutParams);setAnimation(mEndAddress, way);mEndAddress = way;this.mNowPosition = position;}/*** 获取当前下标*/public int getPosition() {return mNowPosition;}}
  • XML基本使用代码
<demo.com.androiddemo.MyIndicatorandroid:id="@+id/my"android:layout_width="match_parent"android:layout_height="50dp"app:array="@array/tabs"app:indicatorColor="@color/btn_red"app:selected="0"app:text_nomal_color="@color/text_hint"app:text_nomal_size="12"app:text_press_color="@color/text_title"app:text_press_size="13"></demo.com.androiddemo.MyIndicator>

结语

客官看完肯定觉得非常简单,每个人的思路不一样实现的方式也有很多,如果觉得我的实现方式有问题或者好的实现方式可以给我留言,当然如果有什么特殊需求的话也可以留言给我,我帮你们提供相关需求,以后还会继续更新相关博客希望各位给一个支持

地址

项目github地址:GitHub

依赖

 compile 'com.github.q1104133609:MyTabLayout:v0.0.1'

自定义TabLayout相关推荐

  1. 一个工具类实现自定义Tablayout的下划线宽度

    ** 只改变Tablayout的下划线的宽度,只需要一个工具类就可以可满足** 1.写个工具类 封装: /*** @author FX* @date 2018/07/19 11:11* @fuctio ...

  2. Android 自定义TabLayout

    默认的TabLayout是没有花里胡哨的功能的,比如说我们可能希望它有边框,或者有背景颜色,或者外边框.因此就需要更改一些属性,或者在代码中实现.比如下图这种带边框,字体改变. 实现思路: tabla ...

  3. 自定义TabLayout的下划线的长度

    tablayout自定义导航线的长度的问题,我见网上有两个解决方案,我用到我的项目中都没效果,自己总结了一个方案: 一:如果你的项目中没有滑动的动画需求你可以自定义tablayout'的item,自然 ...

  4. android tablayout 自定义,TabLayout的自定义

    TabLayout的自定义,主要是通过setCustomView方法来添加自定义布局实现. 自定义TabLayout的实现主要包含以下几个步骤 ●创建自定义布局(这里我加了一个动画控件,可以替换成其他 ...

  5. android tablayout 自定义,TabLayout用法详解及自定义样式

    TabLayout的默认样式: app:theme="@style/Widget.Design.TabLayout" 从系统定义的该样式继续深入: fill fixed 264dp ...

  6. android自定义TabLayout

    由于android自带的tablayout不能实现某些效果,所以我们简单自定义一个,能够满足大部分的使用场景 要点1:继承HorizontalScrollView,linearlayout中addvi ...

  7. Android Studio 第五十期 - 自定义TabLayout

    代码已经整理好,效果如下图: code1: <com.ui.widget.UnAnimTabLayoutandroid:id="@+id/tab"android:layout ...

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

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

  9. TabLayout的自定义实现选项卡背景的滑动动画

    原文链接:http://blog.csdn.net/u013233097/article/details/52489793 最近看到App上一个不错的导航效果:一个导航滑动的效果,被选中的背景会有变化 ...

最新文章

  1. python >> 和 <<
  2. Deleted表用于存储DELETE和UPDATE语句所影响的行的复本
  3. iOS开发:Objective-C优雅的语法
  4. 非常美妙的图片,呵呵
  5. iOS的推送证书过期的处理
  6. Ajax ToolKit --- ModelPopupExtender应用经验二则
  7. svn之迁移代码技巧
  8. Python3 数据库连接
  9. Fortinet 防火墙受高危漏洞影响,可遭远程攻击
  10. JSK-16500 金币【模拟】
  11. 特殊权限suid,sgid,sticky和acl(访问控制列表)参数详解
  12. 简单的全局异常统一处理
  13. 海康GB28181接入SRS服务器,实现低延迟直播
  14. java url 请求 最大长度限制,Http协议中的各种长度限制总结
  15. linux中 zip命令将整个目录打成zip包
  16. Linux系统的上行和下行带宽的检测
  17. java 引用数据类型Scanner类 Random类
  18. (补)单片机原理及应用学习笔记(三)
  19. 机器人是如何实现控制的,它的控制器有哪些组成?
  20. oracle查询sql走索引吗,Oracle SQL不走索引小记

热门文章

  1. java 获得唯一 数字_java生成唯一数字
  2. python+openCV 自适应阈值分割
  3. uva10635 Prince and Princess
  4. es数据库查询API
  5. TcaplusDB君 · 行业新闻汇编(12月20号)
  6. NodeJS简介-node.js是什么?
  7. java channel midi_为Java程序中添加播放MIDI音乐功能
  8. 太阳能路灯网站SEO执行方案
  9. java监测服务器信息(cpu,内存,运行时间等),springboot监控服务器信息
  10. 无法将win10配置在此计算机硬件上运行,WIN10系统备份 提示:无法将系统映像保存在计算机从中启动或安装WIDOWS的驱动器上...