ViewPager全面解析

写在前面:
最近发现,对一些基本用法,隔一段时间不用又会无从下手。因此,慢慢养成了写总结博客的习惯,一方面加深印象理清知识点,另一方面,把自己的学习总结分享给大家。

一、ViewPager的基本使用

1、ViewPager是什么?
ViewPager继承自ViewGroup,也是一个容器类。实际上是一个view的管理器,实现左右滑动的功能。通常我们需要ViewPager+adapter实现左右滑动功能。

2、一个简单的ViewPager Demo
(1)首先ViewPager的xml布局:activity_main.xml。这样就定义好了容纳view的容器。注意ViewPager引入时需要写完整的包名android.support.v4.view.ViewPager.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    >

    <android.support.v4.view.ViewPager
        android:id="@+id/myviewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />
</LinearLayout>

(2)准备数据源——待左右滑动显示的view们。我这里只是简单放了三个图片。

List<View> getViews(){
        List<View> views = new ArrayList<>();

        ImageView imageView = new ImageView(this);
        imageView.setImageDrawable(ContextCompat.getDrawable(this,R.drawable.morning));
        views.add(imageView);

        ImageView imageView1 = new ImageView(this);
        imageView1.setImageDrawable(ContextCompat.getDrawable(this,R.drawable.afternoon));
        views.add(imageView1);

        ImageView imageView2 = new ImageView(this);
        imageView2.setImageDrawable(ContextCompat.getDrawable(this,R.drawable.night));
        views.add(imageView2);

        return views;
    }

(3)实现自定义Adapter,一般采用继承自PagerAdapter。
PagerAdapter是一个抽象类,是将待显示views显示到ViewPager中的桥梁。有兴趣的话可以查看一下PagerAdapter源码,PagerAdapter一系列方法的调用最终表现为页面的切换,startUpdate()方法(意味着ViewPager内容即将改变)→instantiateItem()方法(页面填充和初始化)→destroyItem()(移除view)。
一般而言,实现ViewAdapter至少需要实现4中方法:

 /**
     * 待显示views的数目
     * @return
     */
    @Override
    public int getCount() {
        return 0;
    }

    /**
     * 把待显示view添加到viewpager中,进行初始化操作。一般返回view本身(其实只要返回view的标识就好了)
     * @param container
     * @param position
     * @return
     */
    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        return super.instantiateItem(container, position);
    }

    /**
     * 移除view
     * @param container
     * @param position
     * @param object
     */
    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        super.destroyItem(container, position, object);
    }

    /**
     * 判断视图是否与给定的key(参数中的object)相一致。viewpager使用key对每个页面进行管理,其实我们在instantiateItem中返回的就是这个key,如果instantiateItem返回的是view,只要判断view和key是否相等就好了
     * @param view
     * @param object
     * @return
     */
    @Override
    public boolean isViewFromObject(View view, Object object) {
        return false;
    }

下面是我的一个简单实现:

public class MyViewPagerAdapter extends PagerAdapter {

    List<View> views = null;

    public MyViewPagerAdapter(List<View> views) {
        //把待显示的view们传递进来
        this.views = views;
    }

    /**
     * 初始化指定位置页面  需要返回页面的唯一标识(通常情况下返回view本身)
     * @param container
     * @param position
     * @return
     */
    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        //把当前要显示的view添加到viewPager中
        container.addView(views.get(position));
        return views.get(position);
    }

    @Override
    public int getCount() {
        return views.size();
    }

    /**
     * 负责移除指定位置的view
     * @param container
     * @param position
     * @param object
     */
    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView(views.get(position));
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        //由于前面返回的view本身作为view标识,这里直接判断是否相等就好了
        return view == object;
    }
}

接下来看一下MainActivity.java的代码,就能实现view左右滑动的功能。

这里写代码片public class MainActivity extends AppCompatActivity {

    private ViewPager viewPager = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        viewPager = (ViewPager)findViewById(R.id.myviewpager);

        viewPager.setAdapter(new MyViewPagerAdapter(getViews()));


    }

    List<View> getViews(){
        List<View> views = new ArrayList<>();

        ImageView imageView = new ImageView(this);
        imageView.setImageDrawable(ContextCompat.getDrawable(this,R.drawable.morning));
        views.add(imageView);

        ImageView imageView1 = new ImageView(this);
        imageView1.setImageDrawable(ContextCompat.getDrawable(this,R.drawable.afternoon));
        views.add(imageView1);

        ImageView imageView2 = new ImageView(this);
        imageView2.setImageDrawable(ContextCompat.getDrawable(this,R.drawable.night));
        views.add(imageView2);

        return views;
    }
}

以上是viewPager的最简单的应用。

二、FragmentPagerAdapter使用

1、FragmentPagerAdapter是什么?

背景:大部分时候,我们需要实现fragment之间的左右滑动切换(不同于上面的简单view),也就是说要用到ViewPager+众多Fragment的组合,这时候就需要用到FragmentPagerAdapter来管理众多的Fragment与ViewPager进行交互。

本质:显然FragmentPagerAdapter继承自PagerAdapter,来展示不同的Fragment,比较特别的是,每一个Fragment都会被保存在FragmentManager中。(因而适用于少量的页面,页面过多容易占用较多内存)
FragmentPagerAdapter是一个抽象类,追溯其源码,相较于PagerAdapter,增加了FragmentManager和FragmentTransaction。

FragmentManager:用于管理fragment,保存每个fragment,当要显示新的页面时,先在FragmentManager中查找是否有对应的fragment存在,如果有则把fragment与activity 附着在一起(attach),否则,则获取fragment(这个通过调用getItem()方法获取,此方法为抽象方法,需要子类实现),添加到FragmentManager中并attach到activity。

FragmentTransaction:用于操作fragment事务,比如attach、detach等都需要它。注意事务的提交是在在finishUpdate方法中,这是因为ViewPager的预加载的功能,在ViewPager中加载完多个fragment事件才会事务提交。而在destroyItem方法中,只是调用了detach方法,实质上只是把fragment从UI移除,但仍存在于FragmentManager中。

综上:相对于PagerAdapter ,FragmentPagerAdapter封装了FragmentManager和FragmentTransaction,以实现对fragment的缓存。而FragmentPagerAdapter的实现类需要实现以下两个方法:

/**
     * 返回待显示的fragment
     * @param position
     * @return
     */
    @Override
    public Fragment getItem(int position) {
        return null;
    }

    @Override
    public int getCount() {
        return 0;
    }

2、FragmentPagerAdapter的简单使用

(1)准备数据源——待左右滑动的fragments们。这里我简单的每个fragment显示一张图片。其他的两个fragment与之类似,只是传入的图片不同。注意这里我选择的是继承自android.support.v4.app.Fragment。Fragment存在于两个包中:android.support.v4.app和android.app。二者又有什么区别呢?

① android.support.v4.app.Fragment可以兼容到1.6版本,而android.app.Fragment在3.0之后才可以用,不支持低版本。
② v4包的fragemnt使用时,需要activity继承FragmentActivity,否则就会报错。不过项目中我们一般继承自AppCompatActivity,而AppCompatActivity是继承FragmentActivity的。


/**
 * Created by Administrator on 2016/10/7.
 */

public class MyFragment extends android.support.v4.app.Fragment {

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

        ImageView imageView = new ImageView(getActivity());
        imageView.setImageDrawable(ContextCompat.getDrawable(getActivity(),R.drawable.morning));

        return imageView;
    }
}

(2)实现FragmentPagerAdapter子类。这个只要实现两个方法,比较简单。

public class MyFragmentPagerAdapter extends FragmentPagerAdapter {

    private List<Fragment> fragments = null;

    public MyFragmentPagerAdapter(FragmentManager fm, List<Fragment> fragments) {
        super(fm);
        this.fragments = fragments;
    }

    /**
     * 返回待显示的fragment
     * @param position
     * @return
     */
    @Override
    public Fragment getItem(int position) {
        return fragments.get(position);
    }

    @Override
    public int getCount() {
        return fragments.size();
    }
}

(3)在activity中绑定adapter。如下:

public class MainActivity extends AppCompatActivity {

    private ViewPager viewPager = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        viewPager = (ViewPager)findViewById(R.id.myviewpager);

       // viewPager.setAdapter(new MyViewPagerAdapter(getViews()));

        viewPager.setAdapter(new MyFragmentPagerAdapter(getSupportFragmentManager(),getFragments()));


    }
    List<Fragment> getFragments(){

        List<Fragment> fragments = new ArrayList<>();

        fragments.add(new MyFragment());
        fragments.add(new MyFragment1());
        fragments.add(new MyFragment2());

        return fragments;

    }


    List<View> getViews(){
        List<View> views = new ArrayList<>();

        ImageView imageView = new ImageView(this);
        imageView.setImageDrawable(ContextCompat.getDrawable(this,R.drawable.morning));
        views.add(imageView);

        ImageView imageView1 = new ImageView(this);
        imageView1.setImageDrawable(ContextCompat.getDrawable(this,R.drawable.afternoon));
        views.add(imageView1);

        ImageView imageView2 = new ImageView(this);
        imageView2.setImageDrawable(ContextCompat.getDrawable(this,R.drawable.night));
        views.add(imageView2);

        return views;
    }
}

关于FragmentStatePagerAdapter:

前面有提到过,FragmentPagerAdapter会保存每个fragment,因而适用于fragment页面较少的情况。而对于动态且fragment较多的时候,一般选择用FragmentStatePagerAdapter。追溯FragmentStatePagerAdapter源码,可以发现其destroyItem方法中会直接remove fragment而不同于FragmentPagerAdapter只是detach。使用方法和FragmentPagerAdapter类似,不细说。

参考:http://www.jianshu.com/p/d86e31dcc97b
http://www.imooc.com/article/2742

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值