当前位置:

首页 > 系统应用 > 2.6.3 ViewPager的简单使用

2.6.3 ViewPager的简单使用

本文目录

    本节引言: 这一节要说的,是 Android 3.0 之后引入的一个 UI 控件——ViewPager(视图滑动切换工具)。这个名字其实已经把作用点得很明白了:它的核心能力,就是通过手势滑动来完成 View 之间的切换。实际开发里,这个控件很常见,APP 引导页、图片轮播这类场景,基本都少不了它。也

    本节引言:

    这一节要说的,是 Android 3.0 之后引入的一个 UI 控件——ViewPager(视图滑动切换工具)。这个名字其实已经把作用点得很明白了:它的核心能力,就是通过手势滑动来完成 View 之间的切换。实际开发里,这个控件很常见,APP 引导页、图片轮播这类场景,基本都少不了它。也正因为它是在 3.0 之后才加入的,如果要在更低版本中使用,就需要引入 v4 兼容包。从包路径里也能看出来,ViewPager 位于:android.support.v4.view.ViewPager。接下来,就顺着这个思路看看它的基本用法。官方API文档:ViewPager

    1.ViewPager的简单介绍

    ViewPager本质上就是一个很直观的页面切换组件:往里面塞入多个View之后,用户通过左右滑动,就能在不同的View之间来回切换。它还提供了setPageTransformer()方法,用来给ViewPager配置切换时的动画效果。不过动画这一块暂时还没展开,所以这部分先放到下一章“绘图与动画”里再细讲。它的使用方式和前面接触过的ListView、GridView其实是一脉相承的——同样需要借助一个Adapter(适配器)来完成View和ViewPager之间的绑定,而ViewPager对应的专用适配器,就是PagerAdapter。另外,Google官方更推荐使用Fragment来填充ViewPager,这样在生成每一个Page时会更方便,对每个Page生命周期的管理也更清晰。为此,系统还专门提供了两个面向Fragment的Adapter:FragmentPageAdapter和FragmentStatePagerAdapter。下面就来简单看看,这两个Adapter到底有什么区别。

    • FragmentPageAdapter:和PagerAdapter一样,只会缓存当前的Fragment以及左边一个,右边 一个,即总共会缓存3个Fragment而已,假如有1,2,3,4四个页面:
      处于1页面:缓存1,2
      处于2页面:缓存1,2,3
      处于3页面:销毁1页面,缓存2,3,4
      处于4页面:销毁2页面,缓存3,4
      更多页面的情况,依次类推~
    • FragmentStatePagerAdapter:当Fragment对用户不 见得时,整个Fragment会被销毁, 只会保存Fragment的状态!而在页面需要重新显示的时候,会生成新的页面!

    综上,FragmentPageAdapter适合固定的页面较少的场合;而FragmentStatePagerAdapter则适合 于页面较多或者页面内容非常复杂(需占用大量内存)的情况!

    2.PagerAdapter的使用

    我们先来介绍最普通的PagerAdapter,如果想使用这个PagerAdapter需要重写下面的四个方法: 当然,这只是官方建议,实际上我们只需重写getCount()和isViewFromObject()就可以了~

    • getCount():获得viewpager中有多少个view
    • destroyItem():移除一个给定位置的页面。适配器有责任从容器中删除这个视图。 这是为了确保在finishUpdate(viewGroup)返回时视图能够被移除。

    而另外两个方法则是涉及到一个key的东东:

    • instantiateItem(): ①将给定位置的view添加到ViewGroup(容器)中,创建并显示出来 ②返回一个代表新增页面的Object(key),通常都是直接返回view本身就可以了,当然你也可以 自定义自己的key,但是key和每个view要一一对应的关系
    • isViewFromObject(): 判断instantiateItem(ViewGroup, int)函数所返回来的Key与一个页面视图是否是 代表的同一个视图(即它俩是否是对应的,对应的表示同一个View),通常我们直接写 return view == object!

    使用示例1:最简单用法

    运行效果图:

    关键部分代码:

    好的,代码写起来也是非常简单的:首先是每个View的布局,一式三份,另外两个View一样:

    view_one.xml:

    
    
    
      

    然后编写一个自定义个的PagerAdapter:

    MyPagerAdapter.ja va:

    public class MyPagerAdapter extends PagerAdapter {
        private ArrayList viewLists;
    public MyPagerAdapter() {
        }
    public MyPagerAdapter(ArrayList viewLists) {
            super();
            this.viewLists = viewLists;
        }
    @Override
        public int getCount() {
            return viewLists.size();
        }
    @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == object;
        }
    @Override
        public Object instantiateItem(ViewGroup container, int position) {
            container.addView(viewLists.get(position));
            return viewLists.get(position);
        }
    @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView(viewLists.get(position));
        }
    }

    接着到Activity了,和以前学的ListView非常类似:

    OneActivity.ja va:

    public class OneActivity extends AppCompatActivity{
    private ViewPager vpager_one;
        private ArrayList aList;
        private MyPagerAdapter mAdapter;
    @Override
        protected void onCreate(Bundle sa vedInstanceState) {
            super.onCreate(sa vedInstanceState);
            setContentView(R.layout.activity_one);
            vpager_one = (ViewPager) findViewById(R.id.vpager_one);
    aList = new ArrayList();
            LayoutInflater li = getLayoutInflater();
            aList.add(li.inflate(R.layout.view_one,null,false));
            aList.add(li.inflate(R.layout.view_two,null,false));
            aList.add(li.inflate(R.layout.view_three,null,false));
            mAdapter = new MyPagerAdapter(aList);
            vpager_one.setAdapter(mAdapter);
        }
    }

    好的,关键代码就上述部分,非常容易理解~

    使用示例2:标题栏——PagerTitleStrip与PagerTabStrip

    就是跟随着ViewPager滑动而滑动的标题咯,这两个是官方提供的,一个是普通文字, 一个是带有下划线,以及可以点击文字可切换页面,下面我们来写个简单的例子~

    运行效果图:

    关键代码实现:

    这里两者的区别仅仅是布局不一样而已,其他的都一样:

    PagerTitleStrip所在Activtiy的布局: activity_two.xml:

    
    
    
    
       
     

    而PagerTabStrip所在的布局:

    activity_three.xml:

    
    
    
    
         
    

    接下来的两者都一样了,我们先来编写一个自定义的PagerAdapter,除了前面重写的 四个方法外,我们需要另外重写一个方法:getPageTitle(),这个设置标题的~ 代码如下:

    MyPagerAdapter2.ja va:

    /**
     * Created by Jay on 2015/10/8 0008.
     */
    public class MyPagerAdapter2 extends PagerAdapter {
        private ArrayList viewLists;
        private ArrayList titleLists;
    public MyPagerAdapter2() {}
        public MyPagerAdapter2(ArrayList viewLists,ArrayList titleLists)
        {
            this.viewLists = viewLists;
            this.titleLists = titleLists;
        }
    @Override
        public int getCount() {
            return viewLists.size();
        }
    @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == object;
        }
    @Override
        public Object instantiateItem(ViewGroup container, int position) {
            container.addView(viewLists.get(position));
            return viewLists.get(position);
        }
    @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView(viewLists.get(position));
        }
    @Override
        public CharSequence getPageTitle(int position) {
            return titleLists.get(position);
        }
    }

    最后是Activity部分,两个都是一样的:

    TwoActivity.ja va:

    /**
     * Created by Jay on 2015/10/8 0008.
     */
    public class TwoActivity extends AppCompatActivity {
    private ViewPager vpager_two;
        private ArrayList aList;
        private ArrayList sList;
        private MyPagerAdapter2 mAdapter;
    @Override
        public void onCreate(Bundle sa vedInstanceState) {
            super.onCreate(sa vedInstanceState);
            setContentView(R.layout.activity_two);
            vpager_two = (ViewPager) findViewById(R.id.vpager_two);
            aList = new ArrayList();
            LayoutInflater li = getLayoutInflater();
            aList.add(li.inflate(R.layout.view_one,null,false));
            aList.add(li.inflate(R.layout.view_two,null,false));
            aList.add(li.inflate(R.layout.view_three, null, false));
            sList = new ArrayList();
            sList.add("橘黄");
            sList.add("淡黄");
            sList.add("浅棕");
            mAdapter = new MyPagerAdapter2(aList,sList);
            vpager_two.setAdapter(mAdapter);
        }
    }

    好了,非常简单,有疑问的话,自己下demo看看就懂了~

    使用示例3:ViewPager实现TabHost的效果:

    当然,示例2很多时候,只是中看不中用,实际开发中我们可能需要自行定制这个标题栏, 下面我们就来写个简单的例子来实现TabHost的效果,如果你不知道TabHost是什么鬼的 话,那么,请看效果图!

    运行效果图:

    实现逻辑解析:

    下面我们来讲解下实现上述效果的逻辑,然后贴代码:

    首先是布局:顶部一个LinearLayout,包着三个TextView,weight属性都为1,然后下面跟着 一个滑块的ImageView,我们设置宽度为match_parent;最底下是我们的ViewPager,这里可能 有两个属性你并不认识,一个是:flipInterval:这个是指定View动画间的时间间隔的!
    而persistentDrawingCache:则是设置控件的绘制缓存策略,可选值有四个:

    • none:不在内存中保存绘图缓存;
    • animation:只保存动画绘图缓存;
    • scrolling:只保存滚动效果绘图缓存;
    • all:所有的绘图缓存都应该保存在内存中;
    可以同时用2个,animation|scrolling这样~

    布局代码:activity_four.xml:

    
    
    
    
    
        
    
    
     

    接着到我们的Activity了,我们来捋下思路:

    • Step 1:我们需要让我们的移动块在第一个文字下居中,那这里就要算一下偏移量: 先获得图片宽度pw,然后获取屏幕宽度sw,计算方法很简单:
      offset(偏移量) = ((sw / 3)-pw) / 2 //屏幕宽/3 - 图片宽度,然后再除以2,左右嘛!
      然后我么你调用setImageMatrix设置滑块当前的位置:
      同时我们也把切换一页和两页,滑块的移动距离也算出来,很简单:
      one = offset * 2 + pw;
      two = one * 2;

    • Step 2:当我们滑动页面时,我们的滑块要进行移动,我们要为ViewPager添加一个 OnPageChangeListener事件,我们需要对滑动后的页面来做一个判断,同时记录滑动前处于 哪个页面,下面自己画了个图,可能更容易理解吧!

    PS:太久没写字,字很丑,能看清就好,字丑人美,哈哈~

    嗯,如果还是不能理解的话,自己动手画画图就知道了,下面上代码:

    FourActvitiy.ja va:

    /**
     * Created by Jay on 2015/10/8 0008.
     */
    public class FourActivity extends AppCompatActivity implements View.OnClickListener,
            ViewPager.OnPageChangeListener {
    private ViewPager vpager_four;
        private ImageView img_cursor;
        private TextView tv_one;
        private TextView tv_two;
        private TextView tv_three;
    private ArrayList listViews;
        private int offset = 0;//移动条图片的偏移量
        private int currIndex = 0;//当前页面的编号
        private int bmpWidth;// 移动条图片的长度
        private int one = 0; //移动条滑动一页的距离
        private int two = 0; //滑动条移动两页的距离
    @Override
        public void onCreate(Bundle sa vedInstanceState) {
            super.onCreate(sa vedInstanceState);
            setContentView(R.layout.activity_four);
            initViews();
        }
    private void initViews() {
            vpager_four = (ViewPager) findViewById(R.id.vpager_four);
            tv_one = (TextView) findViewById(R.id.tv_one);
            tv_two = (TextView) findViewById(R.id.tv_two);
            tv_three = (TextView) findViewById(R.id.tv_three);
            img_cursor = (ImageView) findViewById(R.id.img_cursor);
    //下划线动画的相关设置:
            bmpWidth = BitmapFactory.decodeResource(getResources(), R.mipmap.line).getWidth();// 获取图片宽度
            DisplayMetrics dm = new DisplayMetrics();
            getWindowManager().getDefaultDisplay().getMetrics(dm);
            int screenW = dm.widthPixels;// 获取分辨率宽度
            offset = (screenW / 3 - bmpWidth) / 2;// 计算偏移量
            Matrix matrix = new Matrix();
            matrix.postTranslate(offset, 0);
            img_cursor.setImageMatrix(matrix);// 设置动画初始位置
            //移动的距离
            one = offset * 2 + bmpWidth;// 移动一页的偏移量,比如1->2,或者2->3
            two = one * 2;// 移动两页的偏移量,比如1直接跳3
    //往ViewPager填充View,同时设置点击事件与页面切换事件
            listViews = new ArrayList();
            LayoutInflater mInflater = getLayoutInflater();
            listViews.add(mInflater.inflate(R.layout.view_one, null, false));
            listViews.add(mInflater.inflate(R.layout.view_two, null, false));
            listViews.add(mInflater.inflate(R.layout.view_three, null, false));
            vpager_four.setAdapter(new MyPagerAdapter(listViews));
            vpager_four.setCurrentItem(0);          //设置ViewPager当前页,从0开始算
    tv_one.setOnClickListener(this);
            tv_two.setOnClickListener(this);
            tv_three.setOnClickListener(this);
    vpager_four.addOnPageChangeListener(this);
        }
    @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.tv_one:
                    vpager_four.setCurrentItem(0);
                    break;
                case R.id.tv_two:
                    vpager_four.setCurrentItem(1);
                    break;
                case R.id.tv_three:
                    vpager_four.setCurrentItem(2);
                    break;
            }
        }
    @Override
        public void onPageSelected(int index) {
            Animation animation = null;
            switch (index) {
                case 0:
                    if (currIndex == 1) {
                        animation = new TranslateAnimation(one, 0, 0, 0);
                    } else if (currIndex == 2) {
                        animation = new TranslateAnimation(two, 0, 0, 0);
                    }
                    break;
                case 1:
                    if (currIndex == 0) {
                        animation = new TranslateAnimation(offset, one, 0, 0);
                    } else if (currIndex == 2) {
                        animation = new TranslateAnimation(two, one, 0, 0);
                    }
                    break;
                case 2:
                    if (currIndex == 0) {
                        animation = new TranslateAnimation(offset, two, 0, 0);
                    } else if (currIndex == 1) {
                        animation = new TranslateAnimation(one, two, 0, 0);
                    }
                    break;
            }
            currIndex = index;
            animation.setFillAfter(true);// true表示图片停在动画结束位置
            animation.setDuration(300); //设置动画时间为300毫秒
            img_cursor.startAnimation(animation);//开始动画
        }
    @Override
        public void onPageScrollStateChanged(int i) {
    }
    @Override
        public void onPageScrolled(int i, float v, int i1) {
    }
    }

    嗯,关于动画可能你并不熟悉,没事,下一章我们带大家一起扣~

    3.ViewPager结合Fragment示例

    嗯,在前面讲解Fragment的时候我们就讲解了一个使用示例: Android基础入门教程——5.2.4 Fragment实例精讲——底部导航栏+ViewPager滑动切换页面 这里就不再详述了,有兴趣的点下链接看看即可~

    4.代码示例下载

    ViewPagerDemo.zip

    本节小结:

    关于ViewPager,限于篇幅,有些地方并没有讲到,其他的大家需要自己查阅文档了~

    另外,上面也说了,ViewPager的动画我们会在下一章讲解!好的,就说这么多~

    嗯,国庆前曾说会在国庆假期里完成整个系列,结果一篇都没写,实在抱歉... 因为妹子过来玩了,So,你懂的~,会加快进度~,争取早日进阶!

    本文内容来源于网友投稿,如有侵权请联系删除。
    作者最新文章
    系统应用
    下一篇: 2.6.2 菜单(Menu)
    相关文章 更多
    docker容器自动重启怎么解决 排查原因与修复方法
    docker容器自动重启怎么解决 排查原因与修复方法

    遇到Docker容器频繁自动重启?本文提供从查看容器日志、解读退出代码到配置Restart Policy的完整排查与修复方案,确保服务稳定性。

    Linux设置静态路由命令与永久生效教程
    Linux设置静态路由命令与永久生效教程

    学习如何在Linux中使用命令行添加临时静态路由,并通过修改网络配置文件实现重启后依然有效的永久静态路由设置,涵盖CentOS和Ubuntu的不同配置方法。

    摄像头连接电脑后怎么打开查看实时画面教程
    摄像头连接电脑后怎么打开查看实时画面教程

    摄像头连接电脑后不知如何查看画面?本教程演示如何使用Windows自带的“相机”应用快速调取实时视频流,无需下载额外软件,步骤简单直观,适用于大多数USB及内置摄像头。

    如何在 windows 11 关闭自动关机
    如何在 windows 11 关闭自动关机

    针对 Windows 11 电脑在无人操作时自动关机或重启的问题,本文详解如何通过任务计划程序禁用更新重启任务,并调整电源睡眠策略,从根源解决非预期的自动关机现象。

    电脑摄像头怎么测试人脸识别功能及效果判断方法
    电脑摄像头怎么测试人脸识别功能及效果判断方法

    详细讲解在Windows电脑上测试摄像头人脸识别功能的步骤,包括开启Windows Hello、录入面部数据、不同环境下的效果验证及常见问题排查,帮助用户确认设备兼容性与识别准确率。

    docker 容器无法启动的配置检查命令及排查方法
    docker 容器无法启动的配置检查命令及排查方法

    当 Docker 容器启动后立即退出时,不要盲目重启。本文详解如何通过 docker logs 查看标准输出错误,利用 docker inspect 检查挂载与网络配置,并修正入口点脚本权限问题,提供一套高效的因果排查流程。

    安卓手机投屏到电脑win10怎么设置教程
    安卓手机投屏到电脑win10怎么设置教程

    详解如何利用Windows 10自带功能将安卓手机画面投射至电脑屏幕,涵盖开启步骤、连接技巧及延迟分析,适合临时演示与多屏协作场景。

    移动硬盘解除加密怎么操作?详细步骤教程
    移动硬盘解除加密怎么操作?详细步骤教程

    详细介绍如何在Windows系统中为移动硬盘解除BitLocker加密,包括解锁驱动器、关闭加密功能及监控解密进度的完整操作流程,帮助用户安全移除数据保护。

    笔记本电脑耳机没声音怎么设置?Windows 10解决方法
    笔记本电脑耳机没声音怎么设置?Windows 10解决方法

    本文详解Windows 10笔记本耳机无声音的常见原因与解决方法,涵盖物理接口检查、默认播放设备切换、驱动程序更新及音频增强关闭等操作,并分析蓝牙耳机连接异常的例外场景。

    sata固态硬盘安装win10系统怎么分区详细教程
    sata固态硬盘安装win10系统怎么分区详细教程

    还在为SATA固态硬盘装Win10怎么分区头疼?本教程详解安装过程中的分区步骤,涵盖4K对齐检查、ESP引导分区处理及容量规划建议,助你一次性搞定系统盘,避免后期卡顿与空间浪费。

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    macOS软件
    macOS软件

    正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

    Mac软件 更多
    Blender
    Blender
    Windows、macOS 和 Linux

    Blender 是一款免费开源、跨平台的专业 3D 创作软件,集建模、动画、渲染、视频编辑与视觉合成等功能于一体,广泛应用于影视动画、游戏设计和建筑可视化等领域。软件支持 Cycles 物理渲染器与 Eevee 实时渲染引擎,并提供多边形建模、骨骼绑定、物理模拟等专业工具。Blender 兼容 Windows、macOS 和 Linux 系统,安装包轻巧、运行流畅,依托活跃的全球开发者社区持续更新,是从初学者到专业创作者都值得选择的正版 3D 创作工具。

    灵活计算器
    灵活计算器
    macOS/iOS/Android

    灵活计算器是一款笔记式算数应用,支持实时计算、动态关联和云端同步功能。记录、整理和输出之间的过渡会更自然,适合长期写作、做笔记或持续沉淀个人内容。

    赤友清理大师
    赤友清理大师
    macOS

    赤友清理大师是一款为 Mac 设计的智能清理优化工具,可精准扫描垃圾、大文件、重复文件等,释放磁盘空间。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

    WINDOWS 更多
    Blender
    Blender
    Windows、macOS 和 Linux

    Blender 是一款免费开源、跨平台的专业 3D 创作软件,集建模、动画、渲染、视频编辑与视觉合成等功能于一体,广泛应用于影视动画、游戏设计和建筑可视化等领域。软件支持 Cycles 物理渲染器与 Eevee 实时渲染引擎,并提供多边形建模、骨骼绑定、物理模拟等专业工具。Blender 兼容 Windows、macOS 和 Linux 系统,安装包轻巧、运行流畅,依托活跃的全球开发者社区持续更新,是从初学者到专业创作者都值得选择的正版 3D 创作工具。

    Windows 10
    Windows 10
    Windows

    Windows 10 是一款微软推出的经典操作系统,拥有硬件兼容性与多任务处理能力。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。

    极度公式
    极度公式
    Windows/macOS/Linux

    极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。