ViewPager 让我印象最深的是,APP的引导页,当我们下载好一个软件点进去,APP就会有三张这样的引导页(告诉用户这款APP基本用途和操作)。当然,ViewPager 不止这样,
ViewPager 最大作用就是允许使用者滑动数据页面,简单的说ViewPager 是一种布局管理器。它是android扩展包v4包中的类。ViewPager类直接继承了ViewGroup类,所有它是一个容器类,可以在其中添加其他的view类。和List很像,需要通过适配器(PagerAdapter)来提供数据,同时官方还推荐我们ViewPager和Fragment一起使用,并且提供了专门的FragmentPagerAdapter和FragmentStatePagerAdapter类供Fragment中的ViewPager使用。
从ViewPager 简单例子开始学习吧!三步骤:
一:主布局加入ViewPager ,另外写三个滑动布局view:
activity_view_pager.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"> <android.support.v4.view.ViewPager android:id="@+id/view_pager" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center"> </android.support.v4.view.ViewPager> </RelativeLayout>
public class ViewPagerAdapter extends PagerAdapter { private List<View> viewList; public ViewPagerAdapter(List<View> viewList){ this.viewList=viewList; } /** *返回页卡的数量 * @return */ @Override public int getCount() { return viewList.size(); } /** *判断view是否来自于对象 * @param view * @param object * @return */ @Override public boolean isViewFromObject(View view, Object object) { return view==object; } /** *实例化一个页卡 * @param container * @param position * @return */ @Override public Object instantiateItem(ViewGroup container, int position) { container.addView(viewList.get(position)); return viewList.get(position); } /** * 销毁一个页卡 * @param container * @param position * @param object */ @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView(viewList.get(position)); } }
package com.example.dell.viewpagertest; import android.support.v4.view.ViewPager; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import java.util.ArrayList; import java.util.List; public class MyViewPager extends AppCompatActivity { private ViewPager viewPager; private View view1,view2,view3; private List<View> list; private ViewPagerAdapter pagerAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_view_pager); initLayout();//初始化实例方法 //创建PagerAdapter适配器 pagerAdapter=new ViewPagerAdapter(list); //ViewPager加载适配器 viewPager.setAdapter(pagerAdapter); } public void initLayout(){ viewPager=(ViewPager) findViewById(R.id.view_pager); list=new ArrayList<View>(); //通过View对象去作为ViewPager数据源 view1=View.inflate(this,R.layout.layout_view1,null); view2=View.inflate(this,R.layout.layout_view2,null); view3=View.inflate(this,R.layout.layout_view3,null); list.add(view1); list.add(view2); list.add(view3); } }
- int getCount()
- boolean isViewFromObject(View arg0, Object arg1)
- Object instantiateItem(ViewGroup container, int position)
- void destroyItem(ViewGroup container, int position,Object object)
ViewPager 可以加入标题,让标题指引滑动,PagerTitleStrip和PagerTabStrip都是ViewPager 当前页面上一个页面和下一个页面的非交互指示器,一般作为ViewPager 子控件被添加到xml布局文件中。通过android:layout_gravity""属性设置为top或bottom来决定它显示在ViewPager 的头部或底部。每个页面的标题是通过适配器的getPageTitle(int)函数提供给ViewPager的。这里只讲一个,因为他们的用法一样,就简单说说他们的不同点吧!
我们通过上面的例子来进行修改,只贴出部分增加的代码:
主布局文件:
<?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"> <android.support.v4.view.ViewPager android:id="@+id/view_pager" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center"> <android.support.v4.view.PagerTitleStrip android:id="@+id/pager_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="top"> </android.support.v4.view.PagerTitleStrip> </android.support.v4.view.ViewPager> </RelativeLayout>
适配器我们增加了一个方法和一个构造内容:
private List<View> viewList; private List<String> tabList; public ViewPagerAdapter(List<View> viewList,List<String> tabList){ this.viewList=viewList; this.tabList=tabList; }
/** * 根据位置返回当前所对应的标题。 * @param position * @return */ @Override public CharSequence getPageTitle(int position) { return tabList.get(position); }
最后是java代码:
private List<String> tabList;//标题
private PagerTitleStrip titleStrip;
//标题 titleStrip=(PagerTitleStrip) findViewById(R.id.pager_title); tabList=new ArrayList<String>(); tabList.add("TAB1"); tabList.add("TAB2"); tabList.add("TAB3");
//创建PagerAdapter适配器 pagerAdapter=new ViewPagerAdapter(list,tabList);
效果图:
从效果图来看, 些小伙伴可能想到,我们可不可以点击来滑动 呢?还有一个问题,我们上面是直接将布局设置为背景图片,那如果是一百张照片,那不成我们要写一百个布局,这太恐怖了吧!其实ViewPager 和碎片一起使用,效果会更好,官方强力推荐我们那样做。效果图看着不怎么优美,我们来看看终极版例子:ViewPager +Fragment+TabLayout
<?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"> <android.support.design.widget.TabLayout android:id="@+id/tab_layout" android:layout_width="match_parent" android:layout_height="40sp"> </android.support.design.widget.TabLayout> <android.support.v4.view.ViewPager android:id="@+id/tab_pager" android:layout_width="match_parent" android:layout_height="match_parent"> </android.support.v4.view.ViewPager> </LinearLayout>
public class TabFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment return inflater.inflate(R.layout.fragment_tab1, container, false); } }
public class MyTabAdapter extends FragmentPagerAdapter{ private List<Fragment> fragmentList; private List<String> stringList;//存放标题 public MyTabAdapter(FragmentManager fm, List<Fragment> fragmentList, List<String> stringList){ super(fm); this.stringList=stringList; this.fragmentList=fragmentList; } @Override public Fragment getItem(int position) { return fragmentList.get(position); } @Override public int getCount() { return stringList.size(); } //此方法用来显示tab上的名字 @Override public CharSequence getPageTitle(int position) { return stringList.get(position % stringList.size()); } }
package com.xhm.dell.zaiwo; import android.support.design.widget.TabLayout; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.support.v4.view.ViewPager; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import java.util.ArrayList; import java.util.List; public class MyZaiWo extends FragmentActivity { private TabLayout tabLayout; private ViewPager viewPager; private List<Fragment> fragmentList; private List<String> stringList;//存放标题 private MyTabAdapter tabAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_my_zai_wo); viewPager=(ViewPager)findViewById(R.id.tab_pager); tabLayout=(TabLayout)findViewById(R.id.tab_layout); stringList=new ArrayList<String>(); stringList.add("TAB1"); stringList.add("TAB2"); stringList.add("TAB3"); fragmentList=new ArrayList<Fragment>(); fragmentList.add(new TabFragment()); fragmentList.add(new TabFragment2()); fragmentList.add(new TabFragment3()); tabAdapter=new MyTabAdapter(getSupportFragmentManager() ,fragmentList,stringList); viewPager.setAdapter(tabAdapter); tabLayout.addTab(tabLayout.newTab().setText("Tab1")); tabLayout.addTab(tabLayout.newTab().setText("Tab2")); tabLayout.addTab(tabLayout.newTab().setText("Tab2")); /*也可以这样写 TabLayout.Tab tab1 = tabLayout.newTab().setText("Tab1"); tabLayout.addTab(tab1); TabLayout.Tab tab2 = tabLayout.newTab().setText("Tab2"); tabLayout.addTab(tab2); TabLayout.Tab tab3 = tabLayout.newTab().setText("Tab3"); tabLayout.addTab(tab3); */ tabLayout.setupWithViewPager(viewPager); tabLayout.setTabMode(TabLayout.MODE_FIXED); } }
谷歌官方认为,ViewPager应该和Fragment一起使用时,此时ViewPager的适配器应该是FragmentPagerAdapter,当你实现一个FragmentPagerAdapter,你必须至少覆盖以下方法:
getCount() //还回view的数量
getItem()
- 该类中新增的一个虚函数。函数的目的为生成新的 Fragment 对象。重载该函数时需要注意这一点。在需要时,该函数将被 instantiateItem() 所调用。
- 如果需要向 Fragment 对象传递相对静态的数据时,我们一般通过 Fragment.setArguments() 来进行,这部分代码应当放到 getItem()。它们只会在新生成 Fragment 对象时执行一遍。
- 如果需要在生成 Fragment 对象后,将数据集里面一些动态的数据传递给该 Fragment,那么,这部分代码不适合放到 getItem() 中。因为当数据集发生变化时,往往对应的 Fragment 已经生成,如果传递数据部分代码放到了 getItem() 中,这部分代码将不会被调用。这也是为什么很多人发现调用 PagerAdapter.notifyDataSetChanged() 后,getItem() 没有被调用的一个原因。