ViewPage最全解析
简单说明:
ViewPager是android扩展包v4包中的类,直接继承了ViewGroup类,和LinearLayout等布局一样,都是一个容器,需要在里面添加我们想要显示的内容。
一、在xml中添加ViewPager
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@id/bannerContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"> <android.support.v4.view.ViewPager
android:id="@id/bannerViewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false" />
注:除了通过xml代码来定义一个ViewPager外,同其他控件一样也可以动态添加。
二、定义ViewPageAdapter
1、可以在构造函数中传递ViewPager需要加载显示的数据。
2、必须重载的函数:
a) Determines whether a page View is associated with a specific key object return by instantiateItem(ViewGroup ,int)
public abstract boolean isViewFromObject(View view, Object object);
b) 获取Pager的总页数
/**
* Return the number of views available.
*/
public abstract int getCount();
c)干函数中需要将 页面需要加载的内容添加到container中,同时将需要加载的view返回。该函数是PagerAdapter的核心,具体可以参照下面代码
/**
* Create the page for the given position. The adapter is responsible
* for adding the view to the container given here, although it only
* must ensure this is done by the time it returns from
* {@link #finishUpdate(ViewGroup)}.
*
* @param container The containing View in which the page will be shown.
* @param position The page position to be instantiated.
* @return Returns an Object representing the new page. This does not
* need to be a View, but can be some other container of the page.
*/
public Object instantiateItem(ViewGroup container, int position) {
return instantiateItem((View) container, position);
}
d)该函数负责对ViewGroup中已经添加的部分资源进行回收
(遇到过当没有重载该函数时,滑动到图片页数第三张时,activity自动结束返回到上一个Activity。具体原因有待分析)
/**
* Remove a page for the given position. The adapter is responsible
* for removing the view from its container, although it only must ensure
* this is done by the time it returns from {@link #finishUpdate(ViewGroup)}.
*
* @param container The containing View from which the page will be removed.
* @param position The page position to be removed.
* @param object The same object that was returned by
* {@link #instantiateItem(View, int)}.
*/
public void destroyItem(ViewGroup container, int position, Object object) {
destroyItem((View) container, position, object);
}
e) destoryItem() 和 instantiateItem() 执行顺序问题:下图为 移动一个viewpage时 这两个函数打印的 position

ViewPager启动时,第一个和第二个页面已经加载完成。
当再次滑动时,先加载第三个页面,然后再销毁第一个页面。(如果这时返回第1个页面,则先加载第一个页面再销毁第三个页面)
总之,除了第一个后最后一个页面外,ViewPager总会保持左右两侧的页面已经加载完成。
3、 PagerAdapter 还有 FragementPagerAdapter 用于加载Fragment。 (用普通的PagerAdapter加载Fragment的区别)
FragementStatePagerAdapter : 当页数较多时还可以使用该Adapter。
PagerAdapter的实现代码:
/**
* PagerAdapter的实现
* */
public class DripPageGuideAdapter extends PagerAdapter { @Override
public Object instantiateItem(ViewGroup container, int position) {
container.addView(mViews.get(position));
return mViews.get(position);
} @Override
public int getCount() {
return totalSize;
} @Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
} @Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View)object);
}
}
三、 activity中定义viewpage,始化相关控件,并绑定二中定义的adapter
1、加载ViewPager,绑定Adapter
public class ViewPageActivity extends Activity {
private ViewPager viewPager;
private ViewPageAdapter adapter;
private Set<String> citiesSHaredPreference;
private Context context = ViewPageActivity.this;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_viewpage);
citiesSHaredPreference = new HashSet<String>();
citiesSHaredPreference.add("huoshan");
citiesSHaredPreference.add("hefei");
citiesSHaredPreference.add("shanghai");
initLoadData();
initView();
}
private void initLoadData(){
for(int i=0;i<citiesSHaredPreference.size();i++){
}
}
private void initView() {
viewPager = (ViewPager) findViewById(R.id.viewpage);
adapter = new ViewPageAdapter(context,citiesSHaredPreference);
viewPager.setAdapter(adapter);
}
}
当在adapter中添加图片时,如果要想图片适应ViewPager大小,需要设置: imageView.setScaleType(ImageView.ScaleType.FIT_XY);
2、可以在布局中添加页面指示器: 圆圈/数字/横线,并且当滑动到某一页面时,指示器颜色出现变化。
void createIndicator() {
List<ImageView> indicatorImages = new ArrayList<>();
for (int i = 0; i < 2; i++) {
ImageView imageView = new ImageView(mContext);
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(90, 90);
params.leftMargin = 5;
params.rightMargin = 5;
if (i == 0) {
//imageView.setImageResource(R.drawable.gray_radius);
imageView.setImageDrawable(IndicatorShapes.getGrayShape());
} else {
imageView.setImageDrawable(IndicatorShapes.getWhiteShape());
}
indicatorImages.add(imageView);
mIndicator.addView(imageView, params);
}
}
仅仅初始化指示器还不够,还需要在滑动页面的时候指示器的颜色也跟随着改变,要达到此效果需设置viewpager的监听器:
定一个lastPosition变量,初始值为0,当页面滑动时,需要把上一页面的指示器颜色恢复,同时设置当前页面为选中状态。
mViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
if(GuideConfig.isShowIndicator){
indicatorImages.get((lastPosition + totalSize) % totalSize).setImageDrawable(IndicatorShapes.getUnselectedShape());
indicatorImages.get((position + totalSize) % totalSize).setImageDrawable(IndicatorShapes.getSelectedShape());
}
lastPosition = position;
mListener.onPageSelected(totalSize,position);
}
@Override
public void onPageScrollStateChanged(int state) {
}
}
});
指示器开源库推荐:
a、 安卓大神的 : https://github.com/JakeWharton/ViewPagerIndicator
该库长时间没有维护,因为是大神的所以放在第一个
b、一个比我还年轻的人写的,自惭形秽:https://github.com/hackware1993/MagicIndicator
3、滑动到最后页面再滑动监听事件: 很多业务需要当再滑动最后一个页面时需要跳转到下一个Activity的需求
那么如何实现呢,其实就是在上面的监听接口中就能实现,可参考:http://blog.csdn.net/nn955/article/details/46240371
4、滑动到最后页面继续向左拖动时,会有 半透明的条出现,如何禁止该条的出现
四、ViewPager setOnPageChangeListener方法
OnPageChangeListener接口中定义了三个函数:
1.onPageSelected(int position):这个方法有一个参数position,代表哪个页面被选中。当用手指滑动翻页的时候,如果翻动成功了(滑动的距离够长),手指抬起来就会立即执行这个方法,position就是当前滑动到的页面。如果直接setCurrentItem翻页,那position就和setCurrentItem的参数一致,这种情况在onPageScrolled执行方法前就会立即执行。
2.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一致。
3.onPageScrollStateChanged(int state):这个方法在手指操作屏幕的时候发生变化。有三个值:0(END),1(PRESS) , 2(UP) 。
当用手指滑动翻页时,手指按下去的时候会触发这个方法,state值为1,手指抬起时,如果发生了滑动(即使很小),这个值会变为2,然后最后变为0 。总共执行这个方法三次。一种特殊情况是手指按下去以后一点滑动也没有发生,这个时候只会调用这个方法两次,state值分别是1,0 。
当setCurrentItem翻页时,会执行这个方法两次,state值分别为2 , 0 。
三个方法的执行顺序为:用手指拖动翻页时,最先执行一遍onPageScrollStateChanged(1),然后不断执行onPageScrolled,放手指的时候,直接立即执行一次onPageScrollStateChanged(2),然后立即执行一次onPageSelected,然后再不断执行onPageScrollStateChanged,最后执行一次onPageScrollStateChanged(0)。
易忽视问题:
OnPageSelected 方法会有一个问题,当ViewPager第一个页面显示(position 为0)的时候该方法不会被调用。解决办法:
将OnPageSelected 定义成一个私有成员变量,在调用mViewPager.setOnPageChangeListener(mOnPagerChageListener)之后马上调用
mOnPageChangeListener.OnPageSelected(0);
五、如何给页面滑动添加自定义的动画
六、OOM问题
当ViewPager滑动图片较多或者图片较大时容易出现OOM,那么如何优化图片加载呢:
七、关于ViewPager相关的开源库推荐
1、广告轮播,可循环自动播放: https://github.com/youth5201314/banner
2、基于ViewPage的引导页面例子: https://github.com/matrixxun/ProductTour
上面两个只是很实用的库,github上很多炫酷的viewPager效果,有时间可以研究下。
ViewPage最全解析的更多相关文章
- Google Maps地图投影全解析(3):WKT形式表示
update20090601:EPSG对该投影的编号设定为EPSG:3857,对应的WKT也发生了变化,下文不再修改,相对来说格式都是那样,可以到http://www.epsg-registry.or ...
- C#系统缓存全解析(转载)
C#系统缓存全解析 对各种缓存的应用场景和方法做了很详尽的解读,这里推荐一下 转载地址:http://blog.csdn.net/wyxhd2008/article/details/8076105
- 【凯子哥带你学Framework】Activity界面显示全解析
前几天凯子哥写的Framework层的解析文章<Activity启动过程全解析>,反响还不错,这说明“写让大家都能看懂的Framework解析文章”的思想是基本正确的. 我个人觉得,深入分 ...
- iOS Storyboard全解析
来源:http://iaiai.iteye.com/blog/1493956 Storyboard)是一个能够节省你很多设计手机App界面时间的新特性,下面,为了简明的说明Storyboard的效果, ...
- 【转载】Fragment 全解析(1):那些年踩过的坑
http://www.jianshu.com/p/d9143a92ad94 Fragment系列文章:1.Fragment全解析系列(一):那些年踩过的坑2.Fragment全解析系列(二):正确的使 ...
- (转)ASP.NET缓存全解析6:数据库缓存依赖
ASP.NET缓存全解析文章索引 ASP.NET缓存全解析1:缓存的概述 ASP.NET缓存全解析2:页面输出缓存 ASP.NET缓存全解析3:页面局部缓存 ASP.NET缓存全解析4:应用程序数据缓 ...
- jQuery Ajax 实例 全解析
jQuery Ajax 实例 全解析 jQuery确实是一个挺好的轻量级的JS框架,能帮助我们快速的开发JS应用,并在一定程度上改变了我们写JavaScript代码的习惯. 废话少说,直接进入正题,我 ...
- ARM内核全解析,从ARM7,ARM9到Cortex-A7,A8,A9,A12,A15到Cortex-A53,A57
转自: ARM内核全解析,从ARM7,ARM9到Cortex-A7,A8,A9,A12,A15到Cortex-A53,A57 前不久ARM正式宣布推出新款ARMv8架构的Cortex-A50处理器系列 ...
- jQuery Ajax 全解析
转自:http://www.cnblogs.com/qleelulu/archive/2008/04/21/1163021.html 本文地址: jQuery Ajax 全解析 本文作者:QLeelu ...
随机推荐
- 动态渲染的input怎么取消记忆功能
方法1 :自定义去除记忆功能属性: $('#index_table_filter > label > input[type="search"]').attr('auto ...
- 批处理(bat)的注释方法
前面两个批处理教程的转贴,写得实在是太好了,内容详实,语言风趣,举例清晰.说实话,原作者幽默的文风用来写 批处理教程,而不是写文学小说,实在是有些屈才,但这样优秀的教程,用在枯燥乏味的程序事业里,确实 ...
- Object-C中方法
//方法 //方法分了两种 //1.类方法,类调用,方法以+开头 //2.实例方法,对象调用,方法以-开头 //类方法和实例方 ...
- hdu 2190 悼念512汶川大地震遇难同胞——重建希望小学
题目 这道题拿到的时候拼凑了一会,感觉挺难的,然后博客说是:递推,我觉得递推其实就是找规律. 这是别人的思路:对于n米的长度,可以是由n-1长度加1而来,对于增加的1,只有三块1*1的砖一种铺法: 还 ...
- H3C交换机流量镜像
今天需要对交换机进行本地流量镜像,在此记录: 交换机:H3C S5120 配置本地端口镜像时,用户首先要创建一个本地镜像组,然后为本地镜像组配置源端口和目的端口. 表1-1 配置本地端口镜像 操作 命 ...
- EBS trace分析
下载Trace Analyzer,打开bin下的traceanalyzer.bat 即可分析EBS的trace文件,图形化界面,无需tkprof 需要配置javahome,确认java版本为1.6以上 ...
- C++互斥器:Mutex
互斥器的功能是,使多个线程和谐工作.同一时间内,只能有一个线程得到互斥对象,并获得资源操作权限,那么如果同一时间其他线程也想去操作资源,此时就会因为Mutex未处于激发状态,而无奈的等待…这时候,线程 ...
- VS2010+Oracle11+Entity Framework4.1环境搭建及常见问题
在微软的实体数据模型中存在四种查询方式: SQL字符串:Linq:Linq to SQL:Linq to Entity(ESQL) 对于Linq SQL目前微软虽然仍在支持,但微软已经声明不再推荐. ...
- 挂起的更改中的“解析”是什么意思?原来是微软错误的翻译
[2017.4.5 补充] 收到微软TFS产品组的回复,由于版本分支丢失了本来已经修复的内容,并确认下一个版本将修复这个问题. 自从团队资源管理器的"挂起的更改中"可以链接相关工作 ...
- .NET在IE10下的回传BUG修复
以前我也没注意到,直到有次公司新配了台机器做测试服务器,在测试过程中意外发现凡是涉及PostBack的操作仅在IE10下都无效,其他版本浏览器都没有问题,本机调试也没有问题. 这也就是说在程序相同的情 ...