Android入门--ViewPager使用总结

本文详细介绍了Android中的ViewPager组件,包括它的基本使用、如何导入库、与PagerAdapter的关系,以及FragmentPagerAdapter和FragmentStatePagerAdapter的区别。通过示例展示了如何使用PagerAdapter实现ViewPager与View的交互,以及如何使用FragmentPagerAdapter加载Fragment。文中强调了ViewPager的动态加载机制,并提供了实例代码以加深理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ViewPager,是在Android3.0之后新增的API,可以用于导航栏,页面切换等控件,其主要功能是使视图可以左右滑动,使用时注意需要导入android-support-v4.jar包,如果创建的项目是3.0之后的,系统会自动导包,就不需要费心。当然,如果遇到导包问题,也不要着急,下面是解决办法:先检查项目中是否存在android-support-v4.jar包,如果不存在,就检查sdk中是否存在v4的包,路径为 \sdk\extras\android\support\v4 ,如果存在android-support-v4.jar文件,直接复制到项目下的 lib文件夹中,然后选中点击右键–>Build Path–>Add to Build Path。到此,按理说应该导包完成了,当然,如果还有特殊情况,再特殊考虑

下面是对ViewPager的基本理解:
1)ViewPager类直接继承了ViewGroup类,所有它是一个容器类,可以在其中添加其他的view类。

2)ViewPager类需要一个PagerAdapter适配器类给它提供数据。

3)ViewPager经常和Fragment一起使用,并且提供了专门的FragmentPagerAdapter和FragmentStatePagerAdapter类供Fragment中的ViewPager使用。

在使用ViewPager的时候,还需要使用两个组件类分别是PagerTitleStrip类和PagerTabStrip类,PagerTitleStrip类直接继承自ViewGroup类,而PagerTabStrip类继承PagerTitleStrip类,所以这两个类也是容器类。但是有一点需要注意,在定义XML的layout的时候,这两个类必须是ViewPager标签的子标签,不然会出错

总结以上,使用ViewPager大致分为以下几步:
1.在想添加ViewPager控件的布局文件中添加ViewPager控件。
2.在Activity中实例化ViewPager控件。
3.创建Adapter,并设置ViewPager的Adapter。

以上,就是一个最简单的ViewPager的使用方法,其中的重点是第3点,也就是创建PagerAdapter和设置ViewPager的Adapter

接下来主要介绍ViewPager类和其中常用的方法,以及三种不同的适配器的使用,包括
PagerAdapter :简单的适配器
FragmentPagerAdapter:静态的适配器,
FragmentStatePagerAdapter:动态的适配器

以下的资料引用自网络

  • ViewPager:如其名所述,是负责翻页的一个 View。准确说是一个 ViewGroup,包含多个 View 页,在手指横向滑动屏幕时,其负责对 View 进行切换。为了生成这些 View 页,需要提供一个 PagerAdapter 来进行和数据绑定以及生成最终的 View 页

    • setAdapter(): ViewPager 通过 setAdapter() 来建立与 PagerAdapter 的联系。这个联系是双向的,一方面,ViewPager 会拥有 PagerAdapter 对象,从而可以在需要时调用 PagerAdapter 的方法;另一方面,ViewPager 会在 setAdapter() 中调用 PagerAdapter 的 registerDataSetObserver() 方法,注册一个自己生成的 PagerObserver 对象,从而在 PagerAdapter 有所需要时(如 notifyDataSetChanged()或 notifyDataSetInvalidated() 时),可以调用 Observer 的 onChanged() 或 onInvalidated() 方法,从而实现 PagerAdapter 向 ViewPager 方向发送信息。
    • dataSetChanged(): 在 PagerObserver.onChanged(),以及 PagerObserver.onInvalide() 中被调用。因此当 PagerAdapter.notifyDataSetChanged() 被触发时,ViewPager.dataSetChanged() 也可以被触发。该函数将使用 getItemPosition() 的返回值来进行判断,如果为 POSITION_UNCHANGED,则
      什么都不做;如果为 POSITION_NONE,则调用 PagerAdapter.destroyItem() 来去掉该对象,并设置为需要刷新 (needPopulate = true) 以便触发PagerAdapter.instantiateItem() 来生成新的对象
  • PagerAdapter: PageAdapter 是 ViewPager 的适配器,ViewPager 将调用它来取得所需显示的页,而 PageAdapter 也会在数据变化时,通知 ViewPager。这个类也是FragmentPagerAdapter 以及 FragmentStatePagerAdapter 的基类。如果继承自该类,至少需要实现 instantiateItem(), destroyItem(), getCount() 以及 isViewFromObject()

    • getItemPosition(): 该方法用以返回给定对象的位置,给定对象是由 instantiateItem() 的返回值。在 ViewPager.dataSetChanged() 中将对该方法的返回值进行判断,以决定是否最终触发 PagerAdapter.instantiateItem() 方法。在 PagerAdapter 中的实现是直接传回 POSITION_UNCHANGED。如果该方法不被重载,则会一直返回 POSITION_UNCHANGED,从而导致 ViewPager.dataSetChanged() 被调用时,认为不必触发 PagerAdapter.instantiateItem()。很多人因为没有重载该方法,而导致调用PagerAdapter.notifyDataSetChanged() 后,什么都没有发生。
    • instantiateItem(): 在每次 ViewPager 需要一个用以显示的 Object 的时候,该方法都会被 ViewPager.addNewItem() 调用
    • notifyDataSetChanged(): 在数据集发生变化的时候,一般 Activity 会调用 PagerAdapter.notifyDataSetChanged(),以通知 PagerAdapter,而 PagerAdapter 则会通知在自己这里注册过的所有 DataSetObserver。其中之一就是在 ViewPager.setAdapter() 中注册过的 PageObserver。PageObserver 则进而调用ViewPager.dataSetChanged(),从而导致 ViewPager 开始触发更新其内含 View 的操作。
  • FragmentPagerAdapter :FragmentPagerAdapter 继承自 PagerAdapter。相比通用的 PagerAdapter,该类更专注于每一页均为 Fragment 的情况。如文档所述,该类内的每一个生成的 Fragment 都将保存在内存之中,因此适用于那些相对静态的页,数量也比较少的那种;如果需要处理有很多页,并且数据动态性较大、占用内存较多的情况,应该使用FragmentStatePagerAdapter。FragmentPagerAdapter 重载实现了几个必须的函数,因此来自 PagerAdapter 的函数,我们只需要实现 getCount(),即可。且,由于 FragmentPagerAdapter.instantiateItem() 的实现中,调用了一个新增的虚函数 getItem(),因此,我们还至少需要实现一个 getItem()。因此,总体上来说,相对于继承自 PagerAdapter,更方便一些。

    • getItem(): 如果需要向 Fragment 对象传递相对静态的数据时,我们一般通过 Fragment.setArguments() 来进行,这部分代码应当放到 getItem()。它们只会在新生成 Fragment 对象时执行一遍。
      如果需要在生成 Fragment 对象后,将数据集里面一些动态的数据传递给该 Fragment,那么,这部分代码不适合放到 getItem() 中。因为当数据集发生变化时,往往对应的 Fragment 已经生成,如果传递数据部分代码放到了 getItem() 中,这部分代码将不会被调用。这也是为什么很多人发现调用 PagerAdapter.notifyDataSetChanged() 后,getItem() 没有被调用的一个原因。
    • instantiateItem(): 方法中判断一下要生成的 Fragment 是否已经生成过了,如果生成过了,就使用旧的,旧的将被 Fragment.attach();如果没有,就调用 getItem() 生成一个新的,新的对象将被 FragmentTransation.add()。
      FragmentPagerAdapter 会将所有生成的 Fragment 对象通过 FragmentManager 保存起来备用,以后需要该 Fragment 时,都会从 FragmentManager 读取,而不会再次调用 getItem() 方法。
      如果需要在生成 Fragment 对象后,将数据集中的一些数据传递给该 Fragment,这部分代码应该放到这个方法的重载里。在我们继承的子类中,重载该方法,并调用 FragmentPagerAdapter.instantiateItem() 取得该方法返回 Fragment 对象,然后,我们该 Fragment 对象中对应的方法,将数据传递过去,然后返回该对象。
      否则,如果将这部分传递数据的代码放到 getItem()中,在 PagerAdapter.notifyDataSetChanged() 后,这部分数据设置代码将不会被调用。
    • destroyItem(): 该方法被调用后,会对 Fragment 进行 FragmentTransaction.detach()。这里不是 remove(),只是 detach(),因此 Fragment 还在 FragmentManager 管理中,Fragment 所占用的资源不会被释放。
  • FragmentStatePagerAdapter :FragmentStatePagerAdapter 和前面的 FragmentPagerAdapter 一样,是继承子 PagerAdapter。但是,和 FragmentPagerAdapter 不一样的是,正如其类名中的 ‘State’ 所表明的含义一样,该 PagerAdapter 的实现将只保留当前页面,当页面离开视线后,就会被消除,释放其资源;而在页面需要显示时,生成新的页面(就像 ListView 的实现一样)。这么实现的好处就是当拥有大量的页面时,不必在内存中占用大量的内存。

    • getItem(): Fragment.setArguments() 这种只会在新建 Fragment 时执行一次的参数传递代码,可以放在这里。
      由于 FragmentStatePagerAdapter.instantiateItem() 在大多数情况下,都将调用 getItem() 来生成新的对象,因此如果在该方法中放置与数据集相关的 setter 代码,基本上都可以在 instantiateItem() 被调用时执行,但这和设计意图不符。毕竟还有部分可能是不会调用 getItem() 的。因此这部分代码应该放到 instantiateItem() 中。
    • instantiateItem(): 除非碰到 FragmentManager 刚好从 SavedState 中恢复了对应的 Fragment 的情况外,该方法将会调用 getItem() 方法,生成新的 Fragment 对象。新的对象将被 FragmentTransaction.add()。
      FragmentStatePagerAdapter 就是通过这种方式,每次都创建一个新的 Fragment,而在不用后就立刻释放其资源,来达到节省内存占用的目的的。
    • destroyItem(): 将 Fragment 移除,即调用 FragmentTransaction.remove(),并释放其资源。

以上,介绍了ViewPager和其适配器的概念和一些常用的方法,下面通过实例来说明其具体的使用

1. PagerAdapter实现ViewPagerView的使用:

activity_main.xml中就是一个简单的ViewPager控件

<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=".MainActivity" >

    <android.support.v4.view.ViewPager
        android:id="@+id/viewPager"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</RelativeLayout>

view_0.xml, view_1.xml, view_2.xml, view_3.xml 这四个view界面的布局是一样的,这里就不重复了

<?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:gravity="center"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/tv_View1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="50sp" />

</LinearLayout>

MainActivity.java 这里为了简便,我直接new了一个PagerAdapter类的对象,没有单独写成一个类文件来继承PagerAdapter,然后设置Adapter就行了

package com.example.viewpagertest;

import java.util.ArrayList;

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;
import android.widget.TextView;
import android.app.Activity;

public class MainActivity extends Activity {
    private ViewPager mViewPager = null;

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

        // 初始化ViewPager控件
        mViewPager = (ViewPager) findViewById(R.id.viewPager);

        // 初始化视图
        LayoutInflater mLi = LayoutInflater.from(this);
        View view_0 = mLi.inflate(R.layout.view_0, null);
        View view_1 = mLi.inflate(R.layout.view_1, null);
        View view_2 = mLi.inflate(R.layout.view_2, null);
        View view_3 = mLi.inflate(R.layout.view_3, null);

        // 将视图放到一个List列表中,方便存取
        final ArrayList<View> views = new ArrayList<View>();
        views.add(view_0);
        views.add(view_1);
        views.add(view_2);
        views.add(view_3);

        // 创建PagerAdapter类的对象
        PagerAdapter mAdaper = new PagerAdapter() {

            // 返回页面数量
            @Override
            public int getCount() {

                return views.size();
            }

            // 实例化一个页面,这里是主要的方法,是用来将View绑定到页面的方法,并对View中的控件进行设置
            @Override
            public Object instantiateItem(ViewGroup container, int position) {
                System.out.println("-->instantiateItem " + position);

                container.addView(views.get(position));

                TextView tv_view = null;

                // 根据滑动到当前页面的位置,获取到对应View中的控件,并对控件进行设置
                switch (position) {
                case 0:
                    tv_view = (TextView) views.get(position).findViewById(
                            R.id.tv_View0);
                    tv_view.setText("这是页面" + position);
                    break;
                case 1:
                    tv_view = (TextView) views.get(position).findViewById(
                            R.id.tv_View1);
                    tv_view.setText("这是页面" + position);
                    break;
                case 2:
                    tv_view = (TextView) views.get(position).findViewById(
                            R.id.tv_View2);
                    tv_view.setText("这是页面" + position);
                    break;
                case 3:
                    tv_view = (TextView) views.get(position).findViewById(
                            R.id.tv_View3);
                    tv_view.setText("这是页面" + position);
                    break;

                default:
                    break;
                }
                return views.get(position);
            }

            // 判断View是否来自Object
            @Override
            public boolean isViewFromObject(View arg0, Object arg1) {
                return arg0 == arg1;
            }

            // 销毁一个页面
            @Override
            public void destroyItem(ViewGroup container, int position,
                    Object object) {
                System.out.println("-->destroyItem " + position);
                container.removeView(views.get(position));
            }
        };

        // 最后,调用mViewPager的setAdapter方法来适配
        mViewPager.setAdapter(mAdaper);

    }

}

运行效果:
这里写图片描述 这里写图片描述
下面是logcat:
logcat

通过logcat能看到,当打开App时,初相的界面如图一所示,显示”这是页面 0” ,此时,如果当我向右滑动,将会出现“这是页面 1”,此时logcat弹出第一条信息,也就是初始化页面“2”,简单理解下就是当我滑动到下一个页面的时候,下下个一面已经在初始化了。然后当我向左滑的时候,会出现第二条logcat,也就是页面“2”被销毁了,理解就是,这是一种动态添加View的机制,页面的准备与销毁是在当前页面的前后各一个

2.FragmentPagerAdapter实现ViewPagerFragment的使用

使用FragmentPagerAdapter,是静态的加载Fragment,适用于页面较少的情况,所以会先定义好各个Fragment和其对应的View,然后通过一个Fragment的List集合来统一加载页面

activity_main.xml 这是主页显示的View布局文件,其中依然只是一个ViewPager控件

<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=".MainActivity" >

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

</RelativeLayout>

fragment_view_0.xml,,fragment_view_1.xml,,fragment_view_2.xml, fragment_view_3.xml 布局大致相同,这里就只列出一个:

<?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:gravity="center"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/tv_fragment_0"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="30sp" />

</LinearLayout>

Fragment_0.java,Fragment_1.java,Fragment_2.java,Fragment_3.java内容大致相同,这里就不重复了:

package com.example.testviewpager;

import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class Fragment_0 extends Fragment {

    // 当Fragment_0被创建时调用
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        System.out.println("-->Fragment_0 onCreate");
    }

    // 当Activity中的onCreate()方法执行完调用
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        System.out.println("-->Fragment_0 onActivityCreated");
    }

    // 给当前的Fragment绘制UI布局
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        System.out.println("-->Fragment_0 onCreateView");

        View view = inflater.inflate(R.layout.fragment_view_0, null);
        TextView tv_fragment_0 = (TextView) view
                .findViewById(R.id.tv_fragment_0);
        tv_fragment_0.setText("这是Fragment 0");
        return view;
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        System.out.println("-->Fragment_0 onDestroyView");
    }

    @Override
    public void startActivity(Intent intent) {
        super.startActivity(intent);
        System.out.println("-->Fragment_0 startActivity");
    }

}

MainActivity.java

package com.example.testviewpager;

import java.util.ArrayList;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.ViewPager;

public class MainActivity extends FragmentActivity {

    // 定义适配器
    private pageAdapter mAdapter = null;
    // 定义ViewPage控件
    private ViewPager mPager = null;

    // 申明四个Fragment页面
    private Fragment_0 fragment_0 = null;
    private Fragment_1 fragment_1 = null;
    private Fragment_2 fragment_2 = null;
    private Fragment_3 fragment_3 = null;

    // 申明一个用于保存Fragment集合的List
    private ArrayList<Fragment> fragmentList = null;

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

        // 初始化ViewPager控件
        mPager = (ViewPager) findViewById(R.id.viewPager);

        // 初始化Fragment页面
        initFragment();

        // 初始化适配器
        mAdapter = new pageAdapter(getSupportFragmentManager(), fragmentList);

        // 设置适配器
        mPager.setAdapter(mAdapter);
    }

    public void initFragment() {
        fragmentList = new ArrayList<Fragment>();

        fragment_0 = new Fragment_0();
        fragment_1 = new Fragment_1();
        fragment_2 = new Fragment_2();
        fragment_3 = new Fragment_3();

        fragmentList.add(fragment_0);
        fragmentList.add(fragment_1);
        fragmentList.add(fragment_2);
        fragmentList.add(fragment_3);
    }

}

FragmentPagerAdapter.java

package com.example.testviewpager;

import java.util.ArrayList;

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;

public class pageAdapter extends FragmentPagerAdapter {

    private ArrayList<Fragment> fragmentList = null;

    // 构造方法,传入的参数是一个FragmentManager类型
    public pageAdapter(FragmentManager fm, ArrayList<Fragment> fragmentList) {
        super(fm);
        this.fragmentList = fragmentList;
    }

    // 获取ViewPager的数量
    @Override
    public int getCount() {
        return fragmentList.size();
    }

    // 获取ViewPager中指定的Item,这里返回的是Fragment类型,可以看出ViewPager中嵌套的是Fragment
    @Override
    public Fragment getItem(int arg0) {
        return fragmentList.get(arg0);
    }

}

下面是运行效果:
这里写图片描述 这里写图片描述

下面是logcat:
这里写图片描述




未完待续

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值