ViewPager是Google自带的翻页控件,存放在V4兼容包中,继承于ViewGroup,官方推荐和Fragment一块使用。我们平时使用的地方主要有2个,一个是app第一次启动的引导页,第二个就是弄几张图片轮播的那种。在第二种使用方式的时候经常配合PagerTabStrip或者PagerTitleStrip来显示一个标签用来指引现在处于第几个页面。
PagerTabStrip和PagerTitleStrip主要有两点不同:
1、PagerTabStrip可以点击。
2、PagerTabStrip在每个标签下面都有一个短的横线。
需要注意的是在使用他们的时候必须要放在ViewPager里面作为其子控件,要显示标题需要重写Adapter里面的getPagerTitle方法。
下面来看看他们分别有什么常用的方法:
1、ViewPager
onPagerChangedListener:设置页面滑动和改变的时候的监听
setAdapter:设置适配器,有3中适配器,PagerAdapter,FragmentPagerAdapter,FragmentStatePagerAdapter。
setCurrentItem:指定当前页面为指定的页面。
setPagerTransformer:设置页面切换时的动画。
2、PagerTabStrip
setTextColor:设置字体颜色
setTextSize:设置字体大小
setTabIndicatorColor:设置下面横线的颜色
setDrawFullUnderLine:设置是否画下面那条横线,默认是不画的
setBackGroundColor:设置背景色
3、PagerTitleStrip
setTextColor:设置字体颜色
setTextSize:设置字体大小
setGravity:设置标题的对齐方式
还有一个比较重要的就是PagerAdapter,它是一个抽象类,我们必须要重写他的4个方法:destroyItem、instantiateItem、isViewFormObject、getCount,如果我们使用了PagerTabStrip或者PagerTitleStrip还需要重写getPagerTitle方法用来显示标题。
上面简单的介绍了一下需要用到的知识,下面就来一步步实现我们想要的效果,首先我们实现最基本的效果,3个页面,不能循环滑动:
布局文件:
<?xml version="1.0" encoding="utf-8"?> <android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/viewPager" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v4.view.PagerTabStrip android:id="@+id/tabStrip" android:layout_width="wrap_content" android:layout_height="40dp" android:alpha="0.5" android:gravity="center" /> </android.support.v4.view.ViewPager>
public class MainActivity extends AppCompatActivity { private ViewPager viewPager; private List<View> views; private PagerTabStrip tabStrip; private PagerTitleStrip titleStrip; private String[] titles; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); viewPager = (ViewPager) findViewById(R.id.viewPager); views = new ArrayList<>(); titles = new String[5]; { //初始化标题 for (int i = 1; i < 4; i++) { titles[i] = "标题" + i; } //初始化页面视图 View view1 = getLayoutInflater().inflate(R.layout.item, null); ((ImageView) view1.findViewById(R.id.imgv)).setImageResource(R.drawable.a); View view2 = getLayoutInflater().inflate(R.layout.item, null); ((ImageView) view2.findViewById(R.id.imgv)).setImageResource(R.drawable.b); View view3 = getLayoutInflater().inflate(R.layout.item, null); ((ImageView) view3.findViewById(R.id.imgv)).setImageResource(R.drawable.c); views.add(view1); views.add(view2); views.add(view3); } //TabStrip的各种设置 { tabStrip = (PagerTabStrip) findViewById(R.id.tabStrip); tabStrip.setTextColor(Color.GREEN); tabStrip.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); tabStrip.setTabIndicatorColor(Color.RED); tabStrip.setDrawFullUnderline(false); tabStrip.setBackgroundColor(Color.DKGRAY); } //适配器 viewPager.setAdapter(new PagerAdapter() { @Override public int getCount() { return views.size(); } @Override public Object instantiateItem(ViewGroup container, int position) { container.addView(views.get(position)); return views.get(position); } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView(views.get(position)); } //设置标题 @Override public CharSequence getPageTitle(int position) { return titles[position]; } @Override public boolean isViewFromObject(View view, Object object) { return view == object; } }); } }
ok,下面我们来修改之前的代码实现无线循环的效果。我们需要做一下几步:
1、把另外两个页面添加到views集合中。
2、在getPagerTitle方法中动态的添加两个页面的标题。
3、为ViewPager添加页面切换监听,也就是viewpager.addOnPagerChangedListener()方法。
4、在上一步中方法动态的跳转到指定的页面。
上面的4步中前两步非常简单,我就不单独贴出代码了,一会儿贴出整体修改后的代码,大家可以自己去找到对应位置查看,我主要贴出第3步的代码:
//设置切换页面监听 viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { int p; @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { if (position == 4) { p = position = 1; } else if (position == 0) { p = position = 3; } else { p = position; } } @Override public void onPageScrollStateChanged(int state) { if (ViewPager.SCROLL_STATE_IDLE == state) viewPager.setCurrentItem(p, false); } });以前使用的是viewpager.setOnPageChangeListener,现在改为addOnPageChangeListener,里面的参数传的是OnPagechangeListener,也可以使用其实现类SimpleOnChangeListener,这个只是简单的继承了没有写里面的代码,这点和我们学过的手势中的OnGestureListener中SimpleOnGestureListener是一致的,这里提出来是希望大家把学过的知识都总结联系起来,知识不能孤立的存在于我们大脑中。OnPageChangeListener中有3个方法需要重写,其中onPageScrolled在页面第一次显示和手动滑动页面的时候调用,onPageSelected在页面切换后调用(不一定是页面完整的切换完的时候,也不是在页面切换动画播放完的时候调用,什么时候调用需要系统自己去判断),onPageScrollStateChanged在我们一滑动页面和滑动完成的时候调用,他里面的state有三种,分别外ViewPager.SCROLL_STATE_IDLE(空闲),ViewPager.SCROLL_STATE_SETTING(自动设置),ViewPager.SCROLL_STATE_DRAGGING(拖动),下面是其官方文档:
/** * Called when the scroll state changes. Useful for discovering when the user * begins dragging, when the pager is automatically settling to the current page, * or when it is fully stopped/idle. *ok,下面我们贴出修改后的完整代码:
public class MainActivity extends AppCompatActivity { private ViewPager viewPager; private List<View> views; private PagerTabStrip tabStrip; private String[] titles; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); viewPager = (ViewPager) findViewById(R.id.viewPager); views = new ArrayList<>(); titles = new String[5]; { //初始化标题 for (int i = 1; i < 4; i++) { titles[i] = "标题" + i; } //前面添加一个 View view0 = getLayoutInflater().inflate(R.layout.item, null); ((ImageView) view0.findViewById(R.id.imgv)).setImageResource(R.drawable.c); views.add(view0); //初始化页面视图 View view1 = getLayoutInflater().inflate(R.layout.item, null); ((ImageView) view1.findViewById(R.id.imgv)).setImageResource(R.drawable.a); View view2 = getLayoutInflater().inflate(R.layout.item, null); ((ImageView) view2.findViewById(R.id.imgv)).setImageResource(R.drawable.b); View view3 = getLayoutInflater().inflate(R.layout.item, null); ((ImageView) view3.findViewById(R.id.imgv)).setImageResource(R.drawable.c); views.add(view1); views.add(view2); views.add(view3); //后面添加一个 View view4 = getLayoutInflater().inflate(R.layout.item, null); ((ImageView) view4.findViewById(R.id.imgv)).setImageResource(R.drawable.a); views.add(view4); } //TabStrip的各种设置 { tabStrip = (PagerTabStrip) findViewById(R.id.tabStrip); tabStrip.setTextColor(Color.GREEN); tabStrip.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); tabStrip.setTabIndicatorColor(Color.RED); tabStrip.setDrawFullUnderline(false); tabStrip.setBackgroundColor(Color.DKGRAY); } //适配器 viewPager.setAdapter(new PagerAdapter() { @Override public int getCount() { return views.size(); } @Override public Object instantiateItem(ViewGroup container, int position) { container.addView(views.get(position)); return views.get(position); } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView(views.get(position)); } //设置标题 @Override public CharSequence getPageTitle(int position) { if (position == 4) { position = 1; } else if (position == 0) { position = 3; } return titles[position]; } @Override public boolean isViewFromObject(View view, Object object) { return view == object; } }); viewPager.setCurrentItem(1); //设置切换页面监听 viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { int p; @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { if (position == 4) { p = position = 1; } else if (position == 0) { p = position = 3; } else { p = position; } } @Override public void onPageScrollStateChanged(int state) { if (ViewPager.SCROLL_STATE_IDLE == state) viewPager.setCurrentItem(p, false); } }); } }上修改后的效果图(图片太大了,使用Ps转了一下把颜色也给弄失真了,大家凑合着看吧~~~~~~~~~··):
我们的轮播当然也不是那种百度排名靠前的含有各种Bug的残次品,我们要实现的效果是可以真正商品化的效果。每隔一秒钟切换一张图片,当手指滑动页面的时候停止切换,本功能是在上面的基础上实现的。需要做如下几步:
1、添加一个handler属性,在handMessage方法里面重新发送延时消息。
2、添加一个int变量用来存position的值,position值从onPagerScrolled方法中得到。
3、在开始的时候发送延时消息,在onPageScrolled中取消消息,然后在onPageStateChanged方法中发送延时消息。
大概就是这么几步,中间有一些细节需要处理,只要就是onPageScrolled方法在页面第一次显示的时候也会调用,所以我们初始化的时候发送的延时消息会被取消,解决办法就是定义一个Boolean类型的变量用来判断是否是第一次显示。这里我贴出handler里面的代码,别的修改的代码请看后面贴出的完整代码:
private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); viewPager.setCurrentItem(p++, false); handler.sendEmptyMessageDelayed(1, 1000); } };修改后的完整代码:
public class MainActivity extends AppCompatActivity { private ViewPager viewPager; private List<View> views; private PagerTabStrip tabStrip; private String[] titles; private int p; private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); viewPager.setCurrentItem(p++, false); handler.sendEmptyMessageDelayed(1, 1000); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); viewPager = (ViewPager) findViewById(R.id.viewPager); views = new ArrayList<>(); titles = new String[5]; { //初始化标题 for (int i = 1; i < 4; i++) { titles[i] = "标题" + i; } //前面添加一个 View view0 = getLayoutInflater().inflate(R.layout.item, null); ((ImageView) view0.findViewById(R.id.imgv)).setImageResource(R.drawable.c); views.add(view0); //初始化页面视图 View view1 = getLayoutInflater().inflate(R.layout.item, null); ((ImageView) view1.findViewById(R.id.imgv)).setImageResource(R.drawable.a); View view2 = getLayoutInflater().inflate(R.layout.item, null); ((ImageView) view2.findViewById(R.id.imgv)).setImageResource(R.drawable.b); View view3 = getLayoutInflater().inflate(R.layout.item, null); ((ImageView) view3.findViewById(R.id.imgv)).setImageResource(R.drawable.c); views.add(view1); views.add(view2); views.add(view3); //后面添加一个 View view4 = getLayoutInflater().inflate(R.layout.item, null); ((ImageView) view4.findViewById(R.id.imgv)).setImageResource(R.drawable.a); views.add(view4); } //TabStrip的各种设置 { tabStrip = (PagerTabStrip) findViewById(R.id.tabStrip); tabStrip.setTextColor(Color.GREEN); tabStrip.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); tabStrip.setTabIndicatorColor(Color.RED); tabStrip.setDrawFullUnderline(false); tabStrip.setBackgroundColor(Color.DKGRAY); } //适配器 viewPager.setAdapter(new PagerAdapter() { @Override public int getCount() { return views.size(); } @Override public Object instantiateItem(ViewGroup container, int position) { container.addView(views.get(position)); return views.get(position); } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView(views.get(position)); } //设置标题 @Override public CharSequence getPageTitle(int position) { if (position == 4) { position = 1; } else if (position == 0) { position = 3; } return titles[position]; } @Override public boolean isViewFromObject(View view, Object object) { return view == object; } }); viewPager.setCurrentItem(1); handler.sendEmptyMessageDelayed(1, 1000); //设置切换页面监听 viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { boolean isFirst = true; @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { if (!isFirst) handler.removeMessages(1); isFirst = false; } @Override public void onPageSelected(int position) { if (position == 4) { p = position = 1; } else if (position == 0) { p = position = 3; } else { p = position; } } @Override public void onPageScrollStateChanged(int state) { if (ViewPager.SCROLL_STATE_IDLE == state) { viewPager.setCurrentItem(p, false); handler.sendEmptyMessageDelayed(1, 1000); } } }); } }
貌似到这一步基本可以跑起来了,可是我们是一个追求尽量完美的人,ViewPager缺少小圆点兄弟怎么可以,那么下面我们就来给他加上小圆点。这里需要修改布局文件,当然你不嫌麻烦,写代码也是可以实现的。找了半天没找到小点点图片,我们就用一个小动画来代替吧,虽然不美观可是我们学的是技术不是美工作图(大家有好的图片欢迎发我邮箱[email protected],不胜感激)。来看效果图:
将布局文件的根布局改成RelativeLayout,然后添加了一个直接子控件LinearLayout,LinearLayout有3个ImageView,为了美观我把ImageView图片布局改成了填满窗口,Activity布局代码:
<?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/viewPager" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v4.view.PagerTabStrip android:id="@+id/tabStrip" android:layout_width="wrap_content" android:layout_height="40dp" android:alpha="0.5" android:gravity="center" /> </android.support.v4.view.ViewPager> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_marginBottom="30dp" android:background="#77cccccc" android:gravity="center" android:padding="10dp"> <ImageView android:id="@+id/imgv1" android:layout_width="40dp" android:layout_height="40dp" android:src="@drawable/other" /> <ImageView android:id="@+id/imgv2" android:layout_width="40dp" android:layout_height="40dp" android:layout_marginLeft="20dp" android:layout_marginRight="20dp" android:src="@drawable/current" /> <ImageView android:id="@+id/imgv3" android:layout_width="40dp" android:layout_height="40dp" android:src="@drawable/other" /> </LinearLayout> </RelativeLayout>然后在java代码中找到3个图片,动态的去设置ImageView中的图片资源,代码如下:
protected void onResume() { super.onResume(); //找到对应的3张图片 imgv1 = ((ImageView) findViewById(R.id.imgv1)); imgv2 = ((ImageView) findViewById(R.id.imgv2)); imgv3 = ((ImageView) findViewById(R.id.imgv3)); imgv1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { setImg(p = 1); viewPager.setCurrentItem(1, false); handler.sendEmptyMessageDelayed(1, 1000); } }); imgv2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { viewPager.setCurrentItem(2, false); setImg(p = 2); handler.sendEmptyMessageDelayed(1, 1000); } }); imgv3.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { viewPager.setCurrentItem(3, false); setImg(p = 3); handler.sendEmptyMessageDelayed(1, 1000); } }); }
viewpager切换动画使用的是属性动画,这个功能需要运行在3.0以上的手机上,现在我们开发的程序都应设置成最低兼容4.0,我们慢慢的淘汰掉那些太古老的东西。添加动画需要使用到Viewpager中的setpageTransformer()方法,Google给我们写了2个动画,这里我直接使用它的动画,第一种动画效果图:
代码:
//设置动画效果 viewPager.setPageTransformer(true, new ViewPager.PageTransformer() { float MIN_SCALE = 0.75f; @Override public void transformPage(View view, float position) { int pageWidth = view.getWidth(); if (position < -1) { // [-Infinity,-1) // This page is way off-screen to the left. view.setAlpha(0); } else if (position <= 0) { // [-1,0] // Use the default slide transition when // moving to the left page view.setAlpha(1); view.setTranslationX(0); view.setScaleX(1); view.setScaleY(1); } else if (position <= 1) { // (0,1] // Fade the page out. view.setAlpha(1 - position); // Counteract the default slide transition view.setTranslationX(pageWidth * -position); // Scale the page down (between MIN_SCALE and 1) float scaleFactor = MIN_SCALE + (1 - MIN_SCALE) * (1 - Math.abs(position)); view.setScaleX(scaleFactor); view.setScaleY(scaleFactor); } else { // (1,+Infinity] // This page is way off-screen to the right. view.setAlpha(0); } } } );
代码:
//设置动画效果 viewPager.setPageTransformer(true, new ViewPager.PageTransformer() { float MIN_SCALE = 0.85f; float MIN_ALPHA = 0.5f; @Override public void transformPage(View view, float position) { int pageWidth = view.getWidth(); int pageHeight = view.getHeight(); if (position < -1) { // [-Infinity,-1) // This page is way off-screen to the left. view.setAlpha(0); } else if (position <= 1) { // [-1,1] // Modify the default slide transition to // shrink the page as well float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position)); float vertMargin = pageHeight * (1 - scaleFactor) / 2; float horzMargin = pageWidth * (1 - scaleFactor) / 2; if (position < 0) { view.setTranslationX(horzMargin - vertMargin / 2); } else { view.setTranslationX(-horzMargin + vertMargin / 2); } // Scale the page down (between MIN_SCALE and 1) view.setScaleX(scaleFactor); view.setScaleY(scaleFactor); // Fade the page relative to its size. view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA)); } else { // (1,+Infinity] // This page is way off-screen to the right. view.setAlpha(0); } } } );
ok,Viewpager这块基本给大家讲完了,如果有什么问题欢迎给我发邮件,最后送上Demo福利:demo