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));
}
}
第三步:java代码部分
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);
}
}
效果图:
主布局的话,记得添加的是V4包的ViewPager ,同时别忘了android:layout_gravity="center"。
咱们重点关注适配器(PagerAdapter),继承这个类的时候,我们至少需要重写它的四个方法:
- 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"
app:tabMode="scrollable"
app:tabGravity="center"
app:tabTextColor="@color/black"
app:tabIndicatorColor="@color/colorPrimaryDark"
app:tabSelectedTextColor="@color/colorPrimaryDark"
app:tabTextAppearance="@android:style/TextAppearance.Holo.Large">
</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());
}
}
Java代码:
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());
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);
*/
tabAdapter = new MyTabAdapter(getSupportFragmentManager(),fragmentList,stringList);
viewPager.setAdapter(tabAdapter);
tabLayout.setupWithViewPager(viewPager);
tabLayout.setTabMode(TabLayout.MODE_FIXED);
}
//偷懒模式。多个fragment时使用,
@Override
protected void initView() {
ButterKnife.bind(this);
stringList = new ArrayList<String>();
stringList.add("双色球");
stringList.add("大乐透");
stringList.add("福彩3D");
stringList.add("七乐彩");
stringList.add("七星彩");
stringList.add("排列3");
stringList.add("排列5");
stringList.add("足彩胜负/任九");
stringList.add("竞彩足球");
stringList.add("北京单场");
stringList.add("竞彩篮球");
fragmentList = new ArrayList<Fragment>();
for (int i = 0; i < 11; i++) {
BlankFragment blankFragment = BlankFragment.newInstance(i+"");
fragmentList.add(blankFragment);
}
for (int i = 0; i < 11; i++) {
mHighTab.addTab(mHighTab.newTab().setText("Tab" + i));
}
tabAdapter = new HighGradeTabAdapter(getSupportFragmentManager(), fragmentList, stringList);
mHighPager.setAdapter(tabAdapter);
mHighTab.setupWithViewPager(mHighPager);
Log.e("initView", "mHighPager.getCurrentItem(): " + mHighPager.getCurrentItem());
//记得在fragment中添加如下代码
//private static final String KEY = "title";
/*public static BlankFragment newInstance(String str) {
BlankFragment fragment = new BlankFragment();
Bundle bundle = new Bundle();
bundle.putString(KEY, str);
fragment.setArguments(bundle);
return fragment;
}*/
}
}
效果图:
怎么样?是不是美多了。看看代码中又有那些变化了:
布局中多出了个TabLayout,不用担心,这个不难(自己学一下,会了更好)
java代码中,我们继承的是FragmentActivity而不是Activity了,为咋?这里因为我们要兼容是3.0以下版本,所以需继承FragmentActivity,通过getSupportFragmentManager()获取FragmentManager;3.0及其以上版本,只需继承Activity,通过getFragmentManager获取事务。
重点说下适配器:
谷歌官方认为,ViewPager应该和Fragment一起使用时,此时ViewPager的适配器应该是FragmentPagerAdapter,当你实现一个FragmentPagerAdapter,你必须至少覆盖以下方法:
getCount() //还回view的数量
getItem()
- 该类中新增的一个虚函数。函数的目的为生成新的 Fragment 对象。重载该函数时需要注意这一点。在需要时,该函数将被 instantiateItem() 所调用。
- 如果需要向 Fragment 对象传递相对静态的数据时,我们一般通过 Fragment.setArguments() 来进行,这部分代码应当放到 getItem()。它们只会在新生成 Fragment 对象时执行一遍。
- 如果需要在生成 Fragment 对象后,将数据集里面一些动态的数据传递给该 Fragment,那么,这部分代码不适合放到 getItem() 中。因为当数据集发生变化时,往往对应的 Fragment 已经生成,如果传递数据部分代码放到了 getItem() 中,这部分代码将不会被调用。这也是为什么很多人发现调用 PagerAdapter.notifyDataSetChanged() 后,getItem() 没有被调用的一个原因。
除了这个适配器还有一个适配器(FragmentStatePagerAdapter)。这两个适配器都是继承自 PagerAdapter,更专注于每一页均为 Fragment 的情况。FragmentPagerAdapter类内的每一个生成的 Fragment 都将保存在内存之中,因此适用于那些相对静态的页,数量也比较少的那种;如果需要处理有很多页,并且数据动态性较大、占用内存较多的情况,应该使用FragmentStatePagerAdapter适配器。
Android ViewPager滑滑的~~~