Android Banner轮播控件

Android轮播控件

ViewPager无限轮播功能,内置了圆形的IndicatorView,支持三种动画切换。
banner的实现核心思想是通过count+2的轮播思想。

logo.png
  • 支持一屏三页
  • 支持魅族效果
  • 支持自定义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放到项目中,或者根据需求进行自定义。

ViewPagerTransforms

MagicViewPager

如何自定义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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容