ViewPager 的用法详解

来源:互联网 发布:淘宝图片推荐几款相机 编辑:程序博客网 时间:2024/05/17 01:05

现在很多浏览类型app都是viewpager + fragment + 自定义tab的组合,比如网易新闻,优酷等。

使用这种组合的好处: 可以在一个Activity中处理多个页面,方便用户操作,视图结构清晰。

一、 viewpager 对应的几个adapter

PagerAdapter: 一般适配器,图片,view,Fragment都行。
FragmentPagerAdapter: 为PageAdapter子类,适用于数量较少的Fragment为页面。特点,每一个生成的Fragment都将保存到内存中,当不可见时,销毁Fragment的view,调用onDestroyView; 用户体验好
FragmentStatePagerAdapter: 为PageAdapter子类,适用于处理很多页,数据动态性较大,占用内存较多的Fragment为页面。 特点,当不可见时,整个Fragment都会销毁,调用onDestroy 和 onDestroyView; 数据需重新加载

一般PageAdapter中4个方法:
1. public int getCount():  返回当前有效视图的个数。
2. public boolean isViewFromObject(View view, Object object): 该函数用来判断instantiateItem(ViewGroup, int)函数所返回来的Key与一个页面视图是否是代表的同一个视图(即它俩是否是对应的,对应的表示同一个View)
3. public Object instantiateItem(ViewGroup container, int position): 这个函数的实现的功能是创建指定位置的页面视图。返回值:返回一个代表新增视图页面的Object(Key),这里没必要非要返回视图本身,也可以这个页面的其它容器。
4. public void destroyItem(ViewGroup container, int position, Object object): 该方法实现的功能是移除一个给定位置的页面。适配器有责任从容器中删除这个视图。这是为了确保在finishUpdate(viewGroup)返回时视图能够被移除。
5. public CharSequence getPageTitle(int position): 使用系统PagerTabStrip   PagerTitleStrip 返回的tab字符串

二、ViewPager 滑动页面的监听,一般可用于对自定义tab进行动画处理

   //viewPager.setOnPageChangeListener(myOnPageChangeListener);  被弃用。  下面区别是将listener放入集合中   viewPager.addOnPageChangeListener(myOnPageChangeListener);   private MyOnPageChangeListener myOnPageChangeListener = new MyOnPageChangeListener();    public class MyOnPageChangeListener implements ViewPager.OnPageChangeListener {        @Override    //滑动的过程调用   位置     当前页面屏幕的百分比    当前页面偏移的像素位置           public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {            Log.d("stormxz", "onPageScrolled  111");        }        @Override    //当前页面的位置        public void onPageSelected(int position) {            Log.d("stormxz", "onPageScrolled  222");        }        @Override    //状态  1开始  2正在滑动  0结束        public void onPageScrollStateChanged(int state) {            Log.d("stormxz", "onPageScrollStateChanged  333");        }    }
   
   一般用来对自定义tabbar 进行位置,动画设置

三、3种adapter使用Fragment + viewPager

1. PagerAdapter 

package com.example.stormxz.viewpagerdemo;import android.support.v4.app.Fragment;import android.support.v4.app.FragmentManager;import android.support.v4.app.FragmentTransaction;import android.support.v4.view.PagerAdapter;import android.view.View;import android.view.ViewGroup;import java.util.ArrayList;/** * Created by stormxz on 2017/9/6. */public class MyViewPagerAdapter extends PagerAdapter {    private ArrayList<Fragment> fragments = new ArrayList<Fragment>();    private ArrayList<String> titles = new ArrayList<String>();    private FragmentManager fragmentManager = null;    public MyViewPagerAdapter(ArrayList<Fragment> viewArrayList, ArrayList<String> titlesList, FragmentManager fragmentManager) {        this.fragments = viewArrayList;        this.titles = titlesList;        this.fragmentManager = fragmentManager;    }    @Override    public int getCount() {   //返回fragment 的个数        return fragments.size();    }    @Override    public boolean isViewFromObject(View view, Object object) {        return view == object;  //判读当前View是否一致    }    @Override    public Object instantiateItem(ViewGroup container, int position) {        Fragment fragment = fragments.get(position);        if (fragment != null) {            if (!fragment.isAdded()){  //判读当前fragment是否已经提交 ,如果没有,则创建事务,进行提交                FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();                fragmentTransaction.add(fragment, fragment.getClass().getSimpleName());                fragmentTransaction.commitAllowingStateLoss();                /**                 * 在用FragmentTransaction.commit()方法提交FragmentTransaction对象后 会在进程的主线程中,用异步的方式来执行。                 * 如果想要立即执行这个等待中的操作,就要调用这个方法(只能在主线程中调用)。 要注意的是,所有的回调和相关的行为都会在这个调用中被执行完成,因此要仔细确认这个方法的调用位置。                 */                fragmentManager.executePendingTransactions();            }            if (fragment.getView() != null) {                container.addView(fragment.getView());            }        }        return fragment.getView();    }    @Override    public void destroyItem(ViewGroup container, int position, Object object) {        container.removeView(fragments.get(position).getView());  //removeView    }    @Override    public CharSequence getPageTitle(int position) {        return titles.get(position);   //返回tab 文字信息    }}

MainActivity.java  传递FragmentManager   tabname   Fragment集合
    myViewPagerAdapter = new MyViewPagerAdapter(fragments, titles, getSupportFragmentManager());    viewPager.setAdapter(myViewPagerAdapter);

一般不建议使用PagerAdapter. 建议使用其子类FragmentPagerAdapter  以及 FragmentStatePagerAdapter

2.  FragmentPagerAdapter  与   FragmentStatePagerAdapter 

只需要重新2个方法即可
package com.example.stormxz.viewpagerdemo;import android.support.v4.app.Fragment;import android.support.v4.app.FragmentManager;import android.support.v4.app.FragmentPagerAdapter;import android.support.v4.app.FragmentStatePagerAdapter;import java.util.ArrayList;/** * Created by stormxz on 2017/9/11. */public class MyFragmentAdapter extends FragmentPagerAdapter {    private ArrayList<Fragment> fragments = new ArrayList<Fragment>();    public MyFragmentAdapter(FragmentManager fm, ArrayList<Fragment> fragments) {        super(fm);        this.fragments = fragments;    }    @Override    public Fragment getItem(int position) {        return fragments.get(position);    }    @Override    public int getCount() {        return fragments.size();    }}

MainActivity.java 中传递FragmentManager  以及Fragment的集合;  给ViewPager添加适配器
    myFragmentAdapter = new MyFragmentAdapter(getSupportFragmentManager(), fragments);    viewPager.setAdapter(myFragmentAdapter);

源码中已经实现
   @Override    public Object instantiateItem(ViewGroup container, int position) {        // If we already have this item instantiated, there is nothing        // to do.  This can happen when we are restoring the entire pager        // from its saved state, where the fragment manager has already        // taken care of restoring the fragments we previously had instantiated.        if (mFragments.size() > position) {            Fragment f = mFragments.get(position);            if (f != null) {                return f;            }        }        if (mCurTransaction == null) {   //获得事务            mCurTransaction = mFragmentManager.beginTransaction();        }        Fragment fragment = getItem(position);        if (DEBUG) Log.v(TAG, "Adding item #" + position + ": f=" + fragment);        if (mSavedState.size() > position) {            Fragment.SavedState fss = mSavedState.get(position);            if (fss != null) {                fragment.setInitialSavedState(fss);            }        }        while (mFragments.size() <= position) {            mFragments.add(null);        }        fragment.setMenuVisibility(false);        fragment.setUserVisibleHint(false);  //设置为不可见        mFragments.set(position, fragment);        mCurTransaction.add(container.getId(), fragment);  //添加Fragment        return fragment;    }

事务提交
 @Override    public void finishUpdate(ViewGroup container) {        if (mCurTransaction != null) {            mCurTransaction.commitNowAllowingStateLoss();            mCurTransaction = null;        }    }

判断fragment是否是当前的,是则设置为用户可见
@Override    public void setPrimaryItem(ViewGroup container, int position, Object object) {        Fragment fragment = (Fragment)object;        if (fragment != mCurrentPrimaryItem) {            if (mCurrentPrimaryItem != null) {                mCurrentPrimaryItem.setMenuVisibility(false);                mCurrentPrimaryItem.setUserVisibleHint(false);            }            if (fragment != null) {                fragment.setMenuVisibility(true);                fragment.setUserVisibleHint(true);            }            mCurrentPrimaryItem = fragment;        }    }

四、 系统PagerTabStrip   PagerTitleStrip

1. 使用,将其作为子类View 放入ViewPager中
<android.support.v4.view.ViewPager        android:id="@+id/view_pager"        android:layout_width="368dp"        android:layout_height="495dp"        tools:layout_editor_absoluteY="8dp"        tools:layout_editor_absoluteX="8dp">        <android.support.v4.view.PagerTabStrip            android:id="@+id/pager_tab_strip"            android:layout_width="wrap_content"            android:layout_height="wrap_content">        </android.support.v4.view.PagerTabStrip><!--        <android.support.v4.view.PagerTitleStrip            android:id="@+id/pager_title_strip"            android:layout_width="wrap_content"            android:layout_height="wrap_content">        </android.support.v4.view.PagerTitleStrip>-->    </android.support.v4.view.ViewPager>

2. 在Adapter中传入tabname集合,并在不同位置进行提取
    @Override    public CharSequence getPageTitle(int position) {        return titles.get(position);    }

相同点: 
(1)作为ViewPager内部控件进行使用,只需要重写adapter中的getPageTitle(return position的字符串)
(2) android:layout_gravity 属性设置为TOP或BOTTOM来将它显示在ViewPager的顶部或底部。

不同点: PagerTabStrip 支持点击tab进行跳转页面,有下划线; PagerTitleStrip 则无

主流app  不会用

原创粉丝点击