必须知识点
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个页面,不能循环滑动:
布局文件:
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:id="@+id/tabStrip"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:alpha="0.5"
android:gravity="center" />
java代码:
public class MainActivity extends AppCompatActivity {
private ViewPager viewPager;
private List 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;
}
});
}
}
二、无线循环
在上面的基础上面加上无线循环,当然了我们不会使用哪种把页数设置成无限大然后说自己是无线循环的,我们只需要在首末各添加一个页面,就能实现无线循环。原理是这样的,假如我们需要显示3个页面,这3个页面分别为A、B、C,我们在A的页面前增加一个C,在C的后面增加一个A,当我们滑动到C的时候迅速的调到A前面的C页面,因为页面内容是一样的,用户是无法感觉到有跳转的,这样我们就可以进行滑动了,同理往右滑动到A的时候我门迅速跳转到C后面的A,内部的结构是这样的:
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 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 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布局代码:
android:layout_width="match_parent"
android:layout_height="match_parent">
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:id="@+id/tabStrip"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:alpha="0.5"
android:gravity="center" />
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">
android:id="@+id/imgv1"
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@drawable/other" />
android:id="@+id/imgv2"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:src="@drawable/current" />
android:id="@+id/imgv3"
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@drawable/other" />
然后在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添加切换动画
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);
}
}
}
);
扫描关注我的微信公众号:
动画这块其实很简单,只要了解setPageTransformer这个方法就可以了,具体实现一个动画效果需要我们对动画那块的知识掌握的比较熟练,这里就不过多的演示了。
ok,Viewpager这块基本给大家讲完了,如果有什么问题欢迎给我发邮件,最后送上Demo福利:demo