使用ViewPager加载Fragment

ViewPager的简介与使用

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <item name="viewPager" type="id"></item>

</resources>
package com.huangfei.criminalintent;

import java.util.ArrayList;
import java.util.UUID;

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.FragmentStatePagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;

public class CrimePagerActivity extends FragmentActivity {
    private ViewPager mViewPager;
    private ArrayList<Crime> mCrimes;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        /**
         * 以代码的方式创建视图并不奇怪,但我们还无法完全弃用XML文件,因为某些构件块依然需要资源ID。
         * FragmentManager要求任何用作fragment容器的视图都必须具有资源ID。
         * ViewPager是一个fragment容器,因此,必须赋予其资源ID。
         * 
         * 以代码的方式创建视图,应完成以下任务项:
         * 1、为ViewPager创建资源ID;
         * 2、创建ViewPager实例并赋值给mViewPager
         * 3、赋值资源ID给ViewPager,并对其进行配置;
         * 4、设置ViewPager为activity的内容视图
         * 
         * 定义独立资源ID与定义字符串资源ID并没有什么不同:在res/values目录下的XML文件中创建一个名为ids.xml的Android XML资源文件,
         * 用以存储资源ID,并在其中新增一个名为viewPager的ID。
         */
        mViewPager = new ViewPager(this);
        mViewPager.setId(R.id.viewPager);
        setContentView(mViewPager);

        mCrimes = CrimeLab.get(this).getCrimes();

        FragmentManager fm = getSupportFragmentManager();

        /**
         * FragmentStatePagerAdapter与FragmentPagerAdapter的区别:
         * FragmentStatePagerAdapter:使用FragmentStatePagerAdapter会销毁掉不需要的fragment。事务提交后。可将fragment从activity
         * 的FragmentManager中彻底移除。因此FragmentStatePagerAdapter更节省内存。
         * 
         * FragmentPagerAdapter:对于不需要的fragment,FragmentPagerAdapter则选择调用事务的detach(Fragment)方法,
         * 而非remove(Fragment)方法。FragmentPagerAdapter只销毁了fragment的视图,但仍将fragment实例保留在FragmentManager中。
         * 因此,FragmentPagerAdapter创建的fragment永远不会被销毁。
         * 
         * 当有大量fragment实例时,可选择FragmentStatePagerAdapter;而当用户只需少量且固定的fragment时,则选择FragmentPagerAdapter。
         */
        mViewPager.setAdapter(new FragmentStatePagerAdapter(fm) {

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

            @Override
            public Fragment getItem(int position) {
                Crime crime = mCrimes.get(position);
                return CrimeFragment.newInstance(crime.getId());
            }
        });

        /**
         * onPageScrolled(...)方法可告知我们页面将滑向哪里。
         * onPageScrollStateChanged(...)方法可告知我们当前页面所处的行为状态,如正在被用户滑动、页面滑动入位到完全静止以及页面切换完成后的闲置状态。
         * onPageSelected(...)方法可告知我们当前哪一个页面被选中。
         */
        mViewPager.setOnPageChangeListener(new OnPageChangeListener() {

            @Override
            public void onPageSelected(int position) {
                Crime crime = mCrimes.get(position);
                setTitle(crime.getTitle());
            }

            @Override
            public void onPageScrolled(int position, float posOffset, int posOffsetPixels) {
            }

            @Override
            public void onPageScrollStateChanged(int state) {
            }
        });


        UUID crimeId = (UUID) getIntent().getSerializableExtra(CrimeFragment.EXTRA_CRIME_ID);
        for (int i = 0; i < mCrimes.size(); i++) {
            if(mCrimes.get(i).getId().equals(crimeId)){
                mViewPager.setCurrentItem(i);
                break;
            }
        }
    }
}

ViewPager的工作原理

为什么选择使用ViewPager而不是AdapterView呢?AdapterView有一个用起来和ViewPager差不多的Gallery子类,为什么不用它呢?

由于无法使用现有的Fragment,在应用中,如使用AdapterView,则需要处理大量的内部实现工作。Adapter需要我们及时地提供View。然而,决定Fragment视图何时创建的是FragmentManager,而不是我们。所以,当Gallery要求提供Fragment视图时,我们无法立即创建Fragment视并提供其视图。

ViewPager使用的是PagerAdapter,而非原来的Adapter,PagerAdapter要比Adapter复杂的多,因为要处理更多的视图管理相关工作。PagerAdapter中代替可返回视图的getView(…)方法,采用了如下方法:

public Object instantiateItem(ViewGroup container, int position)
public void destroyItem(ViewGroup container, int position,Object object)
public boolean isViewFromObject(View view, Object object)

instantiateItem(ViewGroup, int)方法告诉PagerAdapter创建指定位置的列表项视图,然后将其添加ViewGroup给视图容器,而destroyItem(ViewGroup, int ,Object)方法则告诉PagerAdapter销毁已建视图。注意,instantiateItem(ViewGroup, int)方法对何时创建视图并无要求。因此,PagerAdapter可自行决定何时创建视图。

视图创建完成后,ViewPager会在某个时点注意它。为确定该视图所属的对象,ViewPager会调用isViewFromObject(View, Object)方法。这里,Object参数是instantiateItem(ViewGroup, int)方法返回的对象。因此,假设ViewPager调用instantiateItem(ViewGroup, 5)方法返回一个A对象,那么,只要传入参数是第5个对象的视图,isViewFromObject(View, Object)方法则应返回true,否则会返回false。

对ViewPager来说,这是一个复杂的过程,但对于PagerAdapter来说,这算不上什么,因为PagerAdapter只要能够创建、销毁视图以及识别视图来自那个对象即可。这样宽松的要求使得PagerAdapter能够比较自由地通过instantiateItem(ViewGroup, int)方法创建并添加新的Fragment,然后返回可以跟踪管理的FragmentObject。以下是isViewFromObject(View, Object)方法的具体实现。

@Override
public boolean isViewFromObject(View view, Object object) {
    return ((Fragment)object).getView() == view;
}

代码地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值