ViewPager 详解(二)---详解四大函数
前言:上篇中我们讲解了如何快速实现了一个滑动页面,但问题在于,PageAdapter必须要重写的四个函数,它们都各有什么意义,在上节的函数内部为什么要这么实现,下面我们就结合Android的API说明,详细讲解一下。
相关文章:
3、《ViewPager 详解(三)---PagerTabStrip与PagerTitleStrip添加标题栏的异同》
4、《ViewPager 详解(四)----自主实现滑动指示条》
5、《ViewPager 详解(五)-----使用Fragment实现ViewPager滑动》
这篇涉及到内容比较多,因为有英文文档和中文文档,还有示例,在排版上很难驾驭(因为本人语文太烂……),所以排版有点非常的不赏心悦目,所以只能靠大家耐着性子慢慢看了……,我觉得大家看完之后应该会有所收获,谢谢。
一、SDK讲解
1、官方文档:(看不懂没关系,下面有翻译)
Class Overview
Base class providing the adapter to populate pages inside of a ViewPager
. You will most likely want to use a more specific implementation of this, such as FragmentPagerAdapter
orFragmentStatePagerAdapter
.
When you implement a PagerAdapter, you must override the following methods at minimum:
instantiateItem(ViewGroup, int)
destroyItem(ViewGroup, int, Object)
getCount()
isViewFromObject(View, Object)
PagerAdapter is more general than the adapters used for AdapterViews
. Instead of providing a View recycling mechanism directly ViewPager uses callbacks to indicate the steps taken during an update. A PagerAdapter may implement a form of View recycling if desired or use a more sophisticated method of managing page Views such as Fragment transactions where each page is represented by its own Fragment.
ViewPager associates each page with a key Object instead of working with Views directly. This key is used to track and uniquely identify a given page independent of its position in the adapter. A call to the PagerAdapter method startUpdate(ViewGroup)
indicates that the contents of the ViewPager are about to change. One or more calls to instantiateItem(ViewGroup, int)
and/ordestroyItem(ViewGroup, int, Object)
will follow, and the end of an update will be signaled by a call to finishUpdate(ViewGroup)
. By the time finishUpdate
returns the views associated with the key objects returned by instantiateItem
should be added to the parent ViewGroup passed to these methods and the views associated with the keys passed to destroyItem
should be removed. The method isViewFromObject(View, Object)
identifies whether a page View is associated with a given key object.
A very simple PagerAdapter may choose to use the page Views themselves as key objects, returning them from instantiateItem(ViewGroup, int)
after creation and adding them to the parent ViewGroup. A matching destroyItem(ViewGroup, int, Object)
implementation would remove the View from the parent ViewGroup and isViewFromObject(View, Object)
could be implemented as return view == object;
.
PagerAdapter supports data set changes. Data set changes must occur on the main thread and must end with a call to notifyDataSetChanged()
similar to AdapterView adapters derived fromBaseAdapter
. A data set change may involve pages being added, removed, or changing position. The ViewPager will keep the current page active provided the adapter implements the methodgetItemPosition(Object)
.
网址:http://developer.android.com/reference/android/support/v4/view/PagerAdapter.html
2、对应翻译
Class Overview
提供一个适配器用于填充ViewPager页面. 你很可能想要使用一个更加具体的实现, 例如: FragmentPagerAdapter
or FragmentStatePagerAdapter
.
当你实现一个PagerAdapter时,至少需要覆盖以下几个方法:
instantiateItem(ViewGroup, int)
destroyItem(ViewGroup, int, Object)
getCount()
isViewFromObject(View, Object)
PagerAdapter比AdapterView的使用更加普通.ViewPager使用回调函数来表示一个更新的步骤,而不是使用一个视图回收机制。在需要的时候pageradapter也可以实现视图的回收或者使用一种更为巧妙的方法来管理视图,比如采用可以管理自身视图的fragment。
网址:http://www.cnblogs.com/tony-yang-flutter/p/3591825.html
3、解析
看上面的翻译,与我们相关只有这两段话:
viewpager不直接处理每一个视图而是将各个视图与一个键联系起来。这个键用来跟踪且唯一代表一个页面,不仅如此,该键还独立于这个页面所在adapter的位置。当pageradapter将要改变的时候他会调用startUpdate函数,接下来会调用一次或多次的instantiateItem或者destroyItem。最后在更新的后期会调用finishUpdate。当finishUpdate返回时 instantiateItem返回的对象应该添加到父ViewGroup destroyItem返回的对象应该被ViewGroup删除。methodisViewFromObject(View, Object)代表了当前的页面是否与给定的键相关联。
对于非常简单的pageradapter或许你可以选择用page本身作为键,在创建并且添加到viewgroup后instantiateItem方法里返回该page本身即可destroyItem将会将该page从viewgroup里面移除。isViewFromObject方法里面直接可以返回view == object。
对于上面两段话,我这里有两点要着重讲一下:
1、第一段说明了,键(Key)的概念,首先这里要清楚的一点是,每个滑动页面都对应一个Key,而且这个Key值是用来唯一追踪这个页面的,也就是说每个滑动页面都与一个唯一的Key一一对应。大家先有这个概念就好,关于这个Key是怎么来的,下面再讲。
2、第二段简单讲了一个应用,即将当前页面本身的View作为Key。其实这个应用就是我们前一章讲的例子应用。不太理解?没关系,下面细讲。下面我们讲讲Key的问题
4、关于Key
现在我带着大家看看几个方法的官方文档:(这里结合《ViewPager 详解(一)---基本入门》最底部的例子来看)
首先:destroyItem()
public void destroyItem (ViewGroup container, int position, Object object)
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 fromfinishUpdate(ViewGroup)
.
Parameters
container | The containing View from which the page will be removed. |
---|---|
position | The page position to be removed. |
object | The same object that was returned by instantiateItem(View, int) . |
该方法实现的功能是移除一个给定位置的页面。适配器有责任从容器中删除这个视图。这是为了确保在finishUpdate(viewGroup)返回时视图能够被移除。
下面看看《ViewPager 详解(一)---基本入门》中是如何做的:
- @Override
- public void destroyItem(ViewGroup container, int position,
- Object object) {
- // TODO Auto-generated method stub
- container.removeView(viewList.get(position));
- }
果不其然,我们将给定位置的视图从container中移除了……
然后看getCount ()
public abstract int getCount ()
Return the number of views available.
返回当前有效视图的个数。
在上一章例子中,我们是这么做的:
- @Override
- public int getCount() {
- // TODO Auto-generated method stub
- return viewList.size();
- }
返回了当前要滑动视图的个数,与SDK说明一致。
最难的两个来了
instantiateItem (ViewGroup container, int position)
public Object instantiateItem (ViewGroup container, int position)
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 fromfinishUpdate(ViewGroup)
.
Parameters
container | The containing View in which the page will be shown. |
---|---|
position | The page position to be instantiated. |
Returns
- Returns an Object representing the new page. This does not need to be a View, but can be some other container of the page.
这个函数的实现的功能是创建指定位置的页面视图。适配器有责任增加即将创建的View视图到这里给定的container中,这是为了确保在finishUpdate(viewGroup)返回时this is be done!
返回值:返回一个代表新增视图页面的Object(Key),这里没必要非要返回视图本身,也可以这个页面的其它容器。其实我的理解是可以代表当前页面的任意值,只要你可以与你增加的View一一对应即可,比如position变量也可以做为Key(最后我们举个例子试试可不可行)
心得 :
1、从说明中可以看到,在代码中,我们的责任是将指定position的视图添加到conatiner中
2、Key的问题:从这个函数就可以看出,该函数返回值就是我们根据参数position增加到conatiner里的View的所对应的Key!!!!!!!
3、“it only must ensure this is done by the time it returns fromfinishUpdate(ViewGroup).”这句话在destroyItem()的函数说明中同样出现过,这说明在 finishUpdate(viewGroup)执行完后,有两个操作,一个是原视图的移除(不再显示的视图),另一个是新增显示视图(即将显示的视图)
在上一章的代码中,我们是这样做的:
- @Override
- public Object instantiateItem(ViewGroup container, int position) {
- // TODO Auto-generated method stub
- container.addView(viewList.get(position));
- return viewList.get(position);
- }
- };
在这里,我们做了两件事
第一:将参数里给定的position的视图,增加到conatiner中,供其创建并显示、。
第二:返回当前position的View做为此视图的Key。还记得API官方文档中下面这段话么?
对于非常简单的pageradapter或许你可以选择用page本身作为键,在创建并且添加到viewgroup后instantiateItem方法里返回该page本身即可destroyItem将会将该page从viewgroup里面移除。isViewFromObject方法里面直接可以返回view == object。
这里就把当前的View当作Key传过出去!!!!
最后一个: isViewFromObject (View view, Object object)
public abstract boolean isViewFromObject (View view, Object object)
Determines whether a page View is associated with a specific key object as returned by instantiateItem(ViewGroup, int)
. This method is required for a PagerAdapter to function properly.
Parameters
view | Page View to check for association with object |
---|---|
object | Object to check for association with view |
Returns
- true if
view
is associated with the key objectobject
功能:该函数用来判断instantiateItem(ViewGroup, int)函数所返回来的Key与一个页面视图是否是代表的同一个视图(即它俩是否是对应的,对应的表示同一个View)
返回值:如果对应的是同一个View,返回True,否则返回False。
在上章节的例子中,我们这样做的:
- @Override
- public boolean isViewFromObject(View arg0, Object arg1) {
- // TODO Auto-generated method stub
- return arg0 == arg1;
- }
由于在instantiateItem()中,我们作为Key返回来的是当前的View,所以在这里判断时,我们直接将Key与View看是否相等来判断是否是同一个View。
二、自定义Key实例
经过上面的讲解,想必大家给Key的概念应该有个清楚的理解,下面举个例子来说明Key与View的关系,由于Key与View要一一对应,所以我把每个视图所处的位置Position作为Key,在上章例子的基础上更改的,下面先看全部代码,然后看部分讲解:
- package com.example.testviewpage_2;
- /**
- * @author harvic
- * @date 2014.8.11
- */
- import java.util.ArrayList;
- import java.util.List;
- import android.app.Activity;
- import android.os.Bundle;
- import android.support.v4.view.PagerAdapter;
- import android.support.v4.view.ViewPager;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.ViewGroup;
- public class MainActivity extends Activity {
- private View view1, view2, view3;
- private List<View> viewList;// view数组
- private ViewPager viewPager; // 对应的viewPager
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- viewPager = (ViewPager) findViewById(R.id.viewpager);
- LayoutInflater inflater = getLayoutInflater();
- view1 = inflater.inflate(R.layout.layout1, null);
- view2 = inflater.inflate(R.layout.layout2, null);
- view3 = inflater.inflate(R.layout.layout3, null);
- viewList = new ArrayList<View>();// 将要分页显示的View装入数组中
- viewList.add(view1);
- viewList.add(view2);
- viewList.add(view3);
- PagerAdapter pagerAdapter = new PagerAdapter() {
- @Override
- public boolean isViewFromObject(View arg0, Object arg1) {
- // TODO Auto-generated method stub
- //根据传来的key,找到view,判断与传来的参数View arg0是不是同一个视图
- return arg0 == viewList.get((int)Integer.parseInt(arg1.toString()));
- }
- @Override
- public int getCount() {
- // TODO Auto-generated method stub
- return viewList.size();
- }
- @Override
- public void destroyItem(ViewGroup container, int position,
- Object object) {
- // TODO Auto-generated method stub
- container.removeView(viewList.get(position));
- }
- @Override
- public Object instantiateItem(ViewGroup container, int position) {
- // TODO Auto-generated method stub
- container.addView(viewList.get(position));
- //把当前新增视图的位置(position)作为Key传过去
- return position;
- }
- };
- viewPager.setAdapter(pagerAdapter);
- }
- }
在这里更改了两个地方:
1、先看Key的产生的位置instantiateItem()
- @Override
- public Object instantiateItem(ViewGroup container, int position) {
- // TODO Auto-generated method stub
- container.addView(viewList.get(position));
- //把当前新增视图的位置(position)作为Key传过去
- return position;
- }
我们在上讲也讲了在这个函数中Key是作为返回值与当前装入Container中的视图对应起来的。所以在这里我们返回postion与container.addView(viewList.get(position));里的viewList.get(position)这个视图对应起来。
2、isViewFromObject ()
- @Override
- public boolean isViewFromObject(View arg0, Object arg1) {
- // TODO Auto-generated method stub
- //根据传来的key,找到view,判断与传来的参数View arg0是不是同一个视图
- return arg0 == viewList.get((int)Integer.parseInt(arg1.toString()));
- }
判断从instantiateItem()返回来的Key与当前的View是否能对应起来,我们知道从instantiateItem传过来的其实是position,所以我们要根据position找到View,然后跟参数中的View arg0判断。
但在真正操作时出现了问题,我们要先将obect对应转换为int类型:(int)Integer.parseInt(arg1.toString());然后再根据position找到对应的View;
效果图:三个View之间的滑动切换
这里只所以与上章不一样,仅仅只有上部分一部分的地方才有滑动切换,是因为我更改了布局文件:
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context="com.example.testviewpage_2.MainActivity" >
- <android.support.v4.view.ViewPager
- android:id="@+id/viewpager"
- android:layout_width="wrap_content"
- android:layout_height="200dip"
- android:layout_gravity="center" />
- </RelativeLayout>
这里将layout_height更改为200dip,只所以这么做,是为了告诉大家,只要在想要实现滑动切换的地方添加上<android.support.v4.view.ViewPager />就可以实现切换,无所谓位置和大小,跟普通控件一样!!!!!!
源码地址:http://download.csdn.net/detail/harvic880925/7739873
请大家尊重原创者版权,转载请标明出处:http://blog.csdn.net/harvic880925/article/details/38487149 万分感激!!!
ViewPager 详解(二)---详解四大函数的更多相关文章
- C-指针,二级指针,二维数组作为函数参数使用,C语言链表(详解)
一级指针 int *p; //表示定义一个int型(4字节)的指针p &p //表示p自身的地址位置 p ...
- jni.h头文件详解二
作者:左少华 博客:http://blog.csdn.net/shaohuazuo/article/details/42932813 转载请注明出处:http://blog.csdn.net/shao ...
- 【转】 jni.h头文件详解(二)
原文网址:http://blog.csdn.net/shaohuazuo/article/details/42932813 作者:左少华 博客:http://blog.csdn.net/shaohua ...
- 举例详解Python中的split()函数的使用方法
这篇文章主要介绍了举例详解Python中的split()函数的使用方法,split()函数的使用是Python学习当中的基础知识,通常用于将字符串切片并转换为列表,需要的朋友可以参考下 函数:sp ...
- oracle分析函数技术详解(配上开窗函数over())
一.Oracle分析函数入门 分析函数是什么?分析函数是Oracle专门用于解决复杂报表统计需求的功能强大的函数,它可以在数据中进行分组然后计算基于组的某种统计值,并且每一组的每一行都可以返回一个统计 ...
- PopUpWindow使用详解(二)——进阶及答疑
相关文章:1.<PopUpWindow使用详解(一)——基本使用>2.<PopUpWindow使用详解(二)——进阶及答疑> 上篇为大家基本讲述了有关PopupWindow ...
- [转]文件IO详解(二)---文件描述符(fd)和inode号的关系
原文:https://www.cnblogs.com/frank-yxs/p/5925563.html 文件IO详解(二)---文件描述符(fd)和inode号的关系 ---------------- ...
- pika详解(二) BlockingConnection
pika详解(二) BlockingConnection 本文链接:https://blog.csdn.net/comprel/article/details/94592348 版权 Blocki ...
- ES6(二)解构赋值详解
详解一下之前的解构赋值 ①解构赋值中的"..." let [a,...b]= [1]; b // [] ...代表变量b去匹配剩余的所有元素返回一个数组 ,匹配不到时返回[] // ...
随机推荐
- 安装php时,make步骤报错make: *** [sapi/fpm/php-fpm] Error 1
安装PHP过程中,make步骤报错:(集中网络上各种解决方法) (1)-liconv -o sapi/fpm/php-fpm /usr/bin/ld: cannot find -liconv coll ...
- type和create type
type和create type 异同点: create type 可在库中生成一个长期有效的自定义类型对象,而type作用域仅限于语句块中: 两者都可以自定义数据类型: 各种ty ...
- 【USACO 2.1.2】法雷序列
[问题描述] 对任意给定的一个自然数 n(n<=160), 将分母小于等于 n 的不可约的真分数按上升的次序排序 , 并且在第一个分数前加上 0/1, 而在最后一个分数后加上 1/1, ...
- 服务器之间socket传输单链接和多连接测试结果
今天做了一下测试,目的是看看局域网内服务器a,通过一个连接往服务器b传输数据,和通过多个连接传输的不同. 结果发现和多少个连接没关系,一个进程一个连接就能跑满网卡,只要write的时候够快,read的 ...
- mysql报Fatal error encountered during command execution的解决办法
连接字符串里加上 Allow User Variables=True 解决. 否则时不时的报错,存储过程名长一点也报错,又有时报有时不报,参数传1位数就正常2位数就报错等…… 折腾mysql蛋疼啊
- Extjs之rowEditing编辑状态时列不对齐
Extjs在使用rowEditing的时候,会在每一列加上editor属性,表示当处于编辑状态时这一列的值是什么类型的,后突然发现在rowEditing处于编辑状态时每一列的宽度边框了,如果列数非常多 ...
- [Struts2学习笔记] -- 简单的类型转换
接下来学习一下Struts2简单的类型转换,Struts2基于ognl.jar实现了简单类型的数据转换.比如jsp页面中的form值与字段值的转换,下面写一个例子. 1.创建一个jsp页面,编写一个f ...
- NET Core 数据保护2
ASP.NET Core 数据保护(Data Protection 集群场景)[下] 前言 接[中篇],在有一些场景下,我们需要对 ASP.NET Core 的加密方法进行扩展,来适应我们的需求, ...
- Coupons
uva10288:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=24&am ...
- 所有语言的Awesome
Awesome Awesomeness A curated list of amazingly awesome awesomeness. Also available on: Awesome-Awes ...