Android轮播控件
ViewPager无限轮播功能,内置了圆形的IndicatorView,支持三种动画切换。
banner的实现核心思想是通过count+2的轮播思想。
- 支持一屏三页
- 支持魅族效果
- 支持自定义Indicator
- 支持自定义view
- 支持数据刷新
- 解决下拉刷新等滑动冲突问题,如嵌套SwipeRefreshLayout
- 解决多次重复回调onPageSelected问题
- 良好的代码封装,更多优化请参考代码实现。
https://github.com/zguop/banner
效果图
点击下载 banner.apk 体验
描述 | 图片 |
---|---|
基本使用的功能,请下载apk体验更流畅 | tu1.png |
描述 | 普通样式 | 两边缩放 | 魅族样式 |
---|---|---|---|
一屏三页 | Compress_20200102_191703.gif | Compress_20200102_191737.gif | Compress_20200102_191805.gif |
效果图 | 1 | 2 |
---|---|---|
Indicator查看simple代码 | Compress_20200102_193932.gif | Compress_20200102_194030.gif |
Compress_20200102_194059.gif | Compress_20200102_194242.gif | Compress_20200102_193909.gif |
核心原理
-
一屏一页
我们以数据源四张图片举个实际例子:needCount(6) = count(4) + 2 ,实际轮播的图片是有6张,存放在banner中对应:
四张图片 | - | 0 | 1 | 2 | 3 | - |
---|---|---|---|---|---|---|
实际轮播的数量 | 3 | 0 | 1 | 2 | 3 | 0 |
对应的idnex | 0 | 1 | 2 | 3 | 4 | 5 |
我们可以看到在实际的index=0是图片的最后一张,index=5是图片的第一张,我们只要当右滑动到index=5时,通过 viewPager.setCurrentItem(1, false);切换至第一张,当左滑懂到index=0,通过viewPager.setCurrentItem(count, false);切换到实际图片的最后一张,进行过渡实现了循环轮播的一个效果。
-
一屏三页
还是以4张图片举个例子,一屏三页,一次要展示三张图片,相当左右两边都加载了一张图片,也就是多加载了2张图片,需要的数量:needCount(6) = count(4) + 4 ,实际轮播是有8张,存放在banner对应:
四张图片 | - | - | 0 | 1 | 2 | 3 | - | - |
---|---|---|---|---|---|---|---|---|
实际轮播的数量 | 2 | 3 | 0 | 1 | 2 | 3 | 0 | 1 |
对应的idnex | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
同样的控制滑动到最后一张图片和第一张图片对应的索引位置,实现轮播的效果,这里就不多说了,具体可查看项目代码实现。
使用步骤
Step 1.依赖banner
Gradle
dependencies{
implementation 'com.to.aboomy:banner:3.0.6' //最新版本
implementation 'com.to.aboomy:banner:3.0.6-x' //androidx版本
}
或者引用本地lib
compile project(':banner')
Step 2.xml
<com.to.aboomy.banner.Banner
android:id="@+id/banner"
android:layout_width="match_parent"
android:layout_height="250dp"/>
Step 3.自定义HolderCreator
//实现HolderCreator接口
public interface HolderCreator {
View createView(Context context,final int index, Object o);
}
//举个栗子
public class ImageHolderCreator implements HolderCreator {
@Override
public View createView(final Context context, final int index, Object o) {
ImageView iv = new ImageView(context);
iv.setScaleType(ImageView.ScaleType.FIT_XY);
Glide.with(iv).load(o).into(iv);
//内部实现点击事件
iv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(context, index + "", Toast.LENGTH_LONG).show();
}
});
return iv;
}
}
Step 4.在页面中使用Banner
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
banner = findViewById(R.id.banner);
//使用内置Indicator
IndicatorView qyIndicator = new IndicatorView(this)
.setIndicatorColor(Color.DKGRAY)
.setIndicatorSelectorColor(Color.WHITE);
banner.setIndicator(qyIndicator)
.setHolderCreator(new ImageHolderCreator())
.setPages(list);
}
简单设置一屏三页效果
//设置左右页面露出来的宽度及item与item之间的宽度
.setPageMargin(UIUtil.dip2px(this, 20), UIUtil.dip2px(this, 10))
//内置ScaleInTransformer,设置切换缩放动画
.setPageTransformer(true, new ScaleInTransformer())
关于ViewPager切换动画
Sample中集成了以下两个ViewPager切换动画,请运行Sample查看动画效果,参考需要的ViewPagerTransform放到项目中,或者根据需求进行自定义。
如何自定义Indicator
//实现Indicator接口
/**
* 可以实现该接口,自定义Indicator 可参考内置的{@link IndicatorView}
*/
public interface Indicator extends ViewPager.OnPageChangeListener {
/**
* 当数据初始化完成时调用
*
* @param pagerCount pager数量
*/
void initIndicatorCount(int pagerCount);
/**
* 返回一个View,添加到banner中
*/
View getView();
/**
* banner是一个RelativeLayout,设置banner在RelativeLayout中的位置,可以是任何地方
*/
RelativeLayout.LayoutParams getParams();
}
//举个栗子
public class IndicatorView extends View implements Indicator{
@Override
public void initIndicatorCount(int pagerCount) {
this.pagerCount = pagerCount;
setVisibility(pagerCount > 1 ? VISIBLE : GONE);
requestLayout();
}
@Override
public View getView() {
return this;
}
/**
* 控制Indicator在Banner中的位置,开发者自行实现
*/
@Override
public RelativeLayout.LayoutParams getParams() {
if (params == null) {
params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
params.addRule(RelativeLayout.CENTER_HORIZONTAL);
params.bottomMargin = dip2px(10);
}
return params;
}
/**
* banner切换时同步回调的三个方法
*/
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
selectedPage = position;
offset = positionOffset;
invalidate();
}
@Override
public void onPageSelected(int position) {
}
@Override
public void onPageScrollStateChanged(int state) {
}
}
Banner提供的方法介绍,banner未提供任何自定义属性
方法名 | 描述 |
---|---|
setPageTransformer(boolean reverseDrawingOrder, ViewPager.PageTransformer transformer) | 设置viewpager的自定义动画 |
setOuterPageChangeListener(ViewPager.OnPageChangeListener outerPageChangeListener) | 设置viewpager的滑动监听 |
setAutoTurningTime(long autoTurningTime) | 设置自动轮播时长 |
setPagerScrollDuration(int pagerScrollDuration) | 设置viewpager的切换时长 |
setAutoPlay(boolean autoPlay) | 设置是否自动轮播,大于1页可以轮播 |
setIndicator(Indicator indicator) | 设置indicator |
setIndicator(Indicator indicator, boolean attachToRoot) | 设置indicator |
HolderCreator(HolderCreator holderCreator)) | 设置view创建接口 |
setPages(List<?> items) | 加载数据,此方法时开始轮播的方法,请再最后调用 |
setPages(List<?> items, int startPosition) | 重载方法,设置轮播的起始位置 |
isAutoPlay() | 是否无限轮播 |
getCurrentPager() | 获取viewPager位置 |
startTurning() | 开始轮播 |
stopTurning() | 停止轮播 |
setPageMargin(int multiWidth, int pageMargin) | 设置一屏多页 |
setPageMargin(int leftWidth, int rightWidth, int pageMargin) | 设置一屏多页,方法重载 |
内置IndicatorView使用方法介绍,没有提供任何自定义属性
方法名 | 描述 |
---|---|
setIndicatorRadius(float indicatorRadius) | 设置圆点半径 |
setIndicatorSpacing(float indicatorSpacing) | 设置圆点间距 |
setIndicatorStyle(@IndicatorStyle int indicatorStyle) | 设置圆点切换动画,内置三种切换动画,请参考Sample |
setIndicatorColor(@ColorInt int indicatorColor) | 设置默认的圆点颜色 |
setIndicatorSelectorColor(@ColorInt int indicatorSelectorColor) | 设置选中的圆点颜色 |
setParams(RelativeLayout.LayoutParams params) | 设置IndicatorView在banner中的位置,默认底部居中,距离底部10dp,请参考Sample |
网友评论