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