再说Viewpager,详解PagerAdapter

来源:互联网 发布:空心杯无人机控制算法 编辑:程序博客网 时间:2024/06/06 02:42

终于看到这篇博客了,我被坑的地方就在接下来的内容,所以才被逼着写了上一篇博客。最初是因为想通过ViewPager实现Galley的效果,可以在一个界面中显示三张图片。实现的方式就是设置clipChildren为false,先看具体代码:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="vertical" android:layout_width="match_parent"    android:layout_height="match_parent"    android:clipChildren="false">    <android.support.v4.view.ViewPager        android:id="@+id/gallery_viewpager"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:clipChildren="false"        android:layout_marginLeft="50dp"        android:layout_marginRight="50dp">    </android.support.v4.view.ViewPager></LinearLayout>

mViewPager=(ViewPager)findViewById(R.id.gallery_viewpager);mViewPager.setPageMargin(20);mViewPager.setOffscreenPageLimit(3);imgIDs=new int[]{R.drawable.img1,R.drawable.img2,R.drawable.img3,R.drawable.img4,R.drawable.img5,R.drawable.img6,R.drawable.img7,R.drawable.img8};imgs=new ImageView[imgIDs.length];for(int i=0;i<imgIDs.length;i++){    imgs[i]=new ImageView(this);    //imgs[i].setScaleType(ImageView.ScaleType.CENTER_CROP);    imgs[i].setImageResource(imgIDs[i]);}mViewPager.setAdapter(new GalleryPagerAdapter());
这样基本上就可以实现效果了,代码并没有什么复杂的。除了xml代码之外,java代码与通常的代码并没有什么区别,只是多了两行setPageMargin()和setOffScreenPageLimit()。可惜我这人总爱瞎折腾,先看看我碰到的那些坑吧。

                

可能大家看不太明白,先解释下,第一张图是原始的效果,没有明确设置任何ScaleType,这时候的效果蛮好的,但是我想让图片的高度可以铺满全屏。脑海中第一想法就是设置ScaleType,习惯性的设为CENTER_CROP,就有了第二张图,然后我就崩溃了。我靠,我的刘诗诗右半边脸都被遮住了,而且刘诗诗左边的刘亦菲也被挡住了,我完全不知道发生了什么啊。之后就是不断的捯饬啊,精疲力尽心力交瘁啊,到这里,我又要继续宣传我的上一篇博客,虽然是被逼出来的,但真是良心之作啊。第三张图是我经过九九八十一难,终于学会了设置FIT_XY,可惜不是等比例调节,纵横比变了,不过也凑合着吧,总算熬过这道坎了。


反反复复也写了好几篇ViewPager的博客,那个PagerAdapter也被我写了好几遍,但是却没真正搞明白PagerAdapter怎么回事,是时候好好研究下了,我们先看官方文档:

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 or FragmentStatePagerAdapter.

作为基类提供适配器用于填充页面到ViewPager之中。你最有可能想要去使用它的特定子类,像FragmentPagerAdapter和FragmentStatePagerAdapter。

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的时候,你必须最少重写一下这四个方法: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.

PagerAdapter比AdapterViews的那些适配器更加常用。在更新过程中,ViewPager并不提供一个View回收机制,而是使用回调去指示进行到了哪一步。如果你想的话,PagerAdapter也可以实现View回收机制,或者采用一个更加复杂的方法来管理页面。

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/or destroyItem(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.

ViewPager并不直接操控View,而是通过一个key来联系每一个页面。key用于追踪被唯一标示指定页面,独立于在Adapter中的位置。当ViewPager的内容将要改变的时候,PagerAdapter会调用startUpdate()方法。随后将会调用一次或多次的instantiateItem()和destroyItem()方法。最后以finishUpdate()方法来标志这次更新结束。等到finishUpdate返回时,与instantiateItem返回的key关联的View,应该被添加到父布局中了,与传递给destroyItem的key相关联的View也应该被移除了。isViewFromObject()方法判定是否页面与给定的key关联。
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通常选用View他们本身作为key,在创建和添加到父布局之后,可以在instantiateItem()方法中返回他们。对应的destroyItem()方法的实现则是将他们从父布局移除,isViewFromObject()方法可以直接返回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 from BaseAdapter. 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 method getItemPosition(Object).

PagerAdapter支持数据集改变。数据集必须在主线程发生改变,与继承自BaseAdapter的那些AdapterView的适配器类似,必须以notifyDataSetChanged()结尾。数据集的改变可能蕴含添加,移除或者改变位置。ViewPager将保持当前页面处于active,由实现了getItemPosition()这个方法的适配器提供。


下面细细说下这四个方法,就拿我这个demo的PagerAdapter说下吧,反正大多也没什么区别,看代码:

class GalleryPagerAdapter extends PagerAdapter{    @Override    public int getCount() {        return imgs.length;    }    @Override    public boolean isViewFromObject(View view, Object object) {        return view==object;    }    @Override    public Object instantiateItem(ViewGroup container, int position) {        container.addView(imgs[position]);        return imgs[position];    }    @Override    public void destroyItem(ViewGroup container, int position, Object object) {        container.removeView(imgs[position]);    }}
getcount():返回可用的View数量,没什么可说的。

isViewFromObjectFromObject(View view,Object object):判定页面是否与指定的key相连,key是由instantiate()方法返回。那这个方法具体什么时候调用呢???因为ViewPager并不是直接操控view,而是通过key来联系每个页面的,所以咧,任何情况下需要判断一个View是否与key相关都可以调用,例如onLayout()的时候等等。

instantiateItem(ViewGroup container,in position):container就是viewpager,position当前位置。在指定的位置创建页面,适配器负责添加view到viewpager中,然而它只保证在finishUpdate()返回时才完成。这里返回的就是key,我们并不一定返回view,只要你可以通过key找到view,任何Object都可以。例如,你可以在这里返回position。

destroyItem(ViewGroup container,int position,Object object):删除指定位置的页面,适配器负责从viewPager中删除view,然而它只保证在finishUpdate()返回时才完成。可以看到这里有三个参数,最后一个object就是通过instantiateItem()返回的key。

为了看看我们key的效果,这里我将代码改两行,也是可以运行的:

class GalleryPagerAdapter extends PagerAdapter{    @Override    public int getCount() {        return imgs.length;    }    @Override    public boolean isViewFromObject(View view, Object object) {        return view==imgs[(int)object];    }    @Override    public Object instantiateItem(ViewGroup container, int position) {        container.addView(imgs[position]);        return position;    }    @Override    public void destroyItem(ViewGroup container, int position, Object object) {        container.removeView(imgs[position]);    }}


写到这里ViewPager的基本用法,能说的差不多都说了,好像还有个PageTransformer,是设置ViewPager滑动的效果的,有时间再说吧。这几天的ViewPager写到吐啊。撤了,撒花~~~~~~~~

0 0