Adnroid Tab标签页——基于ViewPager与Fragment实现

Android 2016-03-19

组件功能

  • 标签页可通过参数自定义个数
  • 多余的标签页可以隐藏
  • 可自定义默认显示的标签个数
  • tab内容页可以左右滑动进行切换tab标签页
  • 可自定义tab标签的指示器

下载地址

github下载链接

项目效果

Screenshot_2016-03-19-14-40-01.jpg

项目思路

布局的构建

首先,该界面分为2个部分,上面一个部分由于要自定义指示器与显示内容的滚动,所以我们就自己创建一个LinearLayout的子类来作为他的布局容器,那下半部分就直接使用ViewPager进行构建

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:masterzhang="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    android:background="#ffffff"
    >
    <com.masterzhang.www.view.ViewPagerIndicator
        android:id="@+id/mIndicator"
        android:layout_width="match_parent"
        android:layout_height="45dp"
        android:background="@color/TabColor"
        android:orientation="horizontal"
        masterzhang:visibal_tab_count="4"
        >

    </com.masterzhang.www.view.ViewPagerIndicator>
    <android.support.v4.view.ViewPager
        android:id="@+id/myViewPager"
        android:layout_height="0dp"
        android:layout_width="match_parent"
        android:layout_weight="1"
        >
    </android.support.v4.view.ViewPager>
</LinearLayout>

接下来我们开始构建自定义的顶部控件

首先,我们要想使顶部的tab标签,进行自定义,我们就必须暴露接口给调用者进行设置标签的对应方法。

     /**
     * 设置标签栏
     * @param titls
     */
    public void setTabTitles(List<String> titls)
    {
        if(titls!=null&&titls.size()>0)
        {
            //移除原来的textView
            this.removeAllViews();
            this.mTabTitles=titls;
            for(String title:mTabTitles)
            {
                addView(generateTextView(title));//generateTextView()方法为组件添加Textview
            }
        }
        setItemClickEvent();
    }
    /**
     * 设置可见的tabs个数
     * @param count
     */
    public void setmTabVisibleCount(int count)
    {
        mTabVisibleCount=count;
    }

然后构造generateTextView()方法为LinearLayout动态的添加标签

    /**
     * 根据title生成textview
     * @param title
     * @return
     */
    private View generateTextView(String title) {
        TextView tv=new TextView(getContext());
        LinearLayout.LayoutParams lp=new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT);
        lp.width=getScreenWidth()/mTabVisibleCount;//每个tab的宽度都为屏幕大小除以我们设置的组件的个数
        tv.setText(title);
        tv.setGravity(Gravity.CENTER);
        tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);
        tv.setTextColor(COLOR_TEXT_NORMAL);
        tv.setLayoutParams(lp);
        return tv;
    }

接下来我们来构layout下的三角形指示器,绘制工作在dispatchDraw()方法中进行,改方法是LinearLayout的绘制方法基本与Draw方法相同,所以我们在dispatchDraw方法中进行绘制三角形。

//三角形绘制
    @Override
    protected void dispatchDraw(Canvas canvas) {
        canvas.save();
        canvas.translate(initTrangleX + mTrangleX, getHeight() + 2);
        canvas.drawPath(mPath,mPaint);
        canvas.restore();
        super.dispatchDraw(canvas);
    }

那么我们该在哪里初始化三角形呢?由于在控件的宽高发生变化的时候都会调用onSizeChanged方法,所以我们重写改方法,在盖方法中得到新的控件的宽高,根据比例来初始化三角形。

/**
     *在控件的宽高发生变化的时候都会调用onSizeChanged方法
     *可以在改方法中得到控件的宽和高
     */
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mTrangleWidth=(int)(w/mTabVisibleCount*RADIO_TRANGLE_WIDTH);
        initTrangleX=w/mTabVisibleCount/2-mTrangleWidth/2;
        initTrangle();//初始化三角形
    }
/**
     * 初始化三角形
     */
    private void initTrangle() {
        mTrangleHeight=mTrangleWidth/2;
        mPath=new Path();
        mPath.moveTo(0, 0);
        mPath.lineTo(mTrangleWidth, 0);
        mPath.lineTo(mTrangleWidth / 2, -mTrangleHeight);
        mPath.close();//线条闭合
    }

好接下来我们来解决如何在滑动ViewPager中滑动的时候如何动态的让三角形进行移动。ViewPager中一个setOnPageChangeListener可以监听ViewPager中移动的情况,所以我们在改方法中监听它的移动情况,然后重绘三角形的位置,与重置LinearLayout的位置

     /**
     * 三角形指示器跟随手指进行移动移动
     * @param position
     * @param offset
     */
    public void scroll(int position, float offset) {
        int tabWidth=getWidth()/mTabVisibleCount;
        mTrangleX=(int)(tabWidth*(offset+position));
        //容器移动,当tab处于最后一个时
        if(position>=(mTabVisibleCount-2)&&offset>0&&getChildCount()>mTabVisibleCount)
        {
            if(mTabVisibleCount!=1)
            {
                this.scrollTo((position-(mTabVisibleCount-2))*tabWidth+(int)offset*tabWidth,0);
            }
            else
            {
                this.scrollTo((int)(position*tabWidth+tabWidth*offset),0);
            }

        }
        invalidate();
    }
 /**
     * 设置与之关联的viewPager
     * @param viewPager
     * @param position
     */
    public void setViewPager(ViewPager viewPager,int position)
    {
        mViewPager=viewPager;
        //监听面板移动变化
        mViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                //从第0页移动到第一页的时候移动量为 标签宽度*位置
                scroll(position,positionOffset);
                if(pageChangeListener!=null)
                {
                    pageChangeListener.onPageScrolled(position,positionOffset,positionOffsetPixels);
                }
            }

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

            @Override
            public void onPageScrollStateChanged(int state) {
                if(pageChangeListener!=null)
                {
                    pageChangeListener.onPageScrollStateChanged(state);
                }
            }
        });
        mViewPager.setCurrentItem(position);
        highLightTextView(position);
    }

最后我们设置点击tab按钮,然后调转到对应的tab内容页

    /**
     * 设置tab点击跳转
     */
    private 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 v) {
                    mViewPager.setCurrentItem(j);
                }
            });
        }
    }

-----end-----


本文由 zhanghuayan 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处。

赏个馒头吧