Android22--Android之ViewPager的使用

1.ViewPager的介绍

ViewPager是是Support-v4的包中类,实现在一个布局中,能够进行多个内容界面的切换,通过手指的滑动,可以让这些界面平滑滚动。简单来说,他就是管理ViewPager中添加的Fragment的滑动的.
官方是这样介绍的:

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.

2.ViewPager的适配器

ViewPager是实现页面产生滑动的效果的,首先我们需要在布局中添加一个ViewPager,然后写一个适配器,再为我们的ViewPager添加上适配器,之后就可以愉快地滑滑滑页面了.我们将介绍三个适配器PagerAdapter/FragmentPagerAdapter/FragmentStateAdapter

1.,PagerAdapter

使用:

1. PagerAdapter必须要创建一个子类继承ViewPager,才可以在ViewPager上使用。子类必须实现四个方法..
2.  getCount() 方法来控制页面数量
3. isViewFromObject(View, Object) 检查View是否从Object中得来
4. instantiateItem 方法来进行视图的创建,instantiateItem 方法内部必须手动调用 container.addView,如果加载布局,要使用 类似ListView内部加载的方式.
5. destroyItem 方法,必须重写, 用于释放 instantiateItem创建的控件。
6. 最后ViewPager setAdapter 进行设置。

ViewPager的预加载

1. ViewPager总是保留/加载当前位置相邻的内容。
2. ViewPager默认显示第0个位置,自然就会预加载 1
3. ViewPager显示1位置时,会预加载 2,当ViewPage调整显示位置时,当前位置相邻的两个内容以外的内容,需要销毁;
4. 如当前已经加载了 0, 1, 2, 这个时候,当移动显示到2的时候,会销毁 0, 并且加载 3
5. 第0位置的索引和,最后一个索引,都只会保留一个相邻的内容。
6. 我们可以使用`mPager.setOffscreenPageLimit(2); 手动设置一次预加载的Fragment的数量。`

2.首先我们来看一张ViewPager的继承关系图

这里写图片描述

3.FragmentPagerAdapter

FragmentPagerAdapter的使用

FragmentPagerAdapter
1. 可以在ViewPager中显示Fragment的内容
2. 提供复杂的ViewPager与界面的功能的组合
3. 子类实现 getCount() 返回Fragment的总个数;
4. 子类实现 Fragment getItem(int position) 获取第几个Fragment;
5. 在Adapter之外创建List集合来存Fragment,这样,传递给Adapter的时候,就不需要判断索引了,直接获取Fragment就行了,由Activity来控制显示什么。

FragmentPagerAdapter预加载方式,

1.Fragment生命周期管理:类似于PagerAdapter,每一个加载的时候,都会进入到resume()状态,当需要销毁的时候,并不是真正的销毁Fragment,而是进行视图的销毁,因此,每一个Fragment在移除的时候,都是调用到 onDestroyView() 这个状态;再次需要显示的时候,直接onCreateView() 回复状态。

2.对于数据的加载,再Fragmnet onCreate 当中进行的话,相当于只执行一次,不论ViewPager如何滑动,也只是执行一次。再次显示时,会从onResume()方法开始。

3.如果需要每次切换回来,进行刷新,那么就不应该在onCreate进行获取。如果在onCreate和 onResume() 中都进行加载,那么也是可以的。 onCreate 用于初始化一次的数据加载。onResume() 进行数据的刷新。

附注:

1. FragmentPagerAdapter 在切换Fragment的时候,当一个Fragment 需要移出布局的时候,会根据声明周期方法,调用到 onDestroyView,用于释放UI资源;但是不会再继续销毁了,Fragment的数据依然会保留;便于下一次ViewPager再显示这个Fragment的时候,直接恢复UI就可以了;

2. 应用场景:通常都是应用程序最外层的Tab的管理,用于固定数量的、数据不需要大量刷新的场景;也就是软件主界面的Tab管理;

注意:

1.我们在继承FragmentPagerAdapter时,他的构造方法需要一个FragmentManager类型的参数,会有两种不同情况的处理。比如:

  // 参数1 FragmentManager :如果在Activity中,创建的Adapter, 那么必须使用 getSupportFragmentManager
        //                        如果在Fragment内部,创建Adapter,那么必须调用 getChildFragmentManager
        CommonFragmentPagerAdapter adapter = new CommonFragmentPagerAdapter(
                getSupportFragmentManager(),
                fragmentList
        );

2 . 如果我们想在再次进入同一个Fragment时, 实现FragmentPagerAdapter不会进行自动数据的刷新,也就是不会自动notifyDataSetChanged();如果要刷新,我么可以在onResume()方法中执行我们想要刷新的数据。

3.默认情况下,当前ViewPager如果显示 0 位置的,那么 1位置的Fragment 也会 onResume,如果进行进行网络加载,那么会同时加载两个Fragment的数据。我们要尽量避免显示一些对话框类似的东西,因为这个时候我们不知道是显示的是哪一个页面的,也会有混乱的现象。

4.FragmentStatePagerAdapter

用法:

1.他的用法和FragmentPagerAdapter类似,
2.FragmentStatePagerAdapter操作Fragment时,再次回到相同的页面,会自动刷新,也就是自带notifyDataSetChanged();
3.在进行切换时,会执行到Fragment的onDstory(),不会进行数据的保存。

5.两种适配器的区别

1. FragmentPagerAdapter 会在切换的时候,会进行onDestroyView 的调用.

2. FragmentStatePagerAdapter,,会进行onDestroy 的调用.用于加载大量的Fragment用的,会减少一些内存问题,速度会慢一些;

3. 对于每次销毁Fragment,再onCreate 这种,从运行效率上面,会慢一些;但是内存占用小一些。

4. 官方的说明:
FragmentPagerAdapter 用于数量是固定的,并且少量的Fragment显示的时候,来使用。应用场景:应用程序的模块划分;
FragmentStatePagerAdapter: 用于数量多的,数量变化的Fragment显示;应用场景:支持 notifyDataSetChanged()

3.ViewPager的使用

1.ViewPager+Fragment

简单的应用,使用ViewPager管理Fragment的显示。
1.首先在Fragment的布局中添加一个ViewPager

/**
*需要注意的是ViewPage 高度设置为 wrap_content 与设置
*match_parent 效果是一样的,所以如果需要设定高度,那么,请使用高度数
*值如 150dp
*/
   <android.support.v4.view.ViewPager
        android:id="@+id/main_pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </android.support.v4.view.ViewPager>

2。编写适配器继承FragmentPagerAdapter或者FragmentStatePagerAdapter,实现其中的方法。
3. 为pager setAdapter();

2.ViewPager + Tab

他们有下面的关系
这里写图片描述

几个重要的方法。。

1。ViewPager 通过  setCurrentItem(int pos) 来切换当前页面,从0开始,指定几就是几
2。setCurrentItem(int pos, boolean smooth) 是否平滑切换
3。ViewPager addOnPageChangeListener 设置 页面拖拽的事件监听
通过这个方法,进行RadioGroup 的选中切换

我们一般的设计是,让一个Activity中,有这样的布局:

<RadioGroup
        android:id="@+id/main2_bot_bar"
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="10dp"
        android:layout_height="wrap_content">

         ... RadioButton

    </RadioGroup>
    <android.support.v4.view.ViewPager
        android:id="@+id/main2_pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

之后我们要实现tab和pager之间的联动,我们就需要分别设置适配器了。

public class Main2Activity extends AppCompatActivity implements RadioGroup.OnCheckedChangeListener, ViewPager.OnPageChangeListener {

    private List<Fragment> mFragment;
    private ViewPager mPager;
    private RadioGroup mGroup;
    private TextView mIndicator;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        mPager = (ViewPager) findViewById(R.id.main2_pager);
        mGroup = (RadioGroup) findViewById(R.id.main2_bot_bar);
        mIndicator = (TextView) findViewById(R.id.txt_indicator);

        mFragment = new ArrayList<>();
        mFragment.add(new FirstFragment());
        mFragment.add(new SecondFragment());
        mFragment.add(new ThreeFragment());
        mFragment.add(new FourFragment());

        CommonFragmentAdapter adapter = new CommonFragmentAdapter(getSupportFragmentManager(), mFragment);
        mPager.setAdapter(adapter);


        mGroup.check(R.id.tab_bar_home);
        mPager.addOnPageChangeListener(this);
        mGroup.setOnCheckedChangeListener(this);
    }

    // 实现tab和pager联动
    @Override
    public void onCheckedChanged(RadioGroup group, int checkedId) {
        switch (checkedId) {
            case R.id.tab_bar_home:
            // 第二个参数,默认为true,试一下情况,会有卡的现象。
                mPager.setCurrentItem(0, false);
                break;
            case R.id.tab_bar_find:
                mPager.setCurrentItem(1, false);
                break;
            case R.id.tab_bar_message:
                mPager.setCurrentItem(2, false);
                break;
            case R.id.tab_bar_my:
                mPager.setCurrentItem(3, false);
                break;
        }
    }

// Pager的监听事件
    /**
     * 当页面在持续滚动的时候,会自动回调,能够表示页面滚动的情况
     * 可以显示指示器
     * @param position
     * @param positionOffset
     * @param positionOffsetPixels
     */
    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        View at = mGroup.getChildAt(position);
        // 2. 获取指定指示器控件的坐标
        float x = ViewCompat.getX(at);
        // 3. 计算指示器的位置
        // positionOffset 代表移动一小格的百分比,也就是当前RadioButton宽度的百分比距离
        x = x + (at.getWidth() * positionOffset);
        ViewCompat.setX(mIndicator, x);
    }

    /**
     * 滚动时,切换新页面时,调用的方法
     *
     * @param position
     */
    @Override
    public void onPageSelected(int position) {
        switch (position) {
            case 0:
                mGroup.check(R.id.tab_bar_home);
                break;
            case 1:
                mGroup.check(R.id.tab_bar_find);
                break;
            case 2:
                mGroup.check(R.id.tab_bar_message);
                break;
            case 3:
                mGroup.check(R.id.tab_bar_my);
                break;
        }

    }

// 当前Tab已经是选中的情况下,再次点击这个Tab,会回调这个方法,可以设置刷新
    @Override
    public void onPageScrollStateChanged(int state) {

    }
}

会有这样的一个效果
这里写图片描述

3.ViewPager + ViewPager

在我们日常的一些软件中,我们可以看出,在一个ViewPager中有很多个Fragment,在一个Fragment中可能又有很多个Tab,在一个Tab中,又会有ViewPager(图片的自动播放),比如一些软件:今日头条 爱奇艺 内涵段子等。
下面是其中的一种做法:

public class FirstFragment extends Fragment implements Runnable {


    private ViewPager mPager;
    public int index = 1500;
    private Handler myHandler;

    public FirstFragment() {
    }

    @Override
    public void onResume() {
        super.onResume();
        Thread thread = new Thread(this);
        thread.start();
    }

    @Override
    public void run() {
        while (true) {
            try {
                index++;
                Message message = myHandler.obtainMessage(1);
                if (index >= 3000) {
                    index = 1500;
                }
                message.arg1 = index;
                myHandler.sendMessage(message);
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View ret = inflater.inflate(R.layout.fragment_first, container, false);

        mPager = (ViewPager) ret.findViewById(R.id.fristf_pager);


        // Fragment内部实现ViewPager
        List<Integer> images = new ArrayList<>();
        images.add(R.mipmap.ic_launcher);
        images.add(android.R.drawable.ic_delete);
        images.add(android.R.drawable.ic_delete);
        images.add(android.R.drawable.ic_delete);

        PictrueAdapter pictrueAdapter = new PictrueAdapter(images, getContext());

        mPager.setAdapter(pictrueAdapter);
        myHandler = new AdHandler(mPager);

        return ret;
    }


    private static class AdHandler extends android.os.Handler {
        private ViewPager mPager;
        public AdHandler(ViewPager pager) {
            mPager = pager;
        }
        @Override
        public void handleMessage(Message msg) {
            int what = msg.what;
            if (what == 1) {
                int index = msg.arg1;
                mPager.setCurrentItem(index);
            }
        }
    }

}

在ViewPager的周边16dp以内,都是ViewPager内部的滑动,在16dp以外,是外部ViewPager的范围。
效果:
这里写图片描述

4. 第三方

上面的各种做法,都是在基础类上编写的,我们还可以借助第三方的框架,来实现一些比较好看的界面。
1. 我们可以通过导入desgin包,

  <android.support.design.widget.TabLayout
        android:id="@+id/news_tab"
        // 实现tab的水平滚动
        app:tabMode="scrollable"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    <android.support.v4.view.ViewPager
        android:id="@+id/news_pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

然后在Avtivity中找到控件,只要为ViewPager setAdapter之后,就可以直接看到效果了。
三步走:
1。找到相应控件
2。给ViewPager设置好适配器
3。将TabLayout 和 ViewPager绑定。
其中如果我们想要为Tab设置标题,需要自己在ViewPager的适配器中方法getPageTitle()中自己设置。

public class NewsActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_news);

        // 1. TabLayout 取出来
        //    ViewPager

        TabLayout tabLayout = (TabLayout) findViewById(R.id.news_tab_layout);
        ViewPager pager = (ViewPager) findViewById(R.id.news_pager);

        // 2. ViewPager Adapter 设置

        List<BaseFragment> fragments = new ArrayList<>();

        fragments.add(new FirstFragment());
        fragments.add(new SecondFragment());
        fragments.add(new ThirdFragment());
        fragments.add(new FourthFragment());

        CommonFragmentPagerAdapter adapter = new CommonFragmentPagerAdapter(
                getSupportFragmentManager(),
                fragments
        );
        pager.setAdapter(adapter);
        // 3. setup
        // setupWithViewPager 要求 ViewPager的 Adapter必须要实现
        //  getPagerTitle(int position)
        tabLayout.setupWithViewPager(pager);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值