banner轮播图控件介绍
我们在日常开发过程中经常会碰到轮播图的需求,一般来说都是自己用ViewPager实现的,但是这种实现过程没有经过封装,日常调用起来也比较繁琐,有着各式各样的问题,因此我在github上找到一款非常好用的开源轮播图控件banner,调用起来非常方便,还支持各种效果,部分效果如下图所示。使用时的版本是1.4.9。
基本使用
要使用这个控件,首先我们需要在module的build.gradle中添加依赖
dependencies{
compile 'com.youth.banner:banner:1.4.9'
}
如果要使用网络图片或本地图片要需要在AndroidManifest.xml添加权限
<!-- if you want to load images from the internet -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- if you want to load images from a file OR from the internet -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
接下来就可以使用了
最简单的使用方法是在activity或fragment布局文件中
<com.youth.banner.Banner
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/banner"
android:layout_width="match_parent"
android:layout_height="高度自己设置" />
或者自己new出来控件。
设置图片加载器继承ImageLoader
public class GlideImageLoader extends ImageLoader {
@Override
public void displayImage(Context context, Object path, ImageView imageView) {
/**
注意:
1.图片加载器由自己选择,这里不限制,只是提供几种使用方法
2.返回的图片路径为Object类型,由于不能确定你到底使用的那种图片加载器,
传输的到的是什么格式,那么这种就使用Object接收和返回,你只需要强转成你传输的类型就行,
切记不要胡乱强转!
*/
eg:
//Glide 加载图片简单用法
Glide.with(context).load(path).into(imageView);
//Picasso 加载图片简单用法
Picasso.with(context).load(path).into(imageView);
//用fresco加载图片简单用法,记得要写下面的createImageView方法
Uri uri = Uri.parse((String) path);
imageView.setImageURI(uri);
}
//提供createImageView 方法,如果不用可以不重写这个方法,主要是方便自定义ImageView的创建
@Override
public ImageView createImageView(Context context) {
//使用fresco,需要创建它提供的ImageView,当然你也可以用自己自定义的具有图片加载功能的ImageView
SimpleDraweeView simpleDraweeView=new SimpleDraweeView(context);
return simpleDraweeView;
}
}
最后,在Activity或者Fragment中配置Banner
banner.setImages(image)
.setImageLoader(new GlideImageLoader())
.setOnBannerListener(this)
.start();
就可以播放出轮播图了,该控件还有很多方法可以设置样式,切换动画等属性,具体可以参考项目主页https://github.com/youth5201314/banner
实现源码分析
知其然还要知其所以然,我们用了这个控件还要知道这个控件是怎么实现的。
首先我们从Banner类切入,因为它是轮播图的实现控件
从源码中可以看到,Banner类继承FrameLayout,然后在它的构造函数中inflate了banner.xml,这个布局的结构如下:
<RelativeLayout
android:clipChildren="false">
<!--轮播图-->
<ViewPager
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!--底部布局,包括指示器,title,页码等-->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true">
......
</RelativeLayout>
</RelativeLayout>
同时,在初始化函数中,还初始化了自定义属性等。
接下来我们要关注的就是这个控件是如何实现无限轮播的
可以看到在Activity中通过
banner.setImages(image)
.setImageLoader(new GlideImageLoader())
.setOnBannerListener(this)
.start();
开启轮播,setImages()
方法设置了轮播图的图片路径,配合ImageLoader加载图片,继承ImageLoader抽象类并重写displayImage方法来具体实现图片的加载逻辑,setOnBannerListener()
方法设置banner的点击事件,start()
方法开始轮播。
我们具体看一下start()
public Banner start() {
setBannerStyleUI(); //设置ui
setImageList(imageUrls); //初始化ImageViews
setData(); //初始化ViewPager并开始播放
return this;
}
setBannerStyleUI()
第一个函数setBannerStyleUI()
用于设置UI显示的,包括指示器样式,标题样式等等。
setImageList(imageUrls)
第二个函数是我们关注的重点,在这个方法中我们通过setImages()
方法获取到的对象List,来初始化轮播图显示的ImageView,这里用了一个技巧来实现无限轮播:ImageView数量比图片数量大2,imageViews.get(0)为最后一张图片,imageViews.get(size-1)为第一张图片
if (i == 0) {
url = imagesUrl.get(count - 1);
} else if (i == count + 1) {
url = imagesUrl.get(0);
} else {
url = imagesUrl.get(i - 1);
}
这样在滑动到第一张或者最后一张后,接下来的一张图片是最后一张或者第一张,同时在onPageScrollStateChanged中检测,在停止滑动的状态下如果是最后一个ImageView或者第0个ImageView则更新ViewPager状态,利用viewPager.setCurrentItem()
方法设置其状态为最后一张或者第一张,这样就平滑过度了。
@Override
public void onPageScrollStateChanged(int state) {
if (mOnPageChangeListener != null) {
mOnPageChangeListener.onPageScrollStateChanged(state);
}
currentItem = viewPager.getCurrentItem();
switch (state) {
case 0://No operation
if (currentItem == 0) {
viewPager.setCurrentItem(count, false);
} else if (currentItem == count + 1) {
viewPager.setCurrentItem(1, false);
}
break;
case 1://start Sliding 正在滑动
if (currentItem == count + 1) {
viewPager.setCurrentItem(1, false);
} else if (currentItem == 0) {
viewPager.setCurrentItem(count, false);
}
break;
case 2://end Sliding
break;
}
}
setData()
在setData()
方法中初始化了ViewPager,如果开启了自动轮播,会调用startAutoPlay()
方法利用handler.postDelayed去自动切换ViewPager。
这里额外提一下设置切换动画,是利用viewPager.setPageTransformer()
方法进行设置,这里作者给我们提供了很多动画的默认实现,如果没有需要的切换动画效果,就需要自己去实现PagerTransformer接口去实现自己想要的切换动画,关于切换动画和clipChildren属性,这篇文章介绍的很透彻http://blog.youkuaiyun.com/u012702547/article/details/52334161
public Banner setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer) {
viewPager.setPageTransformer(reverseDrawingOrder, transformer);
return this;
}