This article is published simultaneously in CSDN, shall not be reproduced without permission.

This article is the first in a three-part series on BannerViewPager. See the links below for the other two:

BannerViewPager source code analysis

Analysis of Indicator Design in BannerViewPager

Recently, the company project is upgrading AndroidX, because some of the older libraries used in the project have stopped updating and maintenance, so we need to replace these libraries, including the Banner library of automatic rotation. I have written a rotograph before, so I reconstructed it to create a new rotograph library that supports many different styles –BannerViewPager. Personally, I think BannerViewPager is better than other open source Banner libraries, not only because of its concise and efficient code, but also because it is highly customizable. BannerViewPager supports not only any page layout but also any Indicator styles. Even the Indicator can be placed anywhere. Yeah, that’s how it goes. BannerViewPager’s functions are shown in pictures and code.

BannerViewPager effect preview and API introduction

Due to the quality of GIF images, the following preview is not clear, you can click the link below or scan the QR code to download the Apk experience. Apk is stored on Github and can be slow to download.

Click or scan the QR code to download APK

1. SetIndicatorStyle

BannerViewPager currently has both CIRCLE and DASH style indicators built in. You can switch the indicator style with setIndicatorStyle(int) in a single line of code. Of course, if the built-in styles don’t meet your needs. BannerViewPager also provides the ability to customize indicators. By inheriting BaseIndicatorView or implementing the IIndicator interface and overwriting the corresponding methods, you can create any Indicator you want with a custom View. The following figure [custom] is their own implementation of the indicator style.

CIRCLE DASH The custom

The following code shows how to switch indicators:

mViewPager.setIndicatorStyle(IndicatorStyle.DASH)
          .setIndicatorHeight(BannerUtils.dp2px(3f))
          .setIndicatorWidth(BannerUtils.dp2px(3), BannerUtils.dp2px(10))
          .setHolderCreator(() -> new ImageResourceViewHolder(0))
          .create(mDrawableList)
Copy the code

The above [Dash] copy of Alipay’s Indicator style is easily implemented in 5 lines of code (check out alipay’s Indicator rotifers for fun).

Customizing IndicatorView will be discussed in detail in the following sections.

2.setPageStyle

Use setPageStyle(int) to open the three-page-per-screen mode. Currently, there are three styles in the three-page-per-screen mode, as shown in the figure below:

MULTI_PAGE MULTI_PAGE_SCALE MULTI_PAGE_OVERLAP
Code demo:
` ` `
mViewPager.setPageStyle(PageStyle.MULTI_PAGE)
          .setPageMargin(BannerUtils.dp2px(10))
          .setRevealWidth(BannerUtils.dp2px(10))
          .setHolderCreator(() -> new ImageResourceViewHolder(BannerUtils.dp2px(5)))
          .create(mDrawableList);
Copy the code
Also through the short 5 lines of code to achieve the above [MULTI_PAGE] effect, simple and easy to use! ## 3. How to achieve arbitrary placement of indicators? We can see that the indicator is displayed below the Banner in MULTI_PAGE_OVERLAP mode in the diagram above. How can this effect be achieved? - BannerViewPager supports placing indicators anywhere. This power comes from the fact that we have replaced the built-in IndicatorView with a custom indicator, which means that the IndicatorView is no longer in the BannerViewPager and can be placed anywhere. ### (1)Xml layout file belowCopy the code

<com.zhpan.bannerview.BannerViewPager android:id="@+id/banner_view" android:layout_width="match_parent" android:layout_height="180dp" android:layout_marginTop="20dp" app:bvp_page_style="multi_page" /> <com.zhpan.bannerview.indicator.CircleIndicatorView android:id="@+id/indicator_view" android:layout_width="wrap_content"  android:layout_height="wrap_content" android:layout_below="@id/banner_view" android:layout_centerHorizontal="true" android:layout_marginTop="10dp" />Copy the code
### (2) Replace internal indicators with setIndicatorView(IIndicator)Copy the code
    CircleIndicatorView indicatorView = findViewById(R.id.indicator_view);
mViewPager.setIndicatorView(indicatorView)
              .setIndicatorColor(Color.parseColor("#888888"),
                   Color.parseColor("#118EEA"))
              .setHolderCreator(() -> new ImageResourceViewHolder(BannerUtils.dp2px(5)))
              .create(mDrawableList);
Copy the code

CircleIndicatorView是什么?其实他就是内置在BannerViewPager中的指示器,现在你只需要把它同BannerViewPager放在同一个布局文件中就可以了。又是仅仅通过一行代码就完成了对内部指示器的替换,不知道你看完之后是否会拍案叫绝,竟然如此简单!

***注:2.5.0版本中CircleIndicatorView与DashIndicatorView已被弃用,可以用IndicatorView来替代这两个指示器。IndicatorView承载了CIRCLE与DASH两种样式***

## 4.setIndicatorSlideMode
我们应该见过很多App轮播图的指示器都会跟随页面一起滑动。BannerViewPager自然也不会少了这个功能。通过setIndicatorSlideMode(int)一行代码就可以轻松切换到下图(SMOOTH)的效果。
| NORMAL | SMOOTH |
|--|--|
| ![在这里插入图片描述](https://user-gold-cdn.xitu.io/2019/11/15/16e6f3c1b03e95a9?w=400&h=287&f=gif&s=1634765) |  ![在这里插入图片描述](https://user-gold-cdn.xitu.io/2019/11/15/16e6f3c1b40c0303?w=400&h=284&f=gif&s=1999055)|
代码实现仍然非常简单,使用BannerViewPager你只需要记住一个核心--Only One Line!所以演示代码不再贴出你应该不会揍我吧?

![](https://user-gold-cdn.xitu.io/2019/11/16/16e74a858acffe86?w=440&h=335&f=jpeg&s=33153)
## 5.setPageTransformerStyle

关于Transform更好的方式应该是留给开发者自己去实现,因此BannerViewPager中目前仅内置了四种常用Transform样式,如果不能满足需求,可以通过BannerViewPager的setPageTransformer(ViewPager.PageTransformer transformer)设置自定义的Transform。四种内置Transform样式如下:
| STACK | ACCORDION  | DEPTH | ROTATE  |  
|--|--|--|--|
|
![](https://user-gold-cdn.xitu.io/2019/11/17/16e7992dff1091f3?w=320&h=569&f=gif&s=296534) |![](https://user-gold-cdn.xitu.io/2019/11/17/16e79936284e618f?w=320&h=569&f=gif&s=548911) |![](https://user-gold-cdn.xitu.io/2019/11/17/16e799430aa8fa1e?w=320&h=569&f=gif&s=446023) |![](https://user-gold-cdn.xitu.io/2019/11/17/16e7994bd639fb00)  |
当然,BannerViewPager的功能并不仅仅局限于此,更多功能就不再演示,可以看下面所有开放的API接口。


## 6.BannerViewPager开放的API

BannerViewPager开放了众多API,以供满足不同的需求,具体如下表:

| 方法名 | 方法描述 | 说明 |
|--|--|--|
| BannerViewPager<T, VH> setCanLoop(boolean canLoop) | 是否开启循环 | 默认值true|
| BannerViewPager<T, VH> setAutoPlay(boolean autoPlay) | 是否开启自动轮播 | 默认值true|
| BannerViewPager<T, VH> setInterval(int interval) | 自动轮播时间间隔 |单位毫秒,默认值3000  |
| BannerViewPager<T, VH> setScrollDuration(int scrollDuration) | 设置页面滚动时间 | 设置页面滚动时间 |单位毫秒,默认值800  |
| BannerViewPager<T, VH> setRoundCorner(int radius) | 设置圆角 |默认无圆角 需要SDK_INT>=LOLLIPOP(API 21)  |
| BannerViewPager<T, VH> setOnPageClickListener(OnPageClickListener onPageClickListener) | 设置页面点击事件 |  |
| BannerViewPager<T, VH> setHolderCreator(HolderCreator\<VH> holderCreator) |设置HolderCreator  |必须设置HolderCreator,否则会抛出NullPointerException|
| BannerViewPager<T, VH> setIndicatorVisibility(@Visibility int visibility) | indicator vibility |默认值VISIBLE 2.4.2 新增|
| BannerViewPager<T, VH> setIndicatorStyle(int indicatorStyle) | 设置指示器样式 | 可选枚举(CIRCLE, DASH) 默认CIRCLE  |
| BannerViewPager<T, VH> setIndicatorGravity(int gravity) | 指示器位置 |可选值(CENTER、START、END)默认值CENTER |
| BannerViewPager<T, VH> setIndicatorColor(int normalColor,int checkedColor) | 指示器圆点颜色 |normalColor:未选中时颜色默认"#8C6C6D72", checkedColor:选中时颜色 默认"#8C18171C" |
| BannerViewPager<T, VH> setIndicatorSlideMode(int slideMode)  | 设置Indicator滑动模式 | 可选(NORMAL、SMOOTH),默认值SMOOTH  |
| BannerViewPager<T, VH> setIndicatorRadius(int radius) | 设置指示器圆点半径 | 默认值4dp|
| BannerViewPager<T, VH> setIndicatorRadius(int normalRadius,int checkRadius)  |设置指示器圆点半径  |  normalRadius:未选中时半径  checkedRadius:选中时的半径,默认值4dp |
| BannerViewPager<T, VH> setIndicatorWidth(int indicatorWidth) | 设置指示器宽度,如果是圆形指示器,则为直径 |  默认值8dp|
| BannerViewPager<T, VH> setIndicatorWidth(int normalWidth, int checkWidth) | 设置指示器宽度,如果是圆形指示器,则为直径 | 默认值8dp |
| BannerViewPager<T, VH> setIndicatorHeight(int indicatorHeight) | 设置指示器高度,仅在Indicator样式为DASH时有效 | 默认值normalIndicatorWidth/2 |
| BannerViewPager<T, VH> setIndicatorGap(int indicatorMargin) | 指示器圆点间距| 默认值为指示器宽度(或者是圆的直径)|
| BannerViewPager<T, VH> setIndicatorView(IIndicator indicatorView) | 设置自定义指示器| |
| BannerViewPager<T, VH> setPageTransformerStyle(int style) | 设置页面Transformer内置样式 |  |
| BannerViewPager<T, VH> setCurrentItem(int item) | Set the currently selected page. | 2.3.5新增 |
| void getCurrentItem() | 获取当前position | 2.3.5新增 |
| BannerViewPager<T, VH> setPageStyle(PageStyle pageStyle) | 设置页面样式 | 2.4.0新增 可选(MULTI_PAGE、NORMAL)MULTI_PAGE:一屏多页样式 |
| BannerViewPager<T, VH> setPageMargin(int pageMargin) | 设置页面间隔 | 2.4.0新增 |
| BannerViewPager<T, VH> setIndicatorMargin(int left, int top, int right, int bottom) | 设置Indicator边距 | 2.4.1新增 |
| BannerViewPager<T, VH> setOnPageChangeListener(OnPageChangeListener l) | 页面改变的监听事件 | 2.4.3新增 |
| void startLoop() |开启自动轮播 | 初始化BannerViewPager时不必调用该方法,设置setAutoPlay后会调用startLoop() |
| void stopLoop() | 停止自动轮播 | 如果开启自动轮播,为避免内存泄漏需要在onStop()或onDestroy中调用此方法 |
| List\<T> getList() | 获取Banner中的集合数据 |  |
| void create(List<T> list) |初始化并构造BannerViewPager  |必须调用,否则前面设置的参数无效  |

## 7.BannerViewPager支持的attrs
你也可以通过xml来设置BannerViewPager,xml支持的attrs如下:
| Attributes | format | description |
|--|--|--|
| bvp_interval | integer | 自动轮播时间间隔 |
| bvp_scroll_duration | integer | 页面切换时滑动时间|
| bvp_can_loop | boolean| 是否循环 |
| bvp_auto_play | boolean | 是否自动播放  |
| bvp_indicator_checked_color | color | indicator选中时颜色 |
| bvp_indicator_normal_color | color | indicator未选中时颜色 |
| bvp_indicator_radius | dimension | indicator圆点半径或者Dash模式的1/2宽度  |
| bvp_round_corner| dimension  | Banner圆角大小 |
| bvp_page_margin | dimension | 页面item间距 |
| bvp_reveal_width | dimension | 一屏多页模式下两边item漏出的宽度 |
| bvp_indicator_style | enum | indicator样式(circle/dash)  |
| bvp_indicator_slide_mode | enum | indicator滑动模式(normal/smooth) |
| bvp_indicator_gravity | enum | indicator位置(center/start/end) |
| bvp_page_style | enum | page样式(normal/multi_page/multi_page_overlap/multi_page_scale) |
| bvp_transformer_style | enum | transform样式(normal/depth/stack/accordion) |
| bvp_indicator_visibility| enum | indicator visibility(visible/gone/invisible) |


# 二、BannerViewPager详细使用说明
  

## 1.gradle中添加依赖

如果您已迁移到AndroidX请使用latestVersion(>=2.4.3.1)
Copy the code

implementation ‘com.zhpan.library:bannerview:latestVersion’

If not migrated to AndroidX please use (non-AndroidX packages are hosted on JCenter) :Copy the code

Implementation ‘com. Zhpan. Library: bannerview: 2.4.3.1’

2. Add the following code to the XML file:Copy the code
<com.zhpan.bannerview.BannerViewPager
        android:id="@+id/banner_view"
        android:layout_width="match_parent"
        android:layout_margin="10dp"
        android:layout_height="160dp" />
Copy the code
## 3. The Item page layout of the BannerCopy the code

<ImageView android:id="@+id/banner_image" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"  android:layout_alignParentBottom="true" android:background="#66000000" android:gravity="center_vertical"> <TextView android:id="@+id/tv_describe" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="center_vertical" android:layout_marginStart="15dp" android:gravity="center_vertical" android:paddingTop="5dp" android:paddingBottom="5dp" android:textColor="#FFFFFF" android:textSize="16sp" /> </LinearLayout>Copy the code

4. Customize a ViewHolder

public class NetViewHolder implements ViewHolder<BannerData> { private ImageView mImageView; private TextView mTextView; @Override public View createView(ViewGroup viewGroup, Context context, int position) { View view = LayoutInflater.from(context).inflate(R.layout.item_net, viewGroup, false); mImageView = view.findViewById(R.id.banner_image); mTextView = view.findViewById(R.id.tv_describe); return view; } @Override public void onBind(Context context, BannerData data, int position, int size) { ImageLoaderOptions options = new ImageLoaderOptions.Builder().into(mImageView).load(data.getImagePath()).placeHolder(R.drawable.placeholder).build(); ImageLoaderManager.getInstance().loadImage(options); mTextView.setText(data.getTitle()); }}Copy the code

5. Set BannerViewPager parameters

private BannerViewPager<BannerData, NetViewHolder> mBannerViewPager; private void initViewPager() { mBannerViewPager = findViewById(R.id.banner_view); mBannerViewPager.showIndicator(true) .setInterval(3000) .setCanLoop(false) .setAutoPlay(true) .setRoundCorner(DpUtils.dp2px(7)) .setIndicatorColor(Color.parseColor("#935656"), Color.parseColor("#FF4C39")) .setIndicatorGravity(BannerViewPager.END) .setScrollDuration(1000).setHolderCreator(NetViewHolder::new) .setOnPageClickListener(position -> { BannerData bannerData = mBannerViewPager.getList().get(position); Toast. MakeText (NetworkBannerActivity. This, click on the "image" + position + "" + bannerData getDesc (), Toast. LENGTH_SHORT), show (); }).create(mList); }Copy the code

6. Enable or stop the round-casting

After 2.5.0, stopLoop and startLoop methods do not need to be managed in the Activity or Fragment, but these two methods are still reserved for external development

If automatic rotoasting is enabled, be sure to stop the rotoasting in onDestroy to avoid memory leaks.

@Override protected void onDestroy() { super.onDestroy(); if (mBannerViewPager ! = null) mViewpager.stopLoop(); }Copy the code

To save performance, you can also stop the rotation in onStop and enable the rotation in onResume:

@Override protected void onStop() { super.onStop(); if (mBannerViewPager ! = null) mBannerViewPager.stopLoop(); } @Override protected void onResume() { super.onResume(); if (mBannerViewPager ! = null) mBannerViewPager.startLoop(); }Copy the code

3. Advanced function — customize IndicatorView

Because indicator styles are so variable, it’s impossible to have all the styles built into the BannerViewPager, so I’ve left it up to the developers to define them, so they can meet all their needs. But custom IndicatorView needs to have a certain basis for custom View, although I have handled a lot of logic in BaseIndicatorView, it is still up to the developer to draw indicators according to their needs. Now let’s take a look at how to customize IndicatorView.

As for customizing IndicatorView, we already mentioned in the first section when we explained the position of Indicator, which is to replace the internal Indicator with setIndicator(IIndicator). Of course, this method takes more than just the two built-in indicatorViews, it can also be our own implemented indicators. Premise just need to inherit BaseIndicatorView or inherit View and implement IIndicator, and then draw according to the needs.

(1) understanding BaseIndicatorView

BaseIndicatorView is a class in the BannerViewPager library that inherits from View and implements the IIndicator interface. This class stores many parameters of BannerViewPager, such as pageSize, slideProgress, and currentPosition. These are the kinds of information that are used when drawing IndicatorView. With these parameters we can draw the indicator more easily. If you think my calculation of these data is not accurate or wrong, you can implement IIndicator interface to calculate by yourself. In this article, I’ll implement an example of a custom indicator by inheriting BaseIndicatorView. You can see the full code for BaseIndicatorView by clicking on the link.

(2) Start custom IndicatorView

Ok, let’s complete a custom IndicatorView as shown below!

Create a new FigureIndicatorView class and inherit BaseIndicatorView

public class FigureIndicatorView extends BaseIndicatorView { private int radius = DpUtils.dp2px(20); private int backgroundColor = Color.parseColor("#88FF5252"); private int textColor = Color.WHITE; private int textSize=DpUtils.dp2px(13); / /... Override protected void onMeasure(int widthMeasureSpec, int widthMeasureSpec) int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); setMeasuredDimension(2 * radius, 2 * radius); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint.setColor(backgroundColor); canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius, mPaint); mPaint.setColor(textColor); mPaint.setTextSize(textSize); String text = currentPosition + 1 + "/" + pageSize; int textWidth = (int) mPaint.measureText(text); Paint.FontMetricsInt fontMetricsInt = mPaint.getFontMetricsInt(); int baseline = (getMeasuredHeight() - fontMetricsInt.bottom + fontMetricsInt.top) / 2 - fontMetricsInt.top; canvas.drawText(text, (getWidth() - textWidth) / 2, baseline, mPaint); } public void setRadius(int radius) { this.radius = radius; } @Override public void setBackgroundColor(@ColorInt int backgroundColor) { this.backgroundColor = backgroundColor; } public void setTextSize(int textSize) { this.textSize = textSize; } / /... Omit irrelevant code}Copy the code

Those of you who have a custom View base should be able to read this code pretty easily. First, we measure the size of the View using the onMeasure() method. Next, we draw the circle and text in the onDraw method. It’s easy to implement a custom IndicatorView. Of course, the example itself is relatively simple. If you need to draw more complex and animated indicators, check out the source code CircleIndicatorView and DashIndicatorView for inspiration.

(3) Set a custom indicator

Next we will draw our own indicator into the BannerViewPager!

    FigureIndicatorView indicatorView = new FigureIndicatorView(mContext);
    indicatorView.setRadius(BannerUtils.dp2px(18));
    indicatorView.setTextSize(BannerUtils.dp2px(13));
    indicatorView.setBackgroundColor(Color.parseColor("#aa118EEA"));
    
    mViewPager.setIndicatorGravity(IndicatorGravity.END)
              .setIndicatorView(indicatorView)
              .setHolderCreator(() -> new ImageResourceViewHolder(0))
              .create(mDrawableList);    
        
Copy the code

Still so natural and natural! Well, that’s all for today’s introduction to BannerViewPager. The following article will take a look at the source code of BannerViewPager and see how it implements complex functions through a simple Api implementation.

If you’ve seen this, you’re sure you can’t just hit a star on GitHub? The source code is at the end of this article. Pull Request is also welcome if you have good Idea.

BannerViewPager source code analysis

Download the source code

This article was last updated on November 16, 2019