自定义ViewPagerIndicator-视图指示器

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自定义ViewPagerIndicator-视图指示器相关的知识,希望对你有一定的参考价值。

ViewPagerIndicator.java

public class ViewPagerIndicator extends LinearLayout {

    private Paint mPaint;
    private Path mPath;
    private int mTriangleWidth;
    private int mTriangleHeight;
    private static final float RADIO_TRIANGLE_WIDTH = 1/6F;
    //三角形的底边最大宽度
    private final float DIMENTION_TRIANGLE_WIDTH_MAX = getScreenWidth() / 3 * RADIO_TRIANGLE_WIDTH;
    private int mInitTranslationX;
    private int mTranslationX;
    private int mVisibleTabCount;
    private static final int COUNT_DEFAULT_TAB = 4;
    private static final int COLOR_TEXT_NORMAL = 0x77FFFFFF;
    private static final int COLOR_TEXT_HIGHLIGHT = 0xFFFFFFFF;
    private ViewPager mViewPager;
    private HorizontalScrollView mScrollView;
    private boolean isClicked = false; //判断是否是由点击产生的滑动
    private int scrollLocation; //Tab滚动的位置

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

    public ViewPagerIndicator(Context context, AttributeSet attrs) {
        super(context, attrs);
        //获取可见的tab数量
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ViewPagerIndicator);
        mVisibleTabCount = a.getInt(R.styleable.ViewPagerIndicator_visible_table_count, COUNT_DEFAULT_TAB);

        if (mVisibleTabCount < 0) {
            mVisibleTabCount = COUNT_DEFAULT_TAB;
        }
        a.recycle();

        int w = getScreenWidth();  //屏幕宽度
        Log.i("屏幕宽度", w+"");

        mTriangleWidth = (int) (w / mVisibleTabCount * RADIO_TRIANGLE_WIDTH);
        mTriangleWidth = (int) Math.min(mTriangleWidth, DIMENTION_TRIANGLE_WIDTH_MAX);
        mInitTranslationX = w / mVisibleTabCount / 2 - mTriangleWidth / 2;
        Log.i("InitTranslationX", ""+mInitTranslationX);
        Log.i("mTrianglewidth", mTriangleWidth+"");
        Log.i("TabWidth", ""+(int)(w/mVisibleTabCount));
        initTriangle();

        //初始化画笔
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setColor(Color.parseColor("#ffffff"));
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setPathEffect(new CornerPathEffect(3));
    }

    public interface OnPageChangeListener {
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels);

        public void onPageSelected(int position);

        public void onPageScrollStateChanged(int state);
    }

    public OnPageChangeListener mListener;

    public void setOnPageChangedListener(OnPageChangeListener listener) {
        this.mListener = listener;
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {

        canvas.save();

        canvas.translate(mInitTranslationX + mTranslationX, getHeight()+2);
        canvas.drawPath(mPath, mPaint);

        canvas.restore();

        super.dispatchDraw(canvas);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
    }

    /**
     * 通过布局添加Tab
     */
    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();

        int cCount = getChildCount();
        if (cCount == 0) {
            return;
        }

        for (int i = 0; i < cCount; i++) {
            View view = getChildAt(i);
            LayoutParams lp = (LayoutParams) view.getLayoutParams();
            lp.weight = 0;
            lp.width = getScreenWidth() / mVisibleTabCount;
        }

        setItemClickEvent();
    }

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

    /**
     * 初始化三角形
     */
    private void initTriangle() {
        mTriangleHeight = mTriangleWidth / 2;
        mPath = new Path();
        mPath.moveTo(0,0);
        mPath.lineTo(mTriangleWidth, 0);
        mPath.lineTo(mTriangleWidth/2, -mTriangleHeight);
        mPath.close();
    }

    /**
     * 指示器跟随手指进行滚动
     * @param position
     * @param offset
     */
    public void scroll(int position, float offset) {
        int tabWidth = getScreenWidth() / mVisibleTabCount;
        mTranslationX = (int) (tabWidth * (position + offset));
        invalidate();

        //三角形的位置
        int triangleLocation = mTranslationX + mInitTranslationX;
        int screenWidth = getScreenWidth();
        //当三角形处于滑动至屏幕外时移动外层ScrollView
        if ((triangleLocation - scrollLocation) > (screenWidth - mInitTranslationX)
                && offset > 0.5 && !isClicked) {
            if (mVisibleTabCount == 1) {
                mScrollView.scrollTo(mTranslationX, 0);
                scrollLocation = mTranslationX;
            } else {
                mScrollView.scrollTo((position - 2) * tabWidth, 0);
                scrollLocation = (position - 2) * tabWidth;
            }
        } else if((triangleLocation - scrollLocation) < mInitTranslationX && offset > 0
                && offset < 0.5 && !isClicked) {
            if (mVisibleTabCount == 1) {
                mScrollView.scrollTo(mTranslationX, 0);
                scrollLocation = mTranslationX;
            } else {
                mScrollView.scrollTo(position * tabWidth, 0);
                scrollLocation = position * tabWidth;
            }
        }
        //滑动完成时,将标记位恢复
        if (offset == 0) {
            isClicked = false;
        }
    }

    public void setTabItemTitles(List<String> titles) {
        if(titles != null && titles.size() > 0) {
            this.removeAllViews();
            for (String title : titles) {
                addView(generateTextView(title));
            }
        }

        setItemClickEvent();
    }

    /**
     * 根据title创建tab
     * @param title
     * @return
     */
    private View generateTextView(String title) {
        TextView tv = new TextView(getContext());
        LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
        lp.width = getScreenWidth() / mVisibleTabCount;
        tv.setText(title);
        tv.setGravity(Gravity.CENTER);
        tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);
        tv.setTextColor(COLOR_TEXT_NORMAL);
        tv.setLayoutParams(lp);
        return tv;
    }

    /**
     * 设置可见Tab数量
     * @param count
     */
    public void setVisibleTabCount(int count) {
        mVisibleTabCount = count;
    }

    /**
     * 设置关联的ViewPager
     * @param viewPager
     * @param position
     */
    public void setViewPager(ViewPager viewPager, int position) {
        mViewPager = viewPager;


        viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                scroll(position, positionOffset);
                if(mListener != null) {
                    mListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
                }
            }

            @Override
            public void onPageSelected(int position) {
                if(mListener != null) {
                    mListener.onPageSelected(position);
                }

                highLightTextView(position);
            }

            @Override
            public void onPageScrollStateChanged(int state) {
                if(mListener != null) {
                    mListener.onPageScrollStateChanged(state);
                }
            }
        });

        viewPager.setCurrentItem(position);
        highLightTextView(position);
    }

    /**
     * 设置外层HorizontalScrollView
     * @param scrollView
     */
    @RequiresApi(api = Build.VERSION_CODES.M)
    public void setScrollView(HorizontalScrollView scrollView) {
        mScrollView = scrollView;

        mScrollView.setOnScrollChangeListener(new OnScrollChangeListener() {
            @Override
            public void onScrollChange(View view, int i, int i1, int i2, int i3) {
                scrollLocation = i2;
            }
        });
    }

    /**
     * 高亮显示选中tab文本
     * @param position
     */
    public void highLightTextView(int position) {
        View view;
        for (int i = 0; i < getChildCount(); i++) {
            view = getChildAt(i);
            if(view instanceof TextView) {
                ((TextView) view).setTextColor(COLOR_TEXT_NORMAL);
            }
        }
        view = getChildAt(position);
        if(view instanceof TextView) {
            ((TextView) view).setTextColor(COLOR_TEXT_HIGHLIGHT);
        }
    }

    /**
     * 设置Tab的点击事件
     */
    public void setItemClickEvent() {
        int cCount = getChildCount();
        for (int i = 0; i < cCount; i++) {
            final int j = i;
            View view = getChildAt(i);
            view.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View view) {
                    isClicked = true;
                    mViewPager.setCurrentItem(j);
                }
            });
        }
    }

}

 

以上是关于自定义ViewPagerIndicator-视图指示器的主要内容,如果未能解决你的问题,请参考以下文章

Jake Wharton之ViewPagerIndicator解读预备役

Android自定义ViewPager图片指示器,兼容实现底部横线指示器

自己定义ViewpagerIndicator (仿猫眼,加入边缘回弹滚动效果)

使用自定义视图的自定义属性传入布局资源

开源框架ViewPagerIndicator的使用——TabPageIndicator

ViewPagerIndicator的使用方法