效果演示
![](https://img.haomeiwen.com/i2605454/4ec1ffa1bd6159bf.gif)
上图这个效果你可以于淘宝,爱奇艺,华为应用商店等一系列热门或者不热门的APP中看到,因为使用Banner可以通过固定大小的位置动态或者静态的向用户展示多条甚至几十条(虽然没人这样子做)图文数据,对于我自己来说也经常会使用到Banner来展示广告数据或者手机启动引导界面,所以就有了现在这个SimpleBanner库,它肯定不是最完美的,但是我希望它是有用的。
使用
- 在你project的
build.gradle
的repositories
里面添加:
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}```
2. 在你所需的module的```build.gradle```里面添加依赖:
dependencies {
compile 'com.github.AmatorLee:SimpleBanner:1.0.0'
}```
- 在你需要展示Banner数据的xml文件中引入:
<com.amator.simplebanner.widget.SimpleBanner
android:id="@+id/banner_simple"
android:layout_width="match_parent"
android:layout_height="200dp">
</com.amator.simplebanner.widget.SimpleBanner>```
4. 在Activity或者Fragment中配置SimpleBanner:
/**
* 测试本地图片资源,图片较大,造成开销大
/
private int[] imaRes = {R.drawable.a123, R.drawable.color, R.drawable.flash, R.drawable.zhixiao, R.drawable.xiaozhi};
private SimpleBanner mBanner;
/*
* 默认图片资源(图片URL地址)
/
private String[] defaultUrl = new String[]{
"http://g.hiphotos.baidu.com/imgad/pic/item/a8773912b31bb051be533b24317adab44aede043.jpg",
"http://g.hiphotos.baidu.com/imgad/pic/item/c75c10385343fbf22c362d2fb77eca8065388fa0.jpg",
"http://liaoning.sinaimg.cn/2014/1111/U10435P1195DT20141111220802.jpg",
"http://photocdn.sohu.com/20151124/mp43786429_1448294862260_4.jpeg",
"http://h.hiphotos.baidu.com/image/pic/item/faedab64034f78f0b00507c97e310a55b3191cf9.jpg"};
/*
* 测试文字提示
*/
private String[] titleRes = {"深色", "浅色", "动物", "宋智孝", "宋智孝"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//加载本地图片
List<Integer> mDatas = new ArrayList<>();
for (int i = 0; i < imaRes.length; i++) {
mDatas.add(imaRes[i]);
}
//加载网络图片
List<String> mImageRes = new ArrayList<>();
for (int i = 0; i < defaultUrl.length; i++) {
mImageRes.add(defaultUrl[i]);
}
List<String> tips = new ArrayList<>();
for (int i = 0; i < titleRes.length; i++) {
tips.add(titleRes[i]);
}
//1.写在布局文件中
mBanner = (SimpleBanner) findViewById(R.id.banner_simple);
mBanner.setImageRes(mImageRes)
.start();//调用则表示允许自动循环播放
//2.代码中直接使用
LinearLayout linearLayout = (LinearLayout) findViewById(R.id.ll_banner_container);
mBanner = SimpleBanner.createBanner(this)
.setImageRes(mImageRes);
mBanner.start();
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, DisplayUtil.dp2px(this, 200));
linearLayout.addView(mBanner, params);
}
@Override
protected void onPause() {
super.onPause();
//释放资源避免内存泄漏
mBanner.stop();
}```
就这样就可以实现以下效果
![](https://img.haomeiwen.com/i2605454/0fedbe57178ce488.gif)
可能有人会问,那么切换效果呢?,其实切换效果的实现很简单,但是实现炫酷的切换效果需要大量是时间进行计算,同时对于部分APP来说是不合适的,所以我不打算提供多种切换效果,当然你可以自己实现然后调用
setBannerPageTranFormer(boolean reverseDrawingOrder, ViewPager.PageTransformer transformer)
即可。同时我推荐一个开源库android-viewpager-transformers,感谢。
代码分析
短短的使用步骤绞尽脑汁也写不出来,所以直接show you the fuck codes就好。
在此之前我先简单来说说SimpleBanner实现无限轮播的实现方式
现今gayhub上的banner开源库主要分为两大类:
- 使用ViewPager实现
- 自定义或者使用RecyclerView等实现
那么Simple是使用第一种方式,所以就结合代码分析来说说第一种的套路吧:
既然知道了精髓是ViewPager,在确定ViewPager之后我们要考虑以下两个问题
- 实现循环播放
- 如何进行自动循环
回答一
其实实现循环很简单,只要在最后一张图片滑动时把它下一张重新设置为第一张就可以实现“伪循环”,但是这样重新滑进去会造成很不好的用户体验,所以我们给ViewPager的adapter设置一个很大的数,返回一个巨大的数值,通过与实际数量的求余就可以实现“无限循环”。
回答二
很多时候我们都会新建一个Handler
,然后再其实现方法里面对viewPager进行setCurrentItem,然后再界面跳转完成后掩饰某个delayTime
不断发送自身空消息就可以实现自动播放了,bug,还有更好的办法吗?知道我看到了达哥的《手把手教你用ViewPager自定义实现Banner轮播 》,找到了更好的写法,当然思想是一样的。
BannerViewPager
/**
* Created by AmatorLee on 2017/7/21.
*/
public class BannerViewPager extends ViewPager {
private int delayTime = 3000;//设置展示时间
private BannerDirection mBannerDirection = LEFT;//试着轮播方向
private boolean isAuto = true;//是否为自动轮播
public void setAuto(boolean auto) {
isAuto = auto;
}
public void setDelayTime(int delayTime) {
this.delayTime = delayTime;
}
public void setBannerDirection(BannerDirection bannerDirection) {
mBannerDirection = bannerDirection;
}
public BannerViewPager(Context context) {
super(context);
}
public BannerViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void start() {
if (isAuto) {
//每次开始前先remove掉避免重复调用
removeCallbacks(mBannerTask);
postDelayed(mBannerTask, delayTime);
}
}
public void stop() {
removeCallbacks(mBannerTask);
}
private Runnable mBannerTask = new Runnable() {
@Override
public void run() {
bannerPlay();
}
};
private void bannerPlay() {
PagerAdapter adapter = getAdapter();
if (adapter != null) {
int count = adapter.getCount();
int currentItem = getCurrentItem();
switch (mBannerDirection) {
case LEFT:
currentItem++;
if (currentItem >= count) {
currentItem = 0;
}
break;
case RIGHT:
currentItem--;
if (currentItem < 0) {
currentItem = count - 1;
}
break;
}
setCurrentItem(currentItem);
}
start();
}
@Override
protected void onDetachedFromWindow() {
removeCallbacks(mBannerTask);
super.onDetachedFromWindow();
}
}```
如上所说,需要给Adapter设置一个很大的数```Integer.MAX_VALUE```
**BannerViewPager**
/**
- Created by AmatorLee on 2017/7/20.
*/
public class BannerAdapter extends PagerAdapter {
private List<View> mViews;
public static final String TAG = "BannerPagerAdapter";
private OnBannerClickListener mBannerClickListener;
private int pos;
public void setBannerClickListener(OnBannerClickListener bannerClickListener) {
mBannerClickListener = bannerClickListener;
}
public BannerAdapter(List<View> mViews) {
this.mViews = mViews;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
if (mViews == null || mViews.size() == 0) {
Log.d(TAG, "instantiateItem return");
return null;
}
final int pos = position % mViews.size();
View view = mViews.get(pos);
ViewGroup parent = (ViewGroup) view.getParent();
if (parent != null) {
parent.removeView(view);
}
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d(TAG, "instantiateItem pos is :" + pos);
if (mBannerClickListener != null) {
mBannerClickListener.onBannerClick(pos);
}
}
});
container.addView(view);
return view;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
if (mViews == null || mViews.size() == 0) {
return;
}
int pos = position % mViews.size();
Log.d(TAG, "destroyItempos: " + pos);
container.removeView(mViews.get(pos));
}
@Override
public int getCount() {
return mViews == null ? 0 : Integer.MAX_VALUE;
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
}其实看到上面的演示图还有最后一个注意点就是指示器Indicator,我尝试过自己自定义几种类型的
BannerIndicator```,但是这样做的话实现太多的子类,所以我采取代码家AndroidImageSlider的写法使用图层Drawable动态实现。
总结
Banner几乎是最常见的一种效果同时对于我们Coder来说也应该是最容易实现的,所以自己抽空写一下。如果发现有什么错漏的地方,麻烦指出,同时我也会不断自我完善。
gayhub地址:SimpleBanner
网友评论