Android ViewPager指示器

在很多常见的app中都有使用指示器,别的不说,app顶部就是一个指示器啦,那么指示器这种效果该怎么做呢?步骤有以下几点:
1、构建布局。你的指示器应该长什么样子,在界面中的什么位置,它应该有多少个页面(即有多少个tab选项卡),你给它设计的滑动跟随的东西是三角形还是一杠?
2、自定义控件。虽然不用自定义控件貌似也能做出指示器的效果,但这样你就需要对多个控件单独控制,一个tab的内容就是一个TextView,还有外层的LinearLayout等,你应该怎样来做控制?滑动跟随的效果你打算给谁绘制?这些都是一个个现实的问题。但是自定义控件不同,你想怎么搞就怎么搞,想绘制什么就绘制什么,关键你可以把以上提到的多个控件放到自定义控件中,作为一个控件来直接控制,你说这样的操作爽不爽。
3、画UI,指示器我们采用自定义控件来做,因此指示器即tab部分就用自定义控件了,然后是指示器的主体(即ViewPager)我们直接使用v4包中的ViewPager控件即可。
4、设计分页页面。这里说的分页页面就是一个个的Fragment,指示器来回切换不同的界面内容并不是一直在不断的切换Activity,而是在一个Activity中不断地换页,就好比:一个Activity就是一本书,每个Fragment都是一页一页的纸,不管你怎么翻页,都还是在这本书中。Fragment数量对应tab的数量,Fragment呈现的内容由你自己定义,你可以和Activity一样创建布局文件,在里面放你想展示的内容。
走完以上4步ViewPager应该可以动了。
5、滑动跟随的标志。这个东西完全是自己绘制的东西,app中最常见的就是三角形和一杠,其他的就自己去画吧。这个涉及到自定义绘制的内容。其实弄明白了顺序也不是很难。首先在构造函数中初始化画笔,在合适的地方创建Path类对象即路径,然后通过mPath.moveTo(x,y)将路径起点移动到(x,y)处,然后通过mPath..lineTo(a,b)把线直接从点(x,y)连到(a,b)处,绘制完路径之后在重写的dispatchDraw方法中调整一下画布然后通过drawPath方法绘制一下路径即可。
6、滑动跟随。滑动ViewPager页面让滑动跟随标志同步运动起来?这里面的原理其实很简单,我们之前不是在画布上绘制了滑动跟随标志吗?你只要对画布做平移看起来的效果不就是标志移动了吗。在你翻页的同时平移画布就能实现通过运动了。
7、指示器tab联动。当我们的tab如果超出一个界面所能显示的个数的时候(即你有10个tab,但一次只能显示3个tab),我们都知道每个tab都是自定义控件中的子控件TextView,如果你定了10个,那么默认效果是10一次显示在一个界面中。这样并不是我们所理想的效果。这时候又要说到绘制的问题了,这里的每个TextView的宽度我们在自定义控件类中改参数,用屏幕宽度来除以3(假设你一次只想显示3个tab),这样就定下来每个tab的宽度占屏幕的1 / 3了,超出部分自然不会显示。
8、点击tab切换page页。这个很简单,只要通过循环把所有的TextView加上一个点击事件即可。然后在点击时间的回调函数中调用ViewPager的setCurrentItem(position),这样在你电机的同时才会切换至相应的pager页面,否则只是普通的点击事件。
9、tab文字高亮。很简单。在此之前我们应该先获得所有的TextView并把他们的字体颜色全部覆盖掉,免得等下影响效果。然后我们点击的那个TextView由于我们是通过循环来设置点击事件的,因此我们可以通过循环变量 i 来确定当前点击的tab的索引,只需要在每次循环中使用final int j = i,然后在点击回调中使用 j 来做逻辑即可。拿到 j 后不就可以拿到对应的TextView吗通过getChildAt(j),然后设置字体就完事了。

以上就是ViewPager的基本使用步骤,接下来上代码。

布局文件



MainActivity.java文件

//这里我们使用的是FragmentPagerAdapter,是提供提供来专门给ViewPager使用的
   pagerAdapter = new FragmentPagerAdapter(getSupportFragmentManager()) {
            @Override
            public Fragment getItem(int position) {
    //arrayList中存放的是一个个的Fragment对象  
                return arrayList.get(position);
            }

            @Override
            public int getCount() {
                return arrayList.size();
            }
自定义tab文件,同时把viewpager控制放在一起

public class ViewPagerIndicator extends LinearLayout {

    private Paint mPaint;
    private Path mPath;
    private int mTriangleWidth;
    private int mTriangleHeight;

    private static final float RADIO = 1/6F;
    //定义三角形底边的最大宽度
    private final int DIMENSION_TRIANGLE_MAX = (int)(getScreenWidth() / 3 * RADIO);
    private int mInitTranslationX;      //偏移位置
    private int mTranslationX;          //移动时的偏移

    private int mTabVisibleCount;

    private static final int COUNT_DEFAULT_TAB = 4;

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

    public ViewPagerIndicator(Context context,AttributeSet attrs) {
        super(context, attrs);

        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setColor(Color.WHITE);
        mPaint.setPathEffect(new CornerPathEffect(5));  //给三角形的边设置圆角,使得三角形不至于太尖锐

        TypedArray typeArray = context.obtainStyledAttributes(attrs,R.styleable.ViewPagerIndicator);

        //获得先前在自定义属性文件中定义的visible_tab_count属性,如果找不到则自动使用默认值来设置默认显示的选项卡数量
        mTabVisibleCount = typeArray.getInt(R.styleable.ViewPagerIndicator_visible_tab_count,COUNT_DEFAULT_TAB);

        if(mTabVisibleCount < 0){
            mTabVisibleCount = COUNT_DEFAULT_TAB;
        }
        typeArray.recycle();
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        canvas.save();

        canvas.translate(mInitTranslationX + mTranslationX,getHeight());
        canvas.drawPath(mPath,mPaint);
        canvas.restore();
        super.dispatchDraw(canvas);

    }

    /**
     * 布局加载完毕调用的回调函数
     */
    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();

        int cCount = getChildCount();   //得到当前控件的子控件数

        if(cCount == 0){
            return ;
        }
        for(int i = 0;i= mTabVisibleCount - 2 && getChildCount() > mTabVisibleCount && offset > 0){
            if(mTabVisibleCount != 1){
                this.scrollTo((position - (mTabVisibleCount - 2)) * tabWidth + (int)(tabWidth * offset),0);
            }else{
                this.scrollTo((int)(tabWidth * position + tabWidth * offset),0);
            }

        }
        /**
         * 调用以下方法重绘,即让他去触发dispatchDraw函数,从而,使得画布移动,也就是我们所看到的滑动跟随啦
         */
        invalidate();
    }


    /**
     * 控件宽高发生变化回调该方法,第一次初始化将会调用该函数
     * @param w  控件当前宽度
     * @param h  控件当前高度
     * @param oldw  控件发生变化之前的宽度
     * @param oldh  控件发生变化之前的高度
     */
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        /**
         * 定义三角形的宽度
         * 下面的min函数是为了控制让三角形的宽度不要超过规定的默认值而做的判断
         */
        mTriangleWidth = (int)( w / mTabVisibleCount * RADIO);
        mTriangleWidth = Math.min(mTriangleWidth,DIMENSION_TRIANGLE_MAX);

        /**
         * 起始偏移,我们把跟随标志(下面都将设其为三角形)设计在tab的底部中央,这个就是水平偏移
         */
        mInitTranslationX = w / mTabVisibleCount / 2 - mTriangleWidth / 2;

        initTriangle();
    }
    //初始化三角形
    public void initTriangle(){
        mPath = new Path();
        /**
         * 定下此次绘制路径的起点
         */
        mPath.moveTo(0,0);
        /**
         * 本次绘制路径的终点,从前一个点到本次路径的终点这一段距离是直线
         */
        mPath.lineTo(mTriangleWidth,0);
        mPath.lineTo(mTriangleWidth / 2,-(mTriangleWidth / 2 - 2));
        /**
         * 让路径的起始点和最后一个终止点连接闭合绘制的图形
         */
        mPath.close();
    }

    /**
     * 清除掉tab上所有的字体高亮效果
     */
    public void resetTextViewColor(){
        for(int i = 0;i

你可能感兴趣的:(Android ViewPager指示器)