这个系列主要还是针对一些日常开发中比较复杂的控件的使用来讲述的,基本上不是很难,我会以google官方的文档作为基础,中间附带我自己的理解和一些小例子,争取做到清晰易懂。每个章节对应一个控件的使用。
总览
ViewPager(android.support.v4.view.ViewPager)允许创建用户可以左右滑动的界面。开发人员一般是提供一个PagerAdapter(android.support.v4.view.PagerAdapter)来展示每个视图中的显示内容。
我们需要注意到ViewPager这个控件实际上是一直处在发展和完善中的,所以google并没有将其纳入标准的view或者widget包中。
ViewPager经常被使用来连接碎片(Fragment,实际上就是一个个独立的界面)。有几个预定义的标准adapter,大多数情况下我们使用这几个adapter也就足够了,他们是:
- FragmentPagerAdapter(android.support.v4.app.FragmentPagerAdapter)
- FragmentStatePagerAdapter(android.support.v4.app.FragmentPagerAdapter)
- FragmentPagerAdapter(android.support.v13.app.FragmentPagerAdapter)
- FragmentStatePagerAdapter(android.support.v13.app.FragmentPagerAdapter)
从上面也可以看出我们至少有过一次Adapter的版本升级了。下面我们分别查看每个Adapter的使用。
android.support.v4.view.PagerAdapter
我们应该知道,PagerAdapter是剩下的四个Adapter的父类,所以我们从最基础的这个Adapter看起。
我们做一个小例子:
- 准备三个布局文件,这三个布局文件随便选,最终将会嵌入到我们的滑动界面中。
- 编写我们主界面布局:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <!-- 演示ViewPager --> <android.support.v4.view.ViewPager android:id="@+id/vp_ui_viewpager" android:layout_width="wrap_content" android:layout_height="wrap_content"> <android.support.v4.view.PagerTitleStrip android:layout_width="wrap_content" android:layout_height="wrap_content"> </android.support.v4.view.PagerTitleStrip> </android.support.v4.view.ViewPager> </LinearLayout>
其中,ViewPager可以看到是以第三方控件的方式引入的,并且嵌入了一个PagerTitleStrip,用来显示标题栏。 - 准备我们的Activity:
package com.freesoft.activity.ui; import java.util.ArrayList; import java.util.List; import android.os.Bundle; import android.support.v4.app.FragmentActivity; 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 com.freesoft.android_learning.R; public class ActivityV4ViewPager extends FragmentActivity{ private ViewPager vp; private List<View> viewList; private List<String> titleList; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_ui_viewpager); // 添加三个显示界面 View v1, v2, v3; v1 = LayoutInflater.from(this).inflate(R.layout.activity_ui_viewpager_v4fragmentpageradapter_01, null); v2 = LayoutInflater.from(this).inflate(R.layout.activity_ui_viewpager_v4fragmentpageradapter_02, null); v3 = LayoutInflater.from(this).inflate(R.layout.activity_ui_viewpager_v4fragmentpageradapter_03, null); viewList = new ArrayList<View>(); viewList.add(v1); viewList.add(v2); viewList.add(v3); // 添加三个标题栏显示文字 titleList = new ArrayList<String>(); titleList.add("第一页"); titleList.add("第二页"); titleList.add("第三页"); vp = (ViewPager) findViewById(R.id.vp_ui_viewpager); vp.setAdapter(new MyPagerAdapter()); } class MyPagerAdapter extends PagerAdapter { // 注意官方文档中的说明,对于从PagerAdapter继承下来的类,必须实现以下四个方法 // instantiateItem(ViewGroup, int) // destroyItem(ViewGroup, int, Object) // getCount() // isViewFromObject(View, Object) // 获取fragment总数 @Override public int getCount() { return viewList.size(); } // 判断一个页面视图是否和instantiateItem返回值关联 @Override public boolean isViewFromObject(View view, Object object) { return view == object; } // 将已经加载的视图与需要实例化的碎片关联 @Override public Object instantiateItem(ViewGroup container, int position) { ((ViewPager)container).addView(viewList.get(position)); return viewList.get(position); } // 当碎片不再需要关联时,取消与已加载视图的关联 @Override public void destroyItem(ViewGroup container, int position, Object object) { ((ViewPager)container).removeView(viewList.get(position)); } // 这里覆盖这个方法是为了在PagerTitleStrip中显示文字 @Override public CharSequence getPageTitle(int position) { return titleList.get(position); } } }
- 这样,一个可滑动的多页视图例子就编写完成了。下面我们需要看几个在这基础上的例子。
android.support.v4.app.FragmentPagerAdapter
FragmentPagerAdapter是PagerAdapter的一个直接子类,每一个页面都会保存在碎片管理器中,这样用户可以随时回到页面中。
由于所有用户访问的页面都会保存在内存中,那么他的访问速度肯定是最快的,同时也是最消耗内存的(以空间换时间)。在页面不多的时候我们可以考虑使用这个Adapter,页面很多的情况下我们考虑使用FragmentStatePagerAdapter。
当我们使用FragmentPagerAdapter的时候,作为宿主/容器的ViewPager必须要有一个合法的id。
子类仅需要实现getItem(int)和getCount()方法,即可得到一个可工作的adapter。
下面是具体的例子。
我们首先看我们容器xml页面:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<!-- 演示ViewPager -->
<android.support.v4.view.ViewPager android:id="@+id/vp_ui_viewpager"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<android.support.v4.view.PagerTitleStrip
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</android.support.v4.view.PagerTitleStrip>
</android.support.v4.view.ViewPager>
</LinearLayout>
接着看我们的Activity页面:
package com.freesoft.activity.ui;
import java.util.ArrayList;
import java.util.List;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.freesoft.android_learning.R;
// 必须从FragmentActivity继承,因为其实现了getSupportFragmentManager方法
public class ActivityV4ViewPager extends FragmentActivity {
private ViewPager vp;
private List<String> titleList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ui_viewpager);
// 添加三个标题栏显示文字
titleList = new ArrayList<String>();
titleList.add("第一页");
titleList.add("第二页");
titleList.add("第三页");
vp = (ViewPager) findViewById(R.id.vp_ui_viewpager);
vp.setAdapter(new MyPagerAdapter(getSupportFragmentManager()));
}
class MyPagerAdapter extends FragmentPagerAdapter {
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
// 得到一个Fragment
@Override
public Fragment getItem(int position) {
return ArrayListFragment.newInstance(position);
}
@Override
public int getCount() {
return ArrayListFragment.resourceIds.size();
}
// 这里覆盖这个方法是为了在PagerTitleStrip中显示文字
@Override
public CharSequence getPageTitle(int position) {
return titleList.get(position);
}
}
public static class ArrayListFragment extends Fragment {
public static List<Integer> resourceIds = new ArrayList<Integer>();
private static int num = 0;
static {
resourceIds
.add(R.layout.activity_ui_viewpager_v4fragmentpageradapter_01);
resourceIds
.add(R.layout.activity_ui_viewpager_v4fragmentpageradapter_02);
resourceIds
.add(R.layout.activity_ui_viewpager_v4fragmentpageradapter_03);
}
/**
* 创建Fragment对象
*/
static ArrayListFragment newInstance(int num) {
ArrayListFragment f = new ArrayListFragment();
return f;
}
/**
* 在创建时被自动调用,所以我们需要在这里将视图反射出来
*/
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
int id = resourceIds.get(num);
View v = null;
if (num < resourceIds.size()) {
num++;
v = inflater.inflate(id, container, false);
}
return v;
}
}
}
google官方代码在这里:官方FragmentPagerAdapter代码,但个人感觉我的代码比官方代码更加简单易懂。
官方代码的Fragment使用了ListFragment,所以在内嵌的布局中必须嵌入一个android:id/list这个id的listview,如果内嵌布局需要注册listview中单项被点击的事件,这种方法倒是比较实用。
android.support.v4.app.FragmentStatePagerAdapter
FragmentStatePagerAdapter的实际使用和FragmentPagerAdapter是差不多的,这里不再赘述。
android.support.v13.app.FragmentPagerAdapter
到了v13,google终于不需要我们再从FragmentActivity继承,我们直接从Activity继承即可调用getFragmentManager来得到我们的FragmentManager,其余都和以前v4版本使用一样。
android.support.v13.app.FragmentStatePagerAdapter
不再赘述。