自定义TabLayout
前言
系统自带的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相关推荐
- 一个工具类实现自定义Tablayout的下划线宽度
** 只改变Tablayout的下划线的宽度,只需要一个工具类就可以可满足** 1.写个工具类 封装: /*** @author FX* @date 2018/07/19 11:11* @fuctio ...
- Android 自定义TabLayout
默认的TabLayout是没有花里胡哨的功能的,比如说我们可能希望它有边框,或者有背景颜色,或者外边框.因此就需要更改一些属性,或者在代码中实现.比如下图这种带边框,字体改变. 实现思路: tabla ...
- 自定义TabLayout的下划线的长度
tablayout自定义导航线的长度的问题,我见网上有两个解决方案,我用到我的项目中都没效果,自己总结了一个方案: 一:如果你的项目中没有滑动的动画需求你可以自定义tablayout'的item,自然 ...
- android tablayout 自定义,TabLayout的自定义
TabLayout的自定义,主要是通过setCustomView方法来添加自定义布局实现. 自定义TabLayout的实现主要包含以下几个步骤 ●创建自定义布局(这里我加了一个动画控件,可以替换成其他 ...
- android tablayout 自定义,TabLayout用法详解及自定义样式
TabLayout的默认样式: app:theme="@style/Widget.Design.TabLayout" 从系统定义的该样式继续深入: fill fixed 264dp ...
- android自定义TabLayout
由于android自带的tablayout不能实现某些效果,所以我们简单自定义一个,能够满足大部分的使用场景 要点1:继承HorizontalScrollView,linearlayout中addvi ...
- Android Studio 第五十期 - 自定义TabLayout
代码已经整理好,效果如下图: code1: <com.ui.widget.UnAnimTabLayoutandroid:id="@+id/tab"android:layout ...
- TabLayout自定义指示器及样式
一,自定义指示器下标 效果图如下: 1,新建一个名为:layer_tab_indicator的layer-list文件,然后定义想要的样式,其中bitmap 设置成需要的图片格式,也可以根据需求在it ...
- TabLayout的自定义实现选项卡背景的滑动动画
原文链接:http://blog.csdn.net/u013233097/article/details/52489793 最近看到App上一个不错的导航效果:一个导航滑动的效果,被选中的背景会有变化 ...
最新文章
- python >> 和 <<
- Deleted表用于存储DELETE和UPDATE语句所影响的行的复本
- iOS开发:Objective-C优雅的语法
- 非常美妙的图片,呵呵
- iOS的推送证书过期的处理
- Ajax ToolKit --- ModelPopupExtender应用经验二则
- svn之迁移代码技巧
- Python3 数据库连接
- Fortinet 防火墙受高危漏洞影响,可遭远程攻击
- JSK-16500 金币【模拟】
- 特殊权限suid,sgid,sticky和acl(访问控制列表)参数详解
- 简单的全局异常统一处理
- 海康GB28181接入SRS服务器,实现低延迟直播
- java url 请求 最大长度限制,Http协议中的各种长度限制总结
- linux中 zip命令将整个目录打成zip包
- Linux系统的上行和下行带宽的检测
- java 引用数据类型Scanner类 Random类
- (补)单片机原理及应用学习笔记(三)
- 机器人是如何实现控制的,它的控制器有哪些组成?
- oracle查询sql走索引吗,Oracle SQL不走索引小记
热门文章
- java 获得唯一 数字_java生成唯一数字
- python+openCV 自适应阈值分割
- uva10635 Prince and Princess
- es数据库查询API
- TcaplusDB君 · 行业新闻汇编(12月20号)
- NodeJS简介-node.js是什么?
- java channel midi_为Java程序中添加播放MIDI音乐功能
- 太阳能路灯网站SEO执行方案
- java监测服务器信息(cpu,内存,运行时间等),springboot监控服务器信息
- 无法将win10配置在此计算机硬件上运行,WIN10系统备份 提示:无法将系统映像保存在计算机从中启动或安装WIDOWS的驱动器上...