ViewPager实现轮播图
对于轮播图的实现,我上次已经在博客中通过自定义ViewGroup实现了,不过过程比较复杂,设置到动画以及图片位置的计算,今天通过Android原生的ViewPager来实现开一个效果比较好的轮播图,先上个效果图:
在实现之前在ViewGroup中有个属性值:clipChilder=”true|false”这个值默认是true,就是当父布局设置为true时,子控件设置的宽和高都必须裁剪成和父布局一样大,但是设置为false时,子控件如过设置的比父控件小,多出的部分将不展示其他控件,在ViewPager中如果固定好了Viewpager的宽,设置margin给左右两边之后,两边将会显示ViewPager中的其他视图,下面是ViewPager的布局:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="horizontal"
android:clipChildren="false"
>
<ImageView
android:id="@+id/img_bg"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support.v4.view.ViewPager
android:id="@+id/viewPager"
android:layout_centerInParent="true"
android:layout_width="match_parent"
android:layout_height="350dp"
android:layout_marginLeft="55dp"
android:layout_marginRight="55dp"
>
</android.support.v4.view.ViewPager>
</RelativeLayout>
在布局中这样设置后屏幕就会出现ViewPager中的三个视图,中间最大,两边只是视图的一部分,然后就是如何实现两边的视图高度比中间的小,通过滑动到中间时高度又增加,这是通过自定义ViewPager.PagerTransform来实现的,该类中包含一个方法 public void transformPage(View page, float position),该方法实在ViewPager中视图滑动时调用,其中的position当取值范围分为三个阶段:(-视图个数 , -1),[-1,1] ,(1,视图个数);其中第一个取值表示当视图从中间滑到坐边时,第二个表示视图从右边滑动到中间时,第三个表示视图从右边滑到右边可是框内时调用,核心代码如下:
public static final float MIN_SCALE = 0.6f;
@Override
public void transformPage(View page, float position) {
if(position<-1){
page.setScaleY(MIN_SCALE);
page.setAlpha(MIN_SCALE);
}else if(position<=1){
float scale = Math.max(MIN_SCALE,1-Math.abs(position));
page.setScaleY(scale);
page.setAlpha(scale);
}else {
page.setScaleY(MIN_SCALE);
page.setAlpha(MIN_SCALE);
}
}
这样就出现了两边的视图缩小透明度增加,接下来就是如何实现重复活动,让开始就可以向由滑动,这里我通过设置给Adapter的getCount()返回值为Integer.Max-Value,在一开始就让viewpager纸箱中间位置即Integer.Max-Value/2(),核心代码如下:
int currentItem = getStartSelectItem();
vp.setCurrentItem(currentItem,true);
public int getStartSelectItem() {
int currentItem = Integer.MAX_VALUE/2;
if(currentItem%list_image.length==0){
return currentItem;
}
while(currentItem%list_image.length!=0){
currentItem++;
}
return currentItem;
}
由于在适配器中返回的视图个数为Integer.Max_Value,所以在适配器的instantiateItem和destroyItem中添加以及删除的视图进行取余处理:
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView(data.get(position%data.size()));
}
@Override
public Object instantiateItem(View container, int position) {
((ViewPager)container).addView(data.get(position%data.size()),0);
return data.get(position%data.size());
}
接下来就是实现自动轮播,这里可以采用Handler来进行图片的轮播,通过每个三秒发送一个消息在主线程中切换视图:
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
int pos = msg.what;
pos++;
vp.setCurrentItem(pos);
}
};
new Thread(){
@Override
public void run() {
while(isPlay){
try {
sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
mHandler.sendEmptyMessage(vp.getCurrentItem());
}
}
}.start();
好了,自定义的轮播图就这样实现了。