ViewPager 入门到精通(一)

来源:互联网 发布:阿里巴巴php招聘 编辑:程序博客网 时间:2024/05/16 19:44

一 基本简介

      ViewPager 的存在意义就在于它能够让用户左右滑动屏幕来进行换页,为了实现这个功能,你需要加载一个 PagerAdapter 来实现这些需要滑动的view 的显示.

      ViewPager 大多情况下是和Fragment 联合使用的,这样提供了一个方便的管理每个page的lifecycle的方式。 一般来说,用户可以使用三种类型的PagerAdaper:

      1.PagerAdapter    2.FragmentPagerAdapter  3.FragmentStatePagerAdapter, 但是使用过ListView 的都应该清楚,这种使用adapter的方式是类似的。

     1. 1. 类继承关系如下:

           java.lang.Object

              android.view.View

                   android.view.ViewGroup

                        android.support.v4.view.ViewPager

     1.2  总括

           官方文档如下:

          Layout manager that allows the user to flip left and right through pages of data. You supply an implementation of a PagerAdapter to generate the pages that the view shows. Note this class is currently under early design and development. The API will likely change in later updates of the compatibility library, requiring changes to the source code of apps when they are compiled against the newer version. ViewPager is most often used in conjunction with Fragment, which is a convenient way to supply and manage the lifecycle of each page. There are standard adapters implemented for using fragments with the ViewPager, which cover the most common use cases. These are FragmentPagerAdapter and FragmentStatePagerAdapter; each of these classes have simple code showing how to build a full user interface with them.
          总的来说就如下几条:

          a  ViewPager主要用来左右滑动。(类似图片轮播)
          b  ViewPager要用适配器来连接“视图”和“数据”。(大家可以联想下listview的使用方法,原理是类似的)
          c  官方推荐ViewPager与Fragment一起使用,并且有专门的适配器。

   1.3  使用  PagerAdapter

        当你实现一个PagerAdapter时,你至少需要重写下面的几个方法:

            instantiateItem(ViewGroup, int)

            destroyItem(ViewGroup, int, Object)

            getCount()

            isViewFromObject(View, Object)

      先添加layout_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.support.v4.view.ViewPager        android:id="@+id/view_pager"        android:layout_width="match_parent"        android:layout_height="match_parent">    </android.support.v4.view.ViewPager></LinearLayout>


    再添加3个 page1.xml  page2.xml page3.xml

 

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent">    <ImageView        android:id="@+id/iv_first"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:layout_centerInParent="true"        android:scaleType="centerInside"        android:background="@drawable/a2"/></RelativeLayout>
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent" android:layout_height="match_parent">    <ImageView        android:id="@+id/iv_second"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:layout_centerInParent="true"        android:background="@drawable/aaa"        android:scaleType="centerInside"/></RelativeLayout>


 

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent" android:layout_height="match_parent">    <ImageView        android:id="@+id/iv_thrid"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:layout_centerInParent="true"        android:scaleType="centerInside"        android:background="@drawable/aab"/></RelativeLayout>

在 MainActivity.java 中的代码:

 protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.layout_viewpager);        initView();    }    private void initView() {        myViewPager = (ViewPager)findViewById(R.id.view_pager);        LayoutInflater inflater = getLayoutInflater();        page1 = inflater.inflate(R.layout.page1, null);        page2 = inflater.inflate(R.layout.page2, null);        page3 = inflater.inflate(R.layout.page3, null);        pageList = new ArrayList<View>();        pageList.add(page1);        pageList.add(page2);        pageList.add(page3);        myPageAdapter = new MyPageAdapter();        myViewPager.setAdapter(myPageAdapter);    }    public class MyPageAdapter extends PagerAdapter {
        // 下面这个方法是用来显示 一个PagerView的内容的,由于图片显示的问题,或许会有OOM,或许会有耗时太大,这些不是本文的重点
        @Override        public Object instantiateItem(ViewGroup container, int position) {            Log.v(TAG, "instantiateItem position " + position);            View view = pageList.get(position);            container.addView(view);            return view;        }        @Override        public void destroyItem(ViewGroup container, int position, Object object) {            container.removeView(pageList.get(position));        }        @Override        public int getCount() {            return pageList.size();        }        @Override        public boolean isViewFromObject(View view, Object object) {            return view == object;        }    }

         一个最简单的PagerViewer就可以显示出来使用了。

       1.4 FragmentPagerAdapter 的使用

        大体上来说,这个和PagerAdapter的使用逻辑是相同的,只是它将简单的PagerAdapter换从了 FragmentPagerAdapter,从而Adapter的内容需要根据使用的Fragment 

       的情况来进行丰富,另外,MainActivity需要 进行一些针对fragment 和Activity 组合时的特殊效果,例如 tabcontent添加,又如tabitem 的动画效果等等。

        下面的代码添加了一些关于ViewPager 滚动的事件监听的接口,用来深入对ViewPager 的了解,滚动的监听无法就像 给普通的 view 添加 onClickHandlerListener一样

      我们需要给 ViewPager 添加一个 ViewPager.OnPageChangeListener ,而它又包含了几个接口内容的实现而已,具体细节请看下面的代码:

    

public class MainActivity extends AppCompatActivity implements        ViewPager.OnPageChangeListener{    private static String TAG = "PageView";    private ViewPager myViewPager;//    private View page1;//    private View page2;//    private View page3;//    private ArrayList<View> pageList;////    private MyPageAdapter myPageAdapter;    private List<Fragment> fragmentList;    private MyFragmentAdapter myFragmentAdapter;    private TextView tab1;    private TextView tab2;    private TextView tab3;    private ImageView line_tab;    private int moveOne;    private boolean isScrolling;    private boolean isFingerLeaved;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.layout_viewpager);        initView();    }    private void initView() {        myViewPager = (ViewPager)findViewById(R.id.view_pager);        fragmentList = new ArrayList<Fragment>();        CountingFragment f1 = new CountingFragment();        CursorFragment f2 = new CursorFragment();        ListFragment f3 = new ListFragment();        fragmentList.add(f1);        fragmentList.add(f2);        fragmentList.add(f3);        MyFragmentAdapter myFragmentAdapter = new MyFragmentAdapter(getSupportFragmentManager(),fragmentList);        myViewPager.setAdapter(myFragmentAdapter);        myViewPager.setOnPageChangeListener(this);        /**         * 给每个fragment 添加一个tab,让这些tab的按键事件于fragment的显示相关联起来         * 通过下面的代码我们可以看到两点:         * 1: 代码的设计是有问题的,因为当添加一个fragment的时候,这个activity就需要修改,没有遵守 面向对象的设计思想         * 2:FragmentPagerAdapter 的模式只适合于在具有少数的几个fragment的方式下使用,因为这些fragment一直是缓存着         */        tab1 = (TextView)findViewById(R.id.tv_page1);        tab1.setTextColor(Color.BLUE);        tab2 = (TextView)findViewById(R.id.tv_page2);        tab3 = (TextView)findViewById(R.id.tv_page3);        tab1.setOnClickListener(myClickListener);        tab2.setOnClickListener(myClickListener);        tab3.setOnClickListener(myClickListener);        initLineImage();//        LayoutInflater inflater = getLayoutInflater();////        myPageAdapter = new MyPageAdapter();//        myViewPager.setAdapter(myPageAdapter);    }    /**     * 在设计好了tab 和 fragment 在 ViewPager 上面联动之后,我们发现fragment的设计中一般会在tab下面显示一个     * line,这个接口就是为了初始化这个line,设置其长度和参数     */    private void initLineImage() {        line_tab = (ImageView)findViewById(R.id.iv_line);        DisplayMetrics dm = new DisplayMetrics();        getWindowManager().getDefaultDisplay().getMetrics(dm);        int screenWidth = dm.widthPixels;        ViewGroup.LayoutParams lp = line_tab.getLayoutParams();        lp.width = screenWidth / 3;        line_tab.setLayoutParams(lp);        moveOne = lp.width;    }    /*       动态的实现了tab下面 line的显示动画,这个动画是已经被android封装好了的,比较简单     */    private void movePositionX(int toPosition, float positionOffset) {        float curTranslationX = line_tab.getTranslationX();        float toPositionX = moveOne * toPosition + positionOffset;        ObjectAnimator animator = ObjectAnimator.ofFloat(line_tab, "translationX", curTranslationX, toPositionX);        animator.setDuration(500);        animator.start();    }    //让tab 按键和 viewPager 的fragment进行事件的联动    View.OnClickListener myClickListener = new View.OnClickListener() {        @Override        public void onClick(View v) {            switch (v.getId()) {                case R.id.tv_page1:                    tab1.setTextColor(Color.BLUE);                    tab2.setTextColor(Color.BLACK);                    tab3.setTextColor(Color.BLACK);                    //                    myViewPager.setCurrentItem(0);                    break;                case R.id.tv_page2:                    myViewPager.setCurrentItem(1);                    tab2.setTextColor(Color.BLUE);                    tab1.setTextColor(Color.BLACK);                    tab3.setTextColor(Color.BLACK);                    break;                case R.id.tv_page3:                    myViewPager.setCurrentItem(2);                    tab3.setTextColor(Color.BLUE);                    tab2.setTextColor(Color.BLACK);                    tab1.setTextColor(Color.BLACK);                    break;            }        }    };    /**     *  onPageScrolled()/onPageSelected()/onPageScrollStateChanged     *  这三个函数都是 ViewPager.OnPageChangeListener 继承而来,它们就类似于对于普通view的 handler事件一样,只是     *  由于ViewPager的特殊性,它具备了三个接口,分别是如下,onPageScrolled()这个是在ViewPager正在滚动时调用     *  在真机中,这个onPageScrolled()调用非常频繁,不能在里面直接写updateUI的操作,在这里就不详细说明了     * @param position     * @param positionOffset     * @param positionOffsetPixels     */    @Override    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {        if (isScrolling == true) {            movePositionX(position, positionOffset * moveOne);        } else if (isFingerLeaved == true) {            movePositionX(position, 0.0f);        }    }    /**     * 滚动ViewPager 完成后将调用这个接口,这个接口的作用一般是做滚动操作的最后动作     * @param position     */    @Override    public void onPageSelected(int position) {        Log.v(TAG, "onPageSelected position: " + position);        switch (position) {            case 0:                tab1.setTextColor(Color.BLUE);                tab2.setTextColor(Color.BLACK);                tab3.setTextColor(Color.BLACK);                movePositionX(0, 0.0f);                break;            case 1:                tab2.setTextColor(Color.BLUE);                tab1.setTextColor(Color.BLACK);                tab3.setTextColor(Color.BLACK);                movePositionX(1, 0.0f);                break;            case 2:                tab3.setTextColor(Color.BLUE);                tab2.setTextColor(Color.BLACK);                tab1.setTextColor(Color.BLACK);                movePositionX(2, 0.0f);                break;        }    }    /**     * 这个接口是用于获取scroll 的状态的,当手指正在drag的过程中,它的状态是SCROLL_STATE_DRAGGING     * 当滚动的drag动作已经完成了,手离开了view,且View的显示还没有完全切换完,正在走向完成的时候,它     * 的状态是SCROLL_STATE_SETTLING, 没有任何操作的是是 SCROLL_STATE_IDLE     * @param state     */    @Override    public void onPageScrollStateChanged(int state) {        switch (state) {            case ViewPager.SCROLL_STATE_IDLE:                isScrolling = false;                isFingerLeaved = false;                break;            case ViewPager.SCROLL_STATE_DRAGGING:                isScrolling = true;                isFingerLeaved = false;                break;            case ViewPager.SCROLL_STATE_SETTLING:                isScrolling = false;                isFingerLeaved = true;                break;        }    }}

    FragmentPagerAdapter 的实现如下:

    切记: 它需要实现的两个接口只有 getItem(int position),用于返回需要显示的Fragment, getCount()用于显示需要返回的Adapter的大小。

    

public class MyFragmentAdapter extends FragmentPagerAdapter {    private List<Fragment> fragmentList;    public MyFragmentAdapter(FragmentManager fm, List<Fragment> fragmentList) {        super(fm);        this.fragmentList = fragmentList;    }    @Override    public Fragment getItem(int position) {        Log.v("Kyle" , "getItem " + position);        return fragmentList.get(position);    }    @Override    public int getCount() {        return fragmentList.size();    }}

上面的代码,还缺少了XML 和 Fragment,其中 Fragment 就是定义了普通的Fragment 创建即可,而主要的XML 也就是main_activity_Layout了,这个如下所示:

<?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="vertical">    <include layout="@layout/tab"/>    <ImageView        android:id="@+id/iv_line"        android:layout_width="wrap_content"        android:layout_height="1dp"        android:background="@color/colorblue"/>    <android.support.v4.view.ViewPager        android:id="@+id/view_pager"        android:layout_width="match_parent"        android:layout_height="match_parent">    </android.support.v4.view.ViewPager></LinearLayout>

layout/tab" 如下所示:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:id="@+id/tab"    android:orientation="horizontal"    android:layout_width="match_parent"    android:layout_height="50dp"    >    <TextView        android:id="@+id/tv_page1"        android:layout_width="0dp"        android:layout_weight="1"        android:layout_height="match_parent"        android:gravity="center"        android:text="Page1"        android:textColor="#ff000000"        android:textSize="16sp"/>    <TextView        android:id="@+id/tv_page2"        android:layout_width="0dp"        android:layout_weight="1"        android:layout_height="match_parent"        android:gravity="center"        android:text="Page2"        android:textColor="#ff000000"        android:textSize="16sp"/>    <TextView        android:id="@+id/tv_page3"        android:layout_width="0dp"        android:layout_weight="1"        android:layout_height="match_parent"        android:gravity="center"        android:text="Page3"        android:textColor="#ff000000"        android:textSize="16sp"/></LinearLayout>



 

1.5  FragmentStateAdapter

        FragmentStatePagerAdapter更多用于大量页面,例如视图列表。当某个页面对用户不再可见时,他们的整个fragment就会被销毁,仅保留fragment状态。相比于

        FragmentPagerAdapter,这样做的好处是在访问各个页面时能节约大量的内存开销,但代价是在页面切换时会增加非常多的开销。

        具体实现区别并不太大,只是适用的环境有所变化而已,这里暂时由于时间原因就不详细说明的,等下次回想起来时再来完善

    




    




    

 

 

   

 

 

    

 

 

        

 

 

0 0
原创粉丝点击