ViewPager+三角形指示器(替换掉TabLayout),实测可用!

引言:android提供的viewPager+TabLayout的虽然体验不错,但是tabLayout指示器默认只有横线指示器,想要其他效果 ,比较难。 本文主要内容:替换TabLayout,通过自定义ViewGroup 实现与tabLayout 一样的效果,并且支持三角形箭头,支持数据绑定。参考链接:https://www.imooc.com/article/14502 


看效果:


具体实现及使用步骤:

一:自定义attr属性

二:自定义ViewGroup

三:代码使用


一,添加attr属性

  <!--默认的显示的Tab数量-->
    <attr name="default_display_counts" format="integer"/>
    <!--高亮文本的颜色-->
    <attr name="high_light_color" format="color"/>
    <!--正常文本的颜色-->
    <attr name="normal_text_color" format="color"/>
    <!--图形的颜色-->
    <attr name="graphics_color" format="color"/>
    <!--文本的大小-->
    <attr name="text_size" format="integer"/>
    <!--图形的高度-->
    <attr name="graphics_height" format="integer"/>
    <!--图形的类型-->
    <attr name="is_draw_line" format="boolean"/>

    <declare-styleable name="ChangeablePagerIndicator">
        <!--默认的显示的Tab数量-->
        <attr name="default_display_counts"/>
        <!--高亮文本的颜色-->
        <attr name="high_light_color"/>
        <!--正常文本的颜色-->
        <attr name="normal_text_color"/>
        <!--图形的颜色-->
        <attr name="graphics_color"/>
        <!--文本的大小-->
        <attr name="text_size"/>
        <!--图形的高度-->
        <attr name="graphics_height"/>
        <!--图形的类型-->
        <attr name="is_draw_line"/>
    </declare-styleable>

小白指引图


二:自定义LinearLayout ,之所以自定LinearLayout因为需要"水平排列字体", 当然其他的布局也可以。为了省事

public class ChangeablePagerIndicator extends LinearLayout {

        //默认的高亮文本颜色:白色
        public static final int COLOR_TEXT_HIGHLIGHT = Color.parseColor("#FFFFFFFF");
        //默认的正常文本颜色:灰色
        public static final int COLOR_TEXT_NORMAL = Color.parseColor("#77FFFFFF");
        //默认绘制图形的颜色:白色
        public static final int COLOR_GRAPHICS = Color.parseColor("#FFFFFFFF");
        //默认Tab的文本大小 16sp
        public static final int TAB_TEXT_SIZE = 16;
        //直线的高度 10dp
        public static final int LINE_HEIGHT = 10;
        //最小的显示Tab的数量
        public static final int DEFAULT_VISIBLE_COUNTS = 3;
        //绘制的类型:1.直线 2.三角形
        public static final int STYLE_LINE = 100;
        public static final int STYLE_TRIANGLE = 200;
        //三角形的比例
        public static final float TRIANGLE_RADIO = 1 / 6F;
        //绘制三角形的画笔
        private Paint mTrianglePaint;
        //绘制三角形的路径
        private Path mTrianglePath;
        //三角形的宽
        private int mTriangleWidth;
        //三角形的高
        private int mTriangleHeight;
        //绘制直线的画笔
        private Paint mLinePaint;
        //线的宽度
        private int mLineWidth;
        //初始位置时三角形的位置
        private int mStartX;
        //移动时三角形的位置
        private int mMoveX;
        //绘制的类型
        private int mDrawStyle = STYLE_LINE;
        //默认显示的tab item数量
        private int mDefaultVisibleCounts;
        //高亮文本的颜色
        private int mHighLightColor;
        //普通文本的颜色
        private int mNormalTextColor;
        //文本大小
        private int mTextSize;
        //线的高度(strokeWidth)
        private int mLineHeight;
        //直线或者三角形的颜色
        private int mGraphicsColor;

        public ChangeablePagerIndicator(Context context) {
            this(context, null);
        }

        public ChangeablePagerIndicator(Context context, AttributeSet attrs) {
            super(context, attrs);
            //获取自定义的值
            getCustomValue(context, attrs);
            //初始化三角形的画笔
            initTrianglePaint();
            //初始化直线的画笔
            initLinePaint();
        }

        /**
         * 加载完XML时,调用此方法
         */
        @Override
        protected void onFinishInflate() {
            super.onFinishInflate();

            int coutns = getChildCount();
            if (coutns == 0)
                return;

            for (int i = 0; i < coutns; i++) {
                View view = getChildAt(i);
                LinearLayout.LayoutParams params = (LayoutParams) view.getLayoutParams();
                params.weight = 0;
                params.width = getScreenWidth() / mDefaultVisibleCounts;

                view.setLayoutParams(params);
            }
            //设置监听
            setItemClickListener();
            //直线的宽度
            mLineWidth = getScreenWidth() / mDefaultVisibleCounts;
        }

        @Override
        protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
            super.onSizeChanged(width, height, oldWidth, oldHeight);
            //创建三角形
            createIndicatorTriangle();
        }

        @Override
        protected void dispatchDraw(Canvas canvas) {
            canvas.save();
            if (mDrawStyle == STYLE_LINE) {
                //绘制直线
                canvas.drawLine(mMoveX, getHeight(), mMoveX + mLineWidth, getHeight(), mLinePaint);
            }
            if (mDrawStyle == STYLE_TRIANGLE) {
                //绘制三角形
                canvas.translate(mStartX + mMoveX, getHeight());
                canvas.drawPath(mTrianglePath, mTrianglePaint);
            }
            canvas.restore();
            super.dispatchDraw(canvas);
        }

        /**
         * 获取自定义的值
         *
         * @param attrs
         */
        private void getCustomValue(Context context, AttributeSet attrs) {
            TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.ChangeablePagerIndicator);
            //获取默认显示的可见Tab的数量
            mDefaultVisibleCounts = attributes.
                    getInt(R.styleable.ChangeablePagerIndicator_default_display_counts, DEFAULT_VISIBLE_COUNTS);
            mDefaultVisibleCounts = Math.max(DEFAULT_VISIBLE_COUNTS, mDefaultVisibleCounts);
            //高亮文本的颜色
            mHighLightColor = attributes.getColor(R.styleable.ChangeablePagerIndicator_high_light_color, COLOR_TEXT_HIGHLIGHT);
            //普通文本的颜色
            mNormalTextColor = attributes.getColor(R.styleable.ChangeablePagerIndicator_normal_text_color, COLOR_TEXT_NORMAL);
            //文本大小
            mTextSize = attributes.getInt(R.styleable.ChangeablePagerIndicator_text_size, TAB_TEXT_SIZE);
            //线的高度(strokeWidth)
            mLineHeight = attributes.getInt(R.styleable.ChangeablePagerIndicator_graphics_height, LINE_HEIGHT);
            //直线或者三角形的颜色
            mGraphicsColor = attributes.getColor(R.styleable.ChangeablePagerIndicator_graphics_color, COLOR_GRAPHICS);
            //绘制的类型
            boolean drawStyle = attributes.getBoolean(R.styleable.ChangeablePagerIndicator_is_draw_line, true);
            mDrawStyle = drawStyle ? STYLE_LINE : STYLE_TRIANGLE;
            //直线的宽度
            mLineWidth = getScreenWidth() / mDefaultVisibleCounts;

            attributes.recycle();
        }

        /**
         * 初始化三角形的画笔
         */
        private void initTrianglePaint() {
            mTrianglePaint = new Paint();
            mTrianglePaint.setAntiAlias(true);
            //三角形的画笔颜色
            mTrianglePaint.setColor(mGraphicsColor);
            mTrianglePaint.setStyle(Paint.Style.FILL);
            //绘制角时的弧度
            mTrianglePaint.setPathEffect(new CornerPathEffect(2));
        }

        /**
         * 初始化直线的画笔
         */
        private void initLinePaint() {
            mLinePaint = new Paint(mTrianglePaint);
            mLinePaint.setStrokeWidth(mLineHeight);
        }

        /**
         * 创建指示器的三角形
         */
        private void createIndicatorTriangle() {
            int tabWidth = getScreenWidth() / mDefaultVisibleCounts;
            //三角形的宽度
            mTriangleWidth = (int) (tabWidth * TRIANGLE_RADIO);
            //初始位置时三角形的位置
            mStartX = (tabWidth - mTriangleWidth) / 2;
            //三角形的高度
            mTriangleHeight = mTriangleWidth / 3;

            //绘制三三角形路径
            mTrianglePath = new Path();
            mTrianglePath.moveTo(0, 0);
            mTrianglePath.lineTo(mTriangleWidth, 0);
            mTrianglePath.lineTo(mTriangleWidth / 2, -mTriangleHeight);
            mTrianglePath.close();
        }

        /**
         * 水平滚动
         *
         * @param position
         * @param offset
         */
        public void scroll(int position, float offset) {
            int tabWidth = getWidth() / mDefaultVisibleCounts;
            //指示器移动的距离
            mMoveX = (int) (tabWidth * (position + offset));

            //移动Tab
            if (position >= (mDefaultVisibleCounts - 2) && offset > 0
                    && getChildCount() > mDefaultVisibleCounts
                    && position != getChildCount() - 2) {
                if (mDefaultVisibleCounts != 1) {
                    int scrollX = (position - (mDefaultVisibleCounts - 2)) * tabWidth
                            + (int) (tabWidth * offset);
                    this.scrollTo(scrollX, 0);
                } else {
                    this.scrollTo((position * tabWidth
                            + (int) (tabWidth * offset)), 0);
                }

            }
            //重新绘制
            invalidate();
        }

        /**
         * 设置绘制的类型
         * 1.STYLE_LINE    直线
         * 2.STYLE_TRIANGLE 三角形
         */
        public void setDrawStyle(int style) {
            mDrawStyle = style;
            invalidate();
        }

        public void setDefaultVisibleCounts(int counts) {
            mDefaultVisibleCounts = counts;
            if (counts < DEFAULT_VISIBLE_COUNTS)
                mDefaultVisibleCounts = DEFAULT_VISIBLE_COUNTS;

            //直线的宽度
            mLineWidth = getScreenWidth() / mDefaultVisibleCounts;
        }

        /**
         * 不用加载布局文件,代码生成
         *
         * @param titles
         */
        public void setTabItems(List<String> titles) {
            if (titles == null)
                return;
            //首先移除所有的View
            this.removeAllViews();
            //根据标题生成TextView
            for (String title : titles) {
                this.addView(generateTitleView(title));
            }
            //设置监听
            setItemClickListener();
        }

        /**
         * 设置ViewPager
         *
         * @param viewPager
         * @param currentPos 当前选的位置
         */
        private ViewPager mViewPager;

        public void setViewPager(ViewPager viewPager, int currentPos) {
            mViewPager = viewPager;
            viewPager.addOnPageChangeListener(mListener);
            //设置当前选中项
            viewPager.setCurrentItem(currentPos);
        }

        /**
         * ViewPager监听
         */
        private IndicatorListener mListener = new IndicatorListener() {

            @Override
            public void scrollChanged(int position, float offset) {
                //进行Tab滚动
                scroll(position, offset);
            }

            @Override
            public void selected(int position) {
                //设置高亮文本,当前ViewPager与Tab一一对应
                setHighLightText(position);
            }
        };

        /**
         * Tab Item的点击监听
         */
        private void setItemClickListener() {
            for (int i = 0; i < getChildCount(); i++) {
                //点击的位置
                final int clickPosition = i;
                View view = getChildAt(i);
                if (view instanceof TextView) {
                    view.setOnClickListener(new OnClickListener() {

                        @Override
                        public void onClick(View view) {
                            //ViewPager跳到对应的选中项
                            mViewPager.setCurrentItem(clickPosition);
                        }
                    });
                }
            }
        }

        /**
         * 根据标题生成TextView
         *
         * @param title
         * @return
         */
        private View generateTitleView(String title) {
            TextView tv = new TextView(getContext());
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
            params.width = getScreenWidth() / mDefaultVisibleCounts;
            tv.setGravity(Gravity.CENTER);
            tv.setText(title);
            tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, mTextSize);
            tv.setTextColor(mNormalTextColor);
            tv.setLayoutParams(params);
            return tv;
        }

        /**
         * 设置高亮显示的文本
         * 也就是当前选中的文本
         *
         * @param position
         */
        private void setHighLightText(int position) {
            for (int i = 0; i < getChildCount(); i++) {
                View view = getChildAt(i);
                if (view instanceof TextView) {
                    //高亮颜色
                    if (i == position)
                        ((TextView) view).setTextColor(mHighLightColor);
                        //正常颜色
                    else
                        ((TextView) view).setTextColor(mNormalTextColor);
                }
            }
        }

        /**
         * 获取屏幕的宽度
         *
         * @return
         */
        private int getScreenWidth() {
            WindowManager manager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
            DisplayMetrics metrics = new DisplayMetrics();
            manager.getDefaultDisplay().getMetrics(metrics);
            return metrics.widthPixels;
        }
    }

三  xml布局

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

<!--绑定字体颜色也可以设置,这里没有列出来-->
    <com.xxxx.ChangeablePagerIndicator
        android:id="@+id/ln_indicator"
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="@dimen/dp35"
        android:layout_marginBottom="@dimen/dp10" 
        app:default_display_counts="3"//默认绑定数据大小
        app:is_draw_line="false"//是否需要绘制水平线,false就是绘制三角形
        app:graphics_color="@color/white"//绘制线的颜色
        android:background="@color/main_color"/>//背景颜色
    

    <android.support.v4.view.ViewPager
        android:id="@+id/vp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

四:代码使用如图:


懒得写的小伙伴直接粘贴

       ChangeablePagerIndicator mlnIndicator=view.findViewById(R.id.ln_indicator);
        mlnIndicator.setTabItems(mTitle);//mTitle ==List<String>(); 绑定数据源
        mlnIndicator.setViewPager(mViewPager,1);//绑定viewPager 1代表当前指针位置

目前遇见的问题 :ChangeablePagerIndicator添加android:layout_marginRight=" " android:layout_marginLeft="",会导致字体位置不对称问题,所有尽量不要使用这两个属性,问题研究中!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值