美文网首页
自定义TabLayout

自定义TabLayout

作者: bug音音 | 来源:发表于2021-01-14 21:09 被阅读0次

    前言

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

    效果图

    img

    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初始化布局

    添加控件

     @Override
        protected 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;
            //添加textview
            for (int i = 0; i < mListTitle.size(); i++) {
                addTextView(i);
            }
            //初始化点击事件
            setListener();
        }
    
     /**
         * 添加textview
         */
        private void addTextView(int i) {
            //初始化textview
            TextView 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();
        }
    
    
        @Override
        protected 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;
            //添加textview
            for (int i = 0; i < mListTitle.size(); i++) {
                addTextView(i);
            }
            //初始化点击事件
            setListener();
        }
    
    
        /**
         * 添加textview
         */
        private void addTextView(int i) {
            //初始化textview
            TextView 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() {
                    @Override
                    public 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());
            else
                mListTitle.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.MyIndicator
           android: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

          本文链接:https://www.haomeiwen.com/subject/rztgaktx.html