首页 > 其他 > 详细

ViewPager+Fragment 经典案例

时间:2017-01-11 15:58:09      阅读:375      评论:0      收藏:0      [点我收藏+]

简介

PagerAdapter是android.support.v4包中的类,它的子类有FragmentPagerAdapter, FragmentStatePagerAdapter相比通用的 PagerAdapter,后两个adapter 专注于每一页均为 Fragment 的情况。

FragmentPagerAdapter类内的每一个生成的 【Fragment】 都将保存在内存之中因此适用于那些相对静态、数量也比较少的那种。比如说一个有3-5个tab标签的fragment滑动界面,FragmentPagerAdapter会对我们浏览过所有Fragment进行缓存,保存这些界面的临时状态,这样当我们左右滑动的时候,界面切换更加的流畅。但是,这样也会增加程序占用的内存。

注意,上面所说的FragmentPagerAdapter只是会把Fragment本身保存在内存中,而不是把Fragment中的【View】也保存在内存中。实际上,除了当前页面及左右相邻两个页面中的Fragment中的View会被保存到内存中外,其余Fragment中的View都会销毁。也即所有浏览过的Fragment的【onDestroy】方法都不会被调用,但是除了当前页面及左右相邻两个页面外,Fragment的onDestroyView】方法都会被调用。

如果需要处理有很多页,并且数据动态性较大、占用内存较多的情况,应该使用FragmentStatePagerAdapter。

getItem()

这是该类中新增的一个虚函数,函数的目的为生成新的 Fragment 对象,在需要时,该函数将被 instantiateItem() 所调用。
如果需要向 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 和前面的 FragmentPagerAdapter 一样,是继承子 PagerAdapter。但是,和 FragmentPagerAdapter 不一样的是,正如其类名中的 ‘State‘ 所表明的含义一样,该 PagerAdapter 的实现将只保留当前页面,当页面离开视线后,就会被消除(除了会保留前后两个页面),释放其资源;而在页面需要显示时,生成新的页面(就像 ListView 的实现一样)。这么实现的好处就是当拥有大量的页面时,不必在内存中占用大量的内存。

代码

Activity

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.ImageView;
import android.widget.TextView;
public class MainActivity extends FragmentActivity implements OnClickListener {
    private ViewPager mViewPager;
    private PagerAdapter mPagerAdapter;
    private PagerAdapter mFragmentPagerAdapter;
    private PagerAdapter mFragmentStatePagerAdapter;
    private List<Fragment> mFragments = new ArrayList<Fragment>();
    //标题
    TextView tv_title;
    //四个TextView控件
    private TextView[] mTabTVs = new TextView[4];
    //四个控件【未】按下时的图片id
    private int[] mTabTVIdsNormal;
    //四个控件按下时的图片id
    private int[] mTabTVIdsPress;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);//取消标题栏
        setContentView(R.layout.main2);
        tv_title = (TextView) findViewById(R.id.tv_title);
        tv_title.setOnClickListener(this);
        initTabs();
        initViewPage();
        initPagerAdapter();
        setTabSelection(mTabTVs[0]);
        //mViewPager.setAdapter(mPagerAdapter);
        mViewPager.setAdapter(mFragmentPagerAdapter);//FragmentPagerAdapter类内的每一个生成的 【Fragment】 都将保存在内存之中
        //mViewPager.setAdapter(mFragmentStatePagerAdapter);
    }
    private void initTabs() {
        mTabTVs[0] = (TextView) findViewById(R.id.tv_tab_bottom_weixin);
        mTabTVs[1] = (TextView) findViewById(R.id.tv_tab_bottom_friend);
        mTabTVs[2] = (TextView) findViewById(R.id.tv_tab_bottom_contact);
        mTabTVs[3] = (TextView) findViewById(R.id.tv_tab_bottom_setting);
        mTabTVIdsNormal = new int[] { R.drawable.tab_weixin_normal, R.drawable.tab_find_frd_normal, R.drawable.tab_address_normal,
                R.drawable.tab_settings_normal };
        mTabTVIdsPress = new int[] { R.drawable.tab_weixin_pressed, R.drawable.tab_find_frd_pressed, R.drawable.tab_address_pressed,
                R.drawable.tab_settings_pressed };
        //给四个控件设置一个Tag,当我们点击某个控件时可以根据这个Tag来识别此控件,当然我们也可以根据v.getid()来识别,但在这里setTag还有其他妙用
        for (int i = 0; i < mTabTVs.length; i++) {
            mTabTVs[i].setOnClickListener(this);
            mTabTVs[i].setTag(i);
        }
    }
    private void initViewPage() {
        MainTabFragment wx = MainTabFragment.newInstance("微信 Arguments");
        MainTabFragment friend = MainTabFragment.newInstance("通讯录 Arguments");
        MainTabFragment find = MainTabFragment.newInstance("发现 Arguments");
        MainTabFragment mine = MainTabFragment.newInstance("我 Arguments");
        mFragments.add(wx);
        mFragments.add(friend);
        mFragments.add(find);
        mFragments.add(mine);
        mViewPager = (ViewPager) findViewById(R.id.id_viewpager);
        mViewPager.setOnPageChangeListener(new OnPageChangeListener() {
            @Override
            public void onPageSelected(int position) {
                setTabSelection(mTabTVs[position]);
            }
            @Override
            public void onPageScrollStateChanged(int arg0) {
            }
            @Override
            public void onPageScrolled(int arg0, float arg1, int arg2) {
            }
        });
    }
    private void initPagerAdapter() {
        mPagerAdapter = new PagerAdapter() {
            @Override
            public boolean isViewFromObject(View view, Object object) { // 判断是否是同一条目
                return view == object;
            }
            @Override
            public int getCount() {
                return mFragments.size();
            }
            public Object instantiateItem(ViewGroup container, int position) {// 初始化要显示的条目
                ImageView imageView = new ImageView(MainActivity.this);
                imageView.setImageResource(R.drawable.ic_launcher);
                container.addView(imageView);//一定将要显示的条目加入到ViewGroup的缓存容器中才可以显示
                return imageView;
            }
            public void destroyItem(ViewGroup container, int position, Object object) {//将要销毁的条目从ViewGroup的缓存容器中移除
                container.removeView((View) object);
            }
        };
        mFragmentPagerAdapter = new FragmentPagerAdapter(getSupportFragmentManager()) {
            @Override
            public int getCount() {
                return mFragments.size();
            }
            @Override
            public Fragment getItem(int position) {//只有在【新】生成 Fragment 对象时调用。注意:在调用notifyDataSetChanged() 后不会被调用
                Log.i("bqt""【getItem】被调用了-" + position);
                return mFragments.get(position);
            }
        };
        mFragmentStatePagerAdapter = new FragmentStatePagerAdapter(getSupportFragmentManager()) {
            @Override
            public int getCount() {
                return mFragments.size();
            }
            @Override
            public Fragment getItem(int position) {//尼玛尼玛尼玛:在调用notifyDataSetChanged() 后也会被调用啊!
                Log.i("bqt""【getItem】被调用了-" + position);
                return mFragments.get(position);
            }
        };
    }
    @Override
    /**
     *当下面tab的状态改变时,更改ViewPager选中项
     */
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.tv_title:
            MainTabFragment fragment = (MainTabFragment) mFragments.get(mViewPager.getCurrentItem());
            fragment.notifyData(new SimpleDateFormat("\nmm分 ss秒 SSS毫秒").format(new Date()));
            break;
        case R.id.tv_tab_bottom_weixin:
        case R.id.tv_tab_bottom_friend:
        case R.id.tv_tab_bottom_contact:
        case R.id.tv_tab_bottom_setting:
            setTabSelection(v);
            mViewPager.setCurrentItem((Integer) v.getTag());
            break;
        default:
            break;
        }
    }
    /**
     *当ViewPager选中项改变时,更改下面tab的状态
     */
    private void setTabSelection(View v) {
        //清除掉所有的选中状态
        for (int i = 0; i < mTabTVs.length; i++) {
            mTabTVs[i].setCompoundDrawablesWithIntrinsicBounds(0, mTabTVIdsNormal[i], 0, 0);
            mTabTVs[i].setSelected(false);
        }
        // 改变控件的图片,这里的setSelected是为了演示通过selector来改变文字颜色
        int index = (Integer) v.getTag();
        ((TextView) v).setCompoundDrawablesWithIntrinsicBounds(0, mTabTVIdsPress[index], 0, 0);
        v.setSelected(true);
    }
}

Fragment

import java.text.SimpleDateFormat;
import java.util.Date;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
/**
 * 使用support.v4.app中的Fragment
 * @author 白乾涛
 */
public class MainTabFragment extends Fragment {
    private TextView tv;
    private String mArgument;
    public static final String ARGUMENT = "name";
    /**构造时把传入的参数带进来*/
    public static MainTabFragment newInstance(String argument) {
        Bundle bundle = new Bundle();
        bundle.putString(ARGUMENT, argument);
        MainTabFragment fragment = new MainTabFragment();
        fragment.setArguments(bundle);
        return fragment;
    }
    @Override
    public void onCreate(Bundle savedInstanceState) {//创建【Fragment】时回调,只会调用一次,在Activity的onCreate()方法之【后】执行
        super.onCreate(savedInstanceState);
        Bundle bundle = getArguments();
        if (bundle != null) {
            mArgument = bundle.getString(ARGUMENT);
        }
        Log.i("bqt""【onCreate】-" + mArgument);
    }
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {//开始绘制Fragment的【View】时回调
        View view = inflater.inflate(R.layout.main_tab_01, container, false);
        tv = (TextView) view.findViewById(R.id.tv);
        tv.setText(new SimpleDateFormat("mm分 ss秒 SSS毫秒\n").format(new Date()) + mArgument);
        Log.i("bqt""onCreateView-" + mArgument);
        return view;
    }
    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {//Fragment的【View】绘制完成时回调
        super.onViewCreated(view, savedInstanceState);
        Log.i("bqt""onViewCreated-" + mArgument);
    }
    @Override
    public void onDestroyView() {//与onCreateView对应,销毁Fragment所包含的【View】时调用
        super.onDestroy();
        Log.i("bqt""onDestroyView-" + mArgument);
    }
    @Override
    public void onDestroy() {//销毁【Fragment】时被回调,在Activity的onDestroy()方法之【前】执行
        super.onDestroy();
        Log.i("bqt""【onDestroy】-" + mArgument);
    }
    public void notifyData(String data) {
        tv.append(data);
    }
}






附件列表

     

    ViewPager+Fragment 经典案例

    原文:http://www.cnblogs.com/baiqiantao/p/7ab233c6640a2af19c304c44d4465a91.html

    (0)
    (0)
       
    举报
    评论 一句话评论(0
    关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
    © 2014 bubuko.com 版权所有
    打开技术之扣,分享程序人生!