在很多APP第一次启动时都会出现引导页,在一些APP里面还会包括一些左右滑动翻页和页面轮播切换的情况。在之前也已经学习了AdapterViewFlipper和ViewFlipper,都可以很好的实现,今天继续来学习一个功能更加强大的ViewPager组件。

一、ViewPager简介

ViewPager是android扩展包v4包中的类,这个类可以让用户左右滑动切换当前的view。ViewPager继承自ViewGroup,也就是ViewPager是一个容器类,可以包含其他的View类。

ViewPager的主要方法有以下几个:

  • setAdapter(PagerAdapter adapter) :为ViewPager设置适配器,ViewPager有三种适配器,包括PagerAdapter、FragmentPagerAdapter、FragmentStatePagerAdapter,它们分别有不同的特性,本期会先来学习PagerAdapter。

  • setCurrentItem(int item) :设置显示item位置的界面。

  • setOffscreenPageLimit(int limit) :用来设置当前显示页面左右两边各缓存的页面数。

  • addOnPageChangeListener(OnPageChangeListener listener) :为ViewPager添加页面切换时的监听。

关于界面监听的内容,接下来对OnPageChangeListener中的方法进行说明:

  • onPageScrollStateChanged(int state) :该方法在手指操作屏幕的时候发生变化。有三个值:0(END)、1(PRESS) 、2(UP) 。当用手指滑动翻页时,手指按下去的时候会触发这个方法,state值为1,手指抬起时,如果发生了滑动(即使很小),这个值会变为2,然后最后变为0 。总共执行这个方法三次。一种特殊情况是手指按下去以后一点滑动也没有发生,这个时候只会调用这个方法两次,state值分别是1、0 。当setCurrentItem翻页时,会执行这个方法两次,state值分别为2 、0 。

  • onPageScrolled(int position, float positionOffset, int positionOffsetPixels) :该方法在滑动过程中将一直被调用,该方法的参数说明如下:

    • position:当用手指滑动时,如果手指按在页面上不动,position和当前页面index是一致的;如果手指向左拖动(相应页面向右翻动),这时候position大部分时间和当前页面是一致的,只有翻页成功的情况下最后一次调用才会变为目标页面;如果手指向右拖动(相应页面向左翻动),这时候position大部分时间和目标页面是一致的,只有翻页不成功的情况下最后一次调用才会变为原页面。当直接设置setCurrentItem翻页时,如果是相邻的情况(比如现在是第二个页面,跳到第一或者第三个页面),如果页面向右翻动,大部分时间是和当前页面是一致的,只有最后才变成目标页面;如果向左翻动,position和目标页面是一致的。这和用手指拖动页面翻动是基本一致的。如果不是相邻的情况,比如我从第一个页面跳到第三个页面,position先是0,然后逐步变成1,然后逐步变成2;我从第三个页面跳到第一个页面,position先是1,然后逐步变成0,并没有出现为2的情况。

    • positionOffset:当前页面滑动比例,如果页面向右翻动,这个值不断变大,最后在趋近1的情况后突变为0。如果页面向左翻动,这个值不断变小,最后变为0。

    • positionOffsetPixels:当前页面滑动像素,变化情况和positionOffset一致。

  • onPageSelected(int position) :position是被选中页面的索引,该方法在页面被选中或页面滑动足够距离切换到该页手指抬起时调用。

上面三个方法的执行顺序:用手指拖动翻页时,最先执行一遍onPageScrollStateChanged(1),然后不断执行onPageScrolled,放手指的时候,直接立即执行一次onPageScrollStateChanged(2),然后立即执行一次onPageSelected,然后再不断执行onPageScrollStateChanged,最后执行一次onPageScrollStateChanged(0)。

在大多数使用适配器的控件里,适配器相对于数据源和视图来说都更加复杂,同时也决定了这个控件主要的功能,ViewPager也不例外。实现一个PagerAdapter时,至少需要重写下面的4个方法:

  • getCount():返回有效视图的数量。

  • isViewFromObject(View, Object):决定一个页面view是否与instantiateItem(ViewGroup, int)方法返回的具体key对象相关联。

  • instantiateItem(ViewGroup, int):创建指定位置的页面视图。适配器有责任增加即将创建的View视图到给定的container中,确保在finishUpdate(viewGroup)返回时,增加视图的事情已经完成。

  • destroyItem(ViewGroup, int, Object):移除给定位置的view,适配器有责任将该view从container中移除,确保在finishUpdate(viewGroup)返回时,移除视图的事情已经完成。

除了上述4个方法,还有以下一些方法,可根据实际需要进行重写。

  • getItemPosition (Object object):当宿主视图尝试判断一项的位置是否改变时调用。如果给定项的位置没有改变则返回POSITION_UNCHANGED,如果该项不再存在于适配器中则返回POSITION_NONE。

  • startUpdate (ViewGroup container) :在展示的界面中有改变将要发生时调用。

  • finishUpdate (ViewGroup container):展示界面中的改变完成时调用。在这个时间点上,你必须确保所有的页面已被合适的从container中添加或移除。

  • notifyDataSetChanged ():该方法由应用程序在适配器数据改变时主动调用。

  • registerDataSetObserver (DataSetObserver observer):注册一个观察者去接收关联到适配器数据变化的回调。

  • unregisterDataSetObserver (DataSetObserver observer):反注册去接收关联到适配器数据变化的回调的观察者。

  • setPrimaryItem (ViewGroup container, int position, Object object):调用该方法去通知当前适配器的哪一项被考虑为“primary”,它是当前展示给用户的页面。

  • getPageTitle (int position):该方法由ViewPager在获取描述页面的标题时调用,默认返回null。

  • getPageWidth (int position):该方法返回给定页面的比例宽度,范围(0.f-1.f]。

  • saveState ():保存与适配器关联的实例状态,当当前UI状态需要重建时恢复。

  • restoreState (Parcelable state, ClassLoader loader):恢复之前由saveState ()保存的与适配器关联的实例状态。

ViewPager的具体使用类似于之前学习的列表类组件,首先构造适配器,然后提供数据源,最后加载适配器。

二、ViewPager示例

接下来通过一个简单的示例程序来学习ViewPager的使用。

继续使用WidgetSample工程的advancedviewsample模块,在app/main/res/layout/目录下创建viewpager_layout.xml文件,在其中填充如下代码片段:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.view.ViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</android.support.v4.view.ViewPager>
</LinearLayout>

然后新建几个页面文件,第一个页面命名为viewpager_pager1.xml,其代码如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"> <ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@drawable/image_01"/>
</RelativeLayout>

另外再新建3个,为了简单布局和上面一样,将其中的代码加载的图片换一下即可。

新建ViewPagerAdapter类,继承PagerAdapter,并重写其方法,代码如下:

package com.jinyu.cqkxzsxy.android.advancedviewsample.adapter;

import android.support.v4.view.PagerAdapter;
import android.view.View;
import android.view.ViewGroup; import java.util.ArrayList; /**
* @创建者 鑫鱻
* @描述 Android零基础入门到精通系列教程
* 首发微信公众号分享达人秀(ShareExpert)
*/
public class ViewPagerAdapter extends PagerAdapter {
private ArrayList<View> mPageList = null; public ViewPagerAdapter(ArrayList<View> pageList) {
this.mPageList = pageList;
} @Override
public int getCount() {
return mPageList.size();
} @Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
} @Override
public Object instantiateItem(ViewGroup container, int position) {
View pageView = mPageList.get(position);
container.addView(pageView);
return pageView;
} @Override
public void destroyItem(ViewGroup container, int position, Object object) {
// 将当前位置的View移除
container.removeView(mPageList.get(position));
}
}

新建ViewPagerActivity.java文件,加载上面新建的布局文件,具体代码如下:

package com.jinyu.cqkxzsxy.android.advancedviewsample;

import android.os.Bundle;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Toast; import com.jinyu.cqkxzsxy.android.advancedviewsample.adapter.ViewPagerAdapter; import java.util.ArrayList; /**
* @创建者 鑫鱻
* @描述 Android零基础入门到精通系列教程,欢迎关注微信公众号ShareExpert
*/
public class ViewPagerActivity extends AppCompatActivity implements ViewPager.OnPageChangeListener {
private ViewPager mViewPager = null;
private ViewPagerAdapter mAdapter = null;
private ArrayList<View> mPageList = null; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.viewpager_layout); mViewPager = (ViewPager) findViewById(R.id.view_pager); mPageList = new ArrayList<>();
LayoutInflater inflater = getLayoutInflater();
mPageList.add(inflater.inflate(R.layout.viewpager_page1, null, false));
mPageList.add(inflater.inflate(R.layout.viewpager_page2, null, false));
mPageList.add(inflater.inflate(R.layout.viewpager_page3, null, false));
mPageList.add(inflater.inflate(R.layout.viewpager_page4, null, false)); mAdapter = new ViewPagerAdapter(mPageList);
mViewPager.setAdapter(mAdapter); mViewPager.addOnPageChangeListener(this);
} @Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override
public void onPageSelected(int position) {
Toast.makeText(this, "第" + (position + 1) + "页", Toast.LENGTH_SHORT).show();
} @Override
public void onPageScrollStateChanged(int state) { }
}

      修改程序启动的Activity,运行程序,然后左右滑动屏幕,可以看到下图所示界面效果。

不知道你是否发现,这是不是就是我们常见的应用程序启动时的引导页,只是示例相对来说比较简单,没有页面指示引导,这一块后续学习再逐步来优化完成。

今天就先到这里,如果有问题欢迎留言一起探讨,也欢迎加入Android零基础入门技术讨论微信群,共同成长!

此文章版权为微信公众号分享达人秀(ShareExpert)——鑫鱻所有,若需转载请联系作者授权,特此声明!

往期总结分享:

Android零基础入门第1节:Android的前世今生

Android零基础入门第2节:Android 系统架构和应用组件那些事

Android零基础入门第3节:带你一起来聊一聊Android开发环境

Android零基础入门第4节:正确安装和配置JDK, 高富帅养成第一招

Android零基础入门第5节:善用ADT Bundle, 轻松邂逅女神

Android零基础入门第6节:配置优化SDK Manager, 正式约会女神

Android零基础入门第7节:搞定Android模拟器,开启甜蜜之旅

Android零基础入门第8节:HelloWorld,我的第一趟旅程出发点

Android零基础入门第9节:Android应用实战,不懂代码也可以开发

Android零基础入门第10节:开发IDE大升级,终于迎来了Android Studio

Android零基础入门第11节:简单几步带你飞,运行Android Studio工程

Android零基础入门第12节:熟悉Android Studio界面,开始装逼卖萌

Android零基础入门第13节:Android Studio个性化配置,打造开发利器

Android零基础入门第14节:使用高速Genymotion,跨入火箭时代

Android零基础入门第15节:掌握Android Studio项目结构,扬帆起航

Android零基础入门第16节:Android用户界面开发概述

Android零基础入门第17节:文本框TextView

Android零基础入门第18节:输入框EditText

Android零基础入门第19节:按钮Button

Android零基础入门第20节:复选框CheckBox和单选按钮RadioButton

Android零基础入门第21节:开关组件ToggleButton和Switch

Android零基础入门第22节:图像视图ImageView

Android零基础入门第23节:图像按钮ImageButton和缩放按钮ZoomButton

Android零基础入门第24节:自定义View简单使用,打造属于你的控件

Android零基础入门第25节:简单且最常用的LinearLayout线性布局

Android零基础入门第26节:两种对齐方式,layout_gravity和gravity大不同

Android零基础入门第27节:正确使用padding和margin

Android零基础入门第28节:轻松掌握RelativeLayout相对布局

Android零基础入门第29节:善用TableLayout表格布局

Android零基础入门第30节:两分钟掌握FrameLayout帧布局

Android零基础入门第31节:少用的AbsoluteLayout绝对布局

Android零基础入门第32节:新推出的GridLayout网格布局

Android零基础入门第33节:Android事件处理概述

Android零基础入门第34节:Android中基于监听的事件处理

Android零基础入门第35节:Android中基于回调的事件处理

Android零基础入门第36节:Android系统事件的处理

Android零基础入门第37节:初识ListView

Android零基础入门第38节:初识Adapter

Android零基础入门第39节:ListActivity和自定义列表项

Android零基础入门第40节:自定义ArrayAdapter

Android零基础入门第41节:使用SimpleAdapter

Android零基础入门第42节:自定义BaseAdapter

Android零基础入门第43节:ListView优化和列表首尾使用

Android零基础入门第44节:ListView数据动态更新

Android零基础入门第45节:网格视图GridView

Android零基础入门第46节:列表选项框Spinner

Android零基础入门第47节:自动完成文本框AutoCompleteTextView

Android零基础入门第48节:可折叠列表ExpandableListView

Android零基础入门第49节:AdapterViewFlipper图片轮播

Android零基础入门第50节:StackView卡片堆叠

Android零基础入门第51节:进度条ProgressBar

Android零基础入门第52节:自定义ProgressBar炫酷进度条

Android零基础入门第53节:拖动条SeekBar和星级评分条RatingBar

Android零基础入门第54节:视图切换组件ViewSwitcher

Android零基础入门第55节:ImageSwitcher和TextSwitcher

Android零基础入门第56节:翻转视图ViewFlipper

Android零基础入门第57节:DatePicker和TimePicker选择器

Android零基础入门第58节:数值选择器NumberPicker

Android零基础入门第59节:常用三大Clock时钟组件

Android零基础入门第60节:日历视图CalendarView和定时器Chronometer

Android零基础入门第61节:滚动视图ScrollView

Android零基础入门第62节:搜索框组件SearchView

Android零基础入门第63节:值得借鉴学习的选项卡TabHost

Android零基础入门第64节:揭开RecyclerView庐山真面目

Android零基础入门第65节:RecyclerView分割线开发技巧

Android零基础入门第66节:RecyclerView点击事件处理

Android零基础入门第67节:RecyclerView数据动态更新

Android零基础入门第68节:RecyclerView添加首尾视图

Android零基础入门第69节:ViewPager快速实现引导页的更多相关文章

  1. Android零基础入门第70节:ViewPager轻松完成TabHost效果

    上一期学习了ViewPager的简单使用,本期一起来学习ViewPager的更多用法. 相信很多同学都使用过今日头条APP吧,一打开主界面就可以看到顶部有很多Tab,然后通过左右滑动来切换,就可以通过 ...

  2. Android零基础入门第89节:Fragment回退栈及弹出方法

    在上一期分享的文章末尾留了一个课后作业,有去思考如何解决吗?如果已经会了那么恭喜你,如果还不会也没关系,本期一起来学习. 一.回退栈 在前面两期的示例中,当我们完成一些操作后,如果想要回到操作之前的状 ...

  3. Android零基础入门第88节:Fragment显示和隐藏、绑定和解绑

    在上一期我们学习了FragmentManager和FragmentTransaction的作用,并用案例学习了Fragment的添加.移除和替换,本期一起来学习Fragment显示和隐藏.绑定和解绑. ...

  4. Android零基础入门第87节:Fragment添加、删除、替换

    前面一起学习了Fragment的创建和加载,以及其生命周期方法,那么接下来进一步来学习Fragment的具体使用,本期先来学习Fragment添加.删除.替换. 一.概述 在前面的学习中,特别是动态加 ...

  5. Android零基础入门第86节:探究Fragment生命周期

    一个Activity可以同时组合多个Fragment,一个Fragment也可被多个Activity 复用.Fragment可以响应自己的输入事件,并拥有自己的生命周期,但它们的生命周期直接被其所属的 ...

  6. Android零基础入门第85节:Fragment使用起来非常简单

    Fragment创建完成后并不能单独使用,还需要将Fragment加载到Activity中,在Activity中添加Fragment的方式有两种:静态加载和动态加载,接下来分别进行学习. 一.静态加载 ...

  7. Android零基础入门第84节:引入Fragment原来是这么回事

    随着大众生活水平的提高,再加上移动互联网的迅速发展,几乎每个人都至少拥有一台搭载Android系统的移动设备.Android设备的多样性给我们带来了很大的便捷,各Android设备拥有不同分辨率和不同 ...

  8. Android零基础入门第83节:Activity间数据传递方法汇总

    在Activity间传递的数据一般比较简单,但是有时候实际开发中也会传一些比较复杂的数据,本节一起来学习更多Activity间数据的传递. 一.常用数据类型 在前面几节我们只学习了一些常用类型的数据传 ...

  9. Android零基础入门第82节:Activity数据回传

    上一节学习了将简单的数据从MainActivity传递到SecondActivity,本节一起来学习数据如何从SecondActivity回传到MainActivity. 一.简介 前面己经提到,Ac ...

随机推荐

  1. Hibernate的数据操作(4.*以上版本)

    Hibernate的基本数据操作 适用于4.* ..sessionFactory的创建区别 public class NewsTest { private Session session = null ...

  2. 【基础练习】【线性DP】codevs1576 最长严格上升子序列题解

    连题目都不放了,就是标题中说的那样.裸题 于是直接上代码 暑假要来了 好好学习 --炉火照天地,红星乱紫烟. 赧郎明月夜.歌曲动寒川.

  3. CocoaPods详解之(二)----进阶篇

    CocoaPods详解之----进阶篇 作者:wangzz 原文地址:http://blog.csdn.net/wzzvictory/article/details/19178709 转载请注明出处 ...

  4. 一起学Python:网络通信过程

    1. 2台电脑的网络 image 说明 如果两台电脑之间通过网线连接是可以直接通信的,但是需要提前设置好ip地址以及网络掩码 并且ip地址需要控制在同一网段内,例如 一台为192.168.1.1另一台 ...

  5. 【27.34%】【codeforces 611D】New Year and Ancient Prophecy

    time limit per test2.5 seconds memory limit per test512 megabytes inputstandard input outputstandard ...

  6. mongdb aggregate 聚合数据

    最近用到的一些mongodb的数据查询方法 及api用法 Aggregate() 数据聚合处理的方法 可以将聚合的一些方法放在其后面的括号中,也可继续以agg.的样式链式加入 aggregate.al ...

  7. yii的简单片段缓存

    $dependency = [    'class' => 'yii\caching\DbDependency',    'sql' => 'SELECT MAX(u_id) FROM u ...

  8. 在动态THML语句中调用JS函数传递带空格参数的问题

    刚刚遇到一个问题,调用js函数的参数里带空格,造成调用失败的问题.   部分代码如下: html+="<div><a href=javascript:confirm(&qu ...

  9. ASP.NET Core 配置 MVC - ASP.NET Core 基础教程 - 简单教程,简单编程

    原文:ASP.NET Core 配置 MVC - ASP.NET Core 基础教程 - 简单教程,简单编程 ASP.NET Core 配置 MVC 前面几章节中,我们都是基于 ASP.NET 空项目 ...

  10. RTB业务知识2-Open-RTB全景

    一个.前言 openrtb这是一套开源的竞价广告系统,来自IAB贡献,井. 有许多值太借鉴,提供sdk api接口文档介绍,整理了相关的资料.主要包含其生态图体系.业务流程和基本的对象模型和数据模型. ...