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,这样做的好处是在访问各个页面时能节约大量的内存开销,但代价是在页面切换时会增加非常多的开销。
具体实现区别并不太大,只是适用的环境有所变化而已,这里暂时由于时间原因就不详细说明的,等下次回想起来时再来完善
- ViewPager 入门到精通(一)
- ViewPager实现动画从入门到精通(一)
- Ajax入门到精通(一)
- mybatis 入门到精通(一)
- Raphaeljs入门到精通(一)
- zepto.js入门到精通(一)
- Magento从入门到精通(一)
- GUI从入门到精通(一)
- React入门到精通(一)
- glide从入门到精通(一)
- ActiveMQ从入门到精通(一)
- spring入门到精通(一)
- Gradle 入门到精通(一)
- ActiveMQ从入门到精通(一)
- 数据结构入门到精通学习(一)
- Android选项卡viewpager入门到精通
- Netty入门到精通一
- Git 从入门到精通(常用命令解析)(一)
- unicode 中 CW2A CA2W两个宏的含义
- MongoDB 从节点 延迟的测试
- eclipse下的classpath
- 由烦到简 解析复杂的typedef声明
- 字符串 KMP入门,讲解
- ViewPager 入门到精通(一)
- 【Leetcode】Linked List Random Node
- 大数据培训又开课了
- Android 3d TOS Launcher 之桌面图标主题加框规格化
- poj 1410 Intersection 线段与矩形的关系
- Material Designer的低版本兼容实现—— ActivityOptionsCompat
- 谈谈Processing 3D世界 四
- 三个命令解决ASTGO服务器重启后各种问题
- bzoj 2038 [2009国家集训队]小Z的袜子(hose)