Android 快速实现 ViewPager 滑动页卡切换(可用作整个 app上导航)

我记得在前面,我写了一篇Android 微信6.1 tab栏图标和字体颜色渐变的实现,如果大家仅仅认为这篇文章的功能只是模仿微信颜色渐变效果,那就大错特错了!认真阅读了这篇文章的朋友,应该知道,这里面代码可用作 app 通用的底部栏导航,通过它能快速的实现类似微信6.0版本以底部导航的 app 整体架构,并且在 MainActivity 中需要编写的代码非常简洁。如果有兴趣的朋友可以去看看。

效果:

今天这篇 blog的内容同样可以拿来做 app 的整体架构,但与前面那篇 blog 不同,不同之处是前面那篇文章所讲的内容可用作底部导航,而这篇 blog 的内容,是用作顶部导航,老版本的微信就是此效果,ok,来看看效果图

实现原理

根据效果图,不难分析,可以通过自定义 ViewGroup 来实现,但这样代码量偏多,看了我的前面 blog 的朋友应该清楚,这里最好的实现方式是通过重写 LinearLayout,相比通过 ViewGroup 来实现,省略了测量onMeasure()和布局onLayout()方法的实现,因为这些LinearLayout已经帮我们实现好了,而我们真正要做的就是为 LinearLayout 填充内容,填充内容可大致可分为以下四个步骤:

1、填充每个 item 的内容

2、绘制每个 item 之间的分割线

3、绘制底部线条

4、绘制指示器的内容

代码实现

1、先把需要用的属性定义出来

需要的属性

1、页卡指示器的颜色

2、分割线的颜色

3、底部线条的颜色

4、页卡指示器的高度

5、分割线距离上下边距的距离

6、分割线的宽度

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <attr name="indicatorColor" format="color"/>
    <attr name="dividerColor" format="color"/>
    <attr name="bottomLineColor" format="color"/>
    <attr name="dividerMargin" format="dimension"/>
    <attr name="indicatorHeight" format="dimension"/>
    <attr name="bottomLineHeight" format="dimension"/>
    <attr name="dividerWidth" format="dimension"/>
    <declare-styleable name="SlidingTabLayout">
        <attr name="indicatorColor"/>
        <attr name="dividerColor"/>
        <attr name="bottomLineColor"/>
        <attr name="dividerMargin"/>
        <attr name="indicatorHeight"/>
        <attr name="bottomLineHeight"/>
        <attr name="dividerWidth"/>
    </declare-styleable>
</resources>

2、代码中获取属性,并附上相应的默认值

    /*默认的页卡颜色*/
    private final int DEFAULT_INDICATOR_COLOR = 0xffff00ff;
    /*默认分割线的颜色*/
    private final int DEFAULT_DIVIDER_COLOR = 0xff000000;
    /*默认title字体的大小*/
    private final int DEFAULT_TEXT_SIZE = 16;
    /*默认padding*/
    private final int DEFAULT_TEXT_PADDING = 16;
    /*divider默认的宽度*/
    private final int DEFAULT_DIVIDER_WIDTH = 1;
    /*indicator 的高度*/
    private final int DEFAULT_INDICATOR_HEIGHT = 5;
    /*底部线条的高度默认值*/
    private final int DEFAULT_BOTTOM_LINE_HEIGHT = 2;
    /*分割线距离上下边缘的距离默认为8*/
    private final int DEFAULT_DIVIDER_MARGIN = 8;
    /*底部线条的颜色默认值*/
    private final int DEFAULT_BOTTOM_LINE_COLOR = 0xff000000;
        /*获取TypedArray*/
        TypedArray typedArray = getResources().obtainAttributes(attrs, R.styleable.SlidingTabLayout);
        /*获取自定义属性的个数*/
        int N = typedArray.getIndexCount();
        Log.v("zgy","=========getIndexCount========="+N) ;
        for (int i = 0; i < N; i++) {
            int attr = typedArray.getIndex(i);
            switch (attr) {
                case R.styleable.SlidingTabLayout_indicatorColor:
                    /*获取页卡颜色值*/
                    mIndicatorColor = typedArray.getColor(attr, DEFAULT_INDICATOR_COLOR);
                    break;
                case R.styleable.SlidingTabLayout_dividerColor:
                    /*获取分割线颜色的值*/
                    mDividerColor = typedArray.getColor(attr, DEFAULT_DIVIDER_COLOR);
                    break;
                case R.styleable.SlidingTabLayout_bottomLineColor:
                    /*获取底部线条颜色的值*/
                    mBottomLineColor = typedArray.getColor(attr, DEFAULT_BOTTOM_LINE_COLOR);
                    break;
                case R.styleable.SlidingTabLayout_dividerMargin:
                    /*获取分割线的距离上线边距的距离*/
                    mDividerMargin = (int) typedArray.getDimension(attr, DEFAULT_DIVIDER_MARGIN * getResources().getDisplayMetrics().density);
                    Log.v("zgy","=========mDividerMargin========="+mDividerMargin) ;
                    break;
                case R.styleable.SlidingTabLayout_indicatorHeight:
                    /*获取页卡的高度*/
                    mIndicatorHeight = (int) typedArray.getDimension(attr, DEFAULT_INDICATOR_HEIGHT * getResources().getDisplayMetrics().density);
                    break;
                case R.styleable.SlidingTabLayout_bottomLineHeight:
                    /*获取底部线条的高度*/
                    mBottomLineHeight = (int) typedArray.getDimension(attr, DEFAULT_BOTTOM_LINE_HEIGHT * getResources().getDisplayMetrics().density);
                    break;
                case R.styleable.SlidingTabLayout_dividerWidth:
                    /*获取分割线的宽度*/
                    mDividerWidth = (int) typedArray.getDimension(attr, DEFAULT_DIVIDER_WIDTH * getResources().getDisplayMetrics().density);
                    break;
            }
        }
        /*释放TypedArray*/
        typedArray.recycle();

这里说一个细节,我经常在这里获取属性的时候习惯性的把

case R.styleable.SlidingTabLayout_indicatorColor:

写成

case R.attr.indicatorColor:

而且这里不会报错,不过结果可想而知,无法获取我们设置的属性内容,这里如果有跟我犯同样错误的朋友记得注意一下。

3、为 LinearLayout 填充内容

    /**
     * 设置viewPager,初始化SlidingTab,
     * 在这个方法中为SlidingLayout设置
     * 内容,
     *
     * @param viewPager
     */
    public void setViewPager(ViewPager viewPager) {
        /*先移除所以已经填充的内容*/
        removeAllViews();
        /* viewPager 不能为空*/
        if (viewPager == null) {
            throw new RuntimeException("ViewPager不能为空");
        }
        mViewPager = viewPager;
        mViewPager.setOnPageChangeListener(new InternalViewPagerChange());
        //填充内容
        populateTabLayout();
    }
    /**
     * 填充layout,设置其内容
     */
    private void populateTabLayout() {
        final PagerAdapter adapter = mViewPager.getAdapter();
        final OnClickListener tabOnClickListener = new TabOnClickListener();
        mItemName = (TabItemName) adapter;
        for (int i = 0; i < adapter.getCount(); i++) {
            TextView textView = createDefaultTabView(getContext());
            textView.setOnClickListener(tabOnClickListener);
            textView.setText(mItemName.getTabName(i));
            addView(textView);
        }
    }

根据ViewPager中页面的个数,填充相应的 tab。

4、绘制相应的内容

绘制内容,肯定在 onDraw()方法中

绘制底部线条

canvas.drawRect(0,height - mBottomLineHeight,getWidth(),height,mBottomPaint);

绘制分割线

 for (int i = 0; i < getChildCount() - 1; i++) {
      View child = getChildAt(i);
      canvas.drawLine(child.getRight(), mDividerMargin,child.getRight(), height - mDividerMargin,mDividerPaint);
        }

重点:绘制滑动页卡

        /*当前页面的View tab*/
        View selectView = getChildAt(mSelectedPosition);
        /*计算开始绘制的位置*/
        int left = selectView.getLeft();
        /*计算结束绘制的位置*/
        int right = selectView.getRight();
        if (mSelectionOffset > 0) {
            View nextView = getChildAt(mSelectedPosition + 1);
            /*如果有偏移量,重新计算开始绘制的位置*/
            left = (int) (mSelectionOffset * nextView.getLeft() + (1.0f - mSelectionOffset) * left);
            /*如果有偏移量,重新计算结束绘制的位置*/
            right = (int) (mSelectionOffset * nextView.getRight() + (1.0f - mSelectionOffset) * right);
        }
        /*绘制滑动的页卡*/
        canvas.drawRect(left, height - mIndicatorHeight, right, height, mIndicatorPaint);

运用案例

为了体现他的简洁之处,这里把 xml 中的代码也贴出来

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"               xmlns:tools="http://schemas.android.com/tools"               xmlns:zgy="http://schemas.android.com/apk/res-auto"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                tools:context=".MainActivity">
    <demo.slidingtablayout.view.SlidingTabLayout
        android:id="@+id/id_tab"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        zgy:bottomLineColor="#AEAEAE"
        zgy:dividerMargin="15dp"
        zgy:indicatorColor="#77e69c"
        zgy:indicatorHeight="5dp"
        zgy:bottomLineHeight="2dp"
        android:background="#eeeeee">
    </demo.slidingtablayout.view.SlidingTabLayout>

    <android.support.v4.view.ViewPager
        android:layout_below="@+id/id_tab"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/id_view_pager"/>
</RelativeLayout>

MainActivity.java

public class MainActivity extends ActionBarActivity {

    /*viewPager*/
    private ViewPager mViewPager ;
    /*自定义的 tabLayout*/
    private SlidingTabLayout mTabLayout ;
    /*每个 tab 的 item*/
    private List<PagerItem> mTab = new ArrayList<>() ;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mViewPager = (ViewPager) findViewById(R.id.id_view_pager) ;
        mTabLayout = (SlidingTabLayout) findViewById(R.id.id_tab) ;
        mTab.add(new PagerItem("tab1","FirstPager")) ;
        mTab.add(new PagerItem("tab2","SecondPager")) ;
        mTab.add(new PagerItem("tab3","ThirdPager")) ;
        mTab.add(new PagerItem("tab4","FourthPager")) ;
        mViewPager.setAdapter(new ViewPagerAdapter(getSupportFragmentManager()));
        /*需要先为 viewpager 设置 adapter*/
        mTabLayout.setViewPager(mViewPager);
    }

 private class ViewPagerAdapter extends FragmentPagerAdapter implements SlidingTabLayout.TabItemName{

        public ViewPagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {
            return mTab.get(position).createFragment();
        }

        @Override
        public int getCount() {
            return mTab.size();
        }

        @Override
        public String getTabName(int position) {
            return mTab.get(position).getTitle();
        }
    }
}

点击下载源码

时间: 2024-12-21 07:32:55

Android 快速实现 ViewPager 滑动页卡切换(可用作整个 app上导航)的相关文章

ViewPager实现页卡的3种方法(谷歌组件)

----方法一:---- 效果图: 须要的组件: ViewPager+PagerTabStrip 布局文件代码: <!--xmlns:android_custom="http://schemas.android.com/apk/res/com.pengkv.bigo"--> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layou

jQurey浏览器页卡切换 用于实时接口的长轮询

加页卡切换, <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script type="text/javascript" src="http://mat1.gtimg.com/www/js/jquery/jquery-1.11.1.m

Android中使用ViewPager实现屏幕页面切换和页面轮播效果

之前关于如何实现屏幕页面切换,写过一篇博文<Android中使用ViewFlipper实现屏幕切换>,相比ViewFlipper,ViewPager更适用复杂的视图切换,而且Viewpager有自己的adapter,这也让其适应复杂对象,实现数据的动态加载. ViewPager是谷歌官方给我们提供的一个兼容低版本安卓设备的软件包,里面包囊了只有在安卓3.0以上可以使用的api.而viewpager就是其中之一,利用它,我们可以做很多事情,从最简单的导航,到页面菜单等等. 下面我们就展示下Vie

ViewPager实现页卡的最新方法--简洁的TabLayout(谷歌支持包)

效果图: 加入依赖包: compile 'com.android.support:design:22.2.0' 布局文件: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com

高仿优酷Android客户端图片左右滑动(自动切换)

本例是用ViewPager去做的实现,支持自动滑动和手动滑动,不仅优酷网,实际上有很多商城和门户网站都有类似的实现: 具体思路: 1. 工程中需要添加android-support-v4.jar,才能使用ViewPager控件. 2. 图片的自动切换: 可使用Timer或者ScheduledExecutorService,这个有多重方式可以实现. 同时要切换底部的dots(园点) 3.Handler+Message机制更新UI,这个相信大家都很熟练,不再描述 4. 实现的一些细节:注意本例中的优

ViewPager 滑动页(一)

需求:滑动展示页,能够使用本地数据,及获取服务器数据进行刷新操作: 效果图: 实现分析: 1.目录结构: 代码实现: 1.fragment_main.xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="matc

ViewPager实现页卡的2种方法(谷歌组件)

----方法一:---- 效果图: 需要的组件: ViewPager+PagerTabStrip 布局文件代码: <!--xmlns:android_custom="http://schemas.android.com/apk/res/com.pengkv.bigo"--> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layou

ViewPager 滑动页(二)

需求:滑动展示页,能够使用本地数据,及获取服务器数据进行刷新操作,并实现页面自动切换: 效果图: 实现分析: 1.目录结构: 代码实现: 1.PosterView.java package com.jjc.demo; import java.util.ArrayList; import java.util.List; import android.content.Context; import android.os.Handler; import android.os.Looper; impor

ViewPager 滑动页(三)

需求:滑动展示页,能够使用本地数据,及获取服务器数据进行刷新操作,当滑动到最后一页时,结束当前activity,进入下一个activity: 效果图: 实现分析: 1.目录结构: 代码实现: 1.PosterView.java package com.jjc.demo; import java.util.ArrayList; import java.util.List; import android.app.Activity; import android.content.Context; im