登录

去注册

登录

注册

去登录

注册

一个简单好用的自动轮播控件,支持UI风格完全自定义

wenjiangit   2019-01-03  

LoopBanner

一个简单好用的自动轮播控件,支持UI风格完全自定义

功能介绍

  • 支持自动无限轮播,无需手动开启和关闭,无需担心内存泄漏
  • 支持页面内容完全自定义
  • 支持自定义页面点击事件
  • 支持自定义指示器样式

基本上该有的都有,并且使用简单,只要你会用ListView或者RecyclerView

效果图和Demo下载

图片资源来源于鸿洋大神的wanandroid

扫描二维码下载

扫描二维码下载

点击下载demo

使用介绍

1.添加Gradle依赖

在项目的build.gradle文件中添加jitpack仓库地址

allprojects {
    repositories {
        ...
        //添加下面的仓库地址
        maven { url "https://jitpack.io" }
    }
}

appbuild.gradle文件中添加dependencies

dependencies {
    ...
    implementation 'com.github.wenjiangit:LoopBanner:1.0.1'
}

版本更新:点击查看最新版本号

2.在xml布局资源中引用

 <com.wenjian.loopbanner.LoopBanner
            android:id="@+id/lb1"
            android:layout_width="match_parent"
            android:layout_height="130dp"
            app:lb_indicatorStyle="normal"
            app:lb_pageMargin="4dp"
            app:lb_lrMargin="16dp"
            app:lb_interval="4000" />

有关的属性定义后面再详细介绍

3.绑定数据

绑定数据有两种方式

  1. 直接设置图片资源,并添加点击事件
    //设置图片资源并添加page点击事件
        lb1.setImages(DataCenter.loadImages()) { _, position ->
            Toast.makeText(this, "position=$position", Toast.LENGTH_SHORT).show()
        }

当然如果你不需要点击事件,那就更简单了,如下:

//直接绑定图片资源
lb1.setImages(DataCenter.loadImages())
  1. 通过setAdapter绑定数据
//直接设置adapter,默认的itemView是ImageView
lb2.adapter = object : LoopAdapter<String>(DataCenter.loadImages()) {
    override fun onBindView(holder: ViewHolder, data: String, position: Int) {
        val itemView = holder.itemView as ImageView
        Glide.with(holder.context).load(data).into(itemView)
        itemView.setOnClickListener {
            Toast.makeText(this@MainActivity, "position=$position", Toast.LENGTH_SHORT).show()
        }
    }
}

Adapter的构建也很简单,只需要继承LoopAdapter,传入数据列表,并重写onBindView方法即可,在onBindView中可以设置点击事件,并绑定控件,与RecylerViewonBindView思想是一样的。

需要注意的是LoopAdapter接受两个参数,如下

public LoopAdapter(List<T> data, int layoutId) {
    mData = data;
    mLayoutId = layoutId;
}

layoutId如果不传,默认的holder.itemViewImageView,否则就是加载对应的布局而生成的view。如下:

class MyAdapter(data: List<BannerEntity>) : LoopAdapter<BannerEntity>(data, R.layout.lay_banner_item) {
    override fun onBindView(holder: ViewHolder, data: BannerEntity, position: Int) {
        val image = holder.getView<ImageView>(R.id.iv_image)
        Glide.with(holder.context).load(data.url).into(image)
        holder.setText(R.id.tv_title,data.title)

        holder.itemView.setOnClickListener {
            Toast.makeText(holder.context, "position=$position", Toast.LENGTH_SHORT).show()
        }
    }
}
//设置Adapter
lb3.adapter = MyAdapter(DataCenter.loadEntities())

ViewHolder提供getView方法获取对应的控件,与holder.itemView.findViewById()的效果是一样的,不过getView做了缓存,可以减少每次findViewById的时间。

4.设置指示器风格(可选)

  1. 属性设置
//普通风格,小圆点(默认样式)
app:lb_indicatorStyle="normal"
//京东app首页广告图指示器风格,挺独特的
app:lb_indicatorStyle="jd"
//小药丸风格,选中的小圆点变成小药丸
app:lb_indicatorStyle="pill"
  1. 代码设置
lb1.setIndicatorStyle(LoopBanner.Style.NORMAL)
lb1.setIndicatorStyle(LoopBanner.Style.JD)
lb1.setIndicatorStyle(LoopBanner.Style.PILL)

到此为止,经过以上的设置已经可以实现市场上大部分的效果了。

补充说明

这部分适用于对于UI效果或者指示器风格有更高要求的人

1.自定义属性说明

<!--page之间的间距-->
<attr name="lb_pageMargin" format="dimension|reference" />
<!--是否无限轮播-->
<attr name="lb_canLoop" format="boolean" />
<!--中间page离父布局的左右间距-->
<attr name="lb_lrMargin" format="dimension|reference" />
<!--page的上间距-->
<attr name="lb_topMargin" format="dimension|reference" />
<!--page的下间距-->
<attr name="lb_bottomMargin" format="dimension|reference" />
<!--轮播周期-->
<attr name="lb_interval" format="integer" />
<!--离屏缓存个数-->
<attr name="lb_offsetPageLimit" format="integer" />
<!--page的上下左右间距,如果同时设置单独方向的间距,会被覆盖掉-->
<attr name="lb_margin" format="dimension|reference" />

<!--是否显示指示器-->
<attr name="lb_showIndicator" format="boolean" />
<!--指示器位置-->
<attr name="lb_indicatorGravity">
    <flag name="bottomLeft" value="1" />
    <flag name="bottomRight" value="2" />
    <flag name="bottomCenter" value="3" />
</attr>
<!--单个指示器大小-->
<attr name="lb_indicatorSize" format="dimension"/>
<!--单个指示器之间的间距-->
<attr name="lb_indicatorMargin" format="dimension|reference"/>
<!--选中的指示器的drawable资源-->
<attr name="lb_indicatorSelect" format="reference"/>
<!--未选中的指示器的drawable资源-->
<attr name="lb_indicatorUnSelect" format="reference"/>
<!--指示器容器垂直方向的间距-->
<attr name="lb_indicatorParentMarginV" format="dimension|reference"/>
<!--指示器容器水平方向的间距-->
<attr name="lb_indicatorParentMarginH" format="dimension|reference"/>
<!--指示器风格样式-->
<attr name="lb_indicatorStyle">
    <enum name="normal" value="0"/>
    <enum name="jd" value="1"/>
    <enum name="pill" value="2"/>
</attr>

每个属性都有详细注释,并且提供对应的代码设置api,就不一一介绍了。

2.指示器位置和样式

位置设置:

lb_indicatorGravity:定义指示器处于左下,中下,右下

lb_indicatorParentMarginV:定义指示器垂直向下的间距

lb_indicatorParentMarginH:定义指示器水平方向的间距,靠左还是靠右由lb_indicatorGravity决定

这3个属性配合使用基本上可以定位到父容器内的任何位置。

样式设置:

lb_indicatorSelect:选中的drawable资源

lb_indicatorUnSelect:未选中的drawable资源

当然也可以通过代码设置,如下:

 /**
     * 设置指示器资源
     *
     * @param selectRes   选中
     * @param unSelectRes 未选中
     */
    public void setIndicatorResource(@DrawableRes int selectRes, @DrawableRes int unSelectRes) {
        this.setIndicatorResource(selectRes, unSelectRes, true);
    }

注意:如果drawable资源设置了宽高,就会使用drawable的宽高,如下

<shape xmlns:android="http://schemas.android.com/apk/res/android">

    <solid android:color="?attr/colorAccent"/>

    <size android:width="14dp" android:height="6dp"/>

    <corners android:radius="5dp"/>

</shape>

如果没有设置宽高,就会使用<attr name="lb_indicatorSize" format="dimension"/>属性值.

这两个配合使用可以实现80%的效果,另外的20%需要通过以下方式实现

实现IndicatorAdapter接口,每个方法的作用可以看注释

public interface IndicatorAdapter {

    /**
     * 添加子indicator
     *
     * @param container 父布局
     * @param drawable  配置的Drawable
     * @param size      配置的指示器大小
     * @param margin    配置的指示器margin值
     */
    void addIndicator(LinearLayout container, Drawable drawable, int size, int margin);

    /**
     * 应用选中效果
     *
     * @param prev    上一个
     * @param current 当前
     * @param reverse 是否逆向滑动
     */
    void applySelectState(View prev, View current, boolean reverse);

    /**
     * 应用为选中效果
     *
     * @param indicator 指示器
     */
    void applyUnSelectState(View indicator);


    /**
     * 是否需要对某个位置进行特殊处理
     *
     * @param container 指示器容器
     * @param position  第一个或最后一个
     * @return 返回true代表处理好了
     */
    boolean handleSpecial(LinearLayout container, int position);


}

以下是默认的实现SelectDrawableAdapter,大家可以参考下

public final class SelectDrawableAdapter implements IndicatorAdapter {

    private LinearLayout.LayoutParams mLayoutParams;

    @Override
    public void addIndicator(LinearLayout container, Drawable drawable, int size, int margin) {
        LinearLayout.LayoutParams layoutParams = generateLayoutParams(drawable, size, margin);
        ImageView image = new ImageView(container.getContext());
        image.setImageDrawable(drawable);
        container.addView(image, layoutParams);
    }

    @Override
    public void applySelectState(View prev, View current, boolean reverse) {
        current.setSelected(true);
        current.requestLayout();
    }

    private LinearLayout.LayoutParams generateLayoutParams(Drawable drawable, int size, int margin) {
        if (mLayoutParams == null) {
            final int minimumWidth = drawable.getMinimumWidth();
            final int minimumHeight = drawable.getMinimumHeight();
            LinearLayout.LayoutParams layoutParams;
            if (minimumWidth == 0 || minimumHeight == 0) {
                layoutParams = new LinearLayout.LayoutParams(size, size);
            } else {
                layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
                        LinearLayout.LayoutParams.WRAP_CONTENT);
            }
            layoutParams.leftMargin = margin;
            mLayoutParams = layoutParams;
        }
        return mLayoutParams;
    }

    @Override
    public void applyUnSelectState(View indicator) {
        indicator.setSelected(false);
        indicator.requestLayout();
    }

    @Override
    public boolean handleSpecial(LinearLayout container, int position) {
        return false;
    }

除此之外,还有一个JDIndicatorAdapter,这里就不贴代码了,感兴趣的可以自己看看。

然后通过调用以下方法设置自己定义的指示器适配器即可,建议各种配置设置都放在setAdapter方法调用之前.

    /**
     * 设置指示适配器
     *
     * @param indicatorAdapter IndicatorAdapter
     */
    public void setIndicatorAdapter(IndicatorAdapter indicatorAdapter) {
        this.setIndicatorAdapter(indicatorAdapter, true);
    }

3.页面切换效果

观察了市面上大多数知名app后,发现并没有使用多么炫酷的切换效果,都是一般的平滑过度,所以这里也没有内置切换效果,不过开放了接口,有需求的同学可以自己设置。

常见的切换效果参考MagicViewPager

public void setPageTransformer(ViewPager.PageTransformer pageTransformer)

4.图片圆角和硬件加速

如果需要图片或者CardView的圆角效果,就不要设置lb_lrMargin,否则你设置任何圆角效果都是毫无意义的,这关系到硬件加速,具体原因还不清楚。

感谢

BaseRecyclerViewAdapterHelper(思想来源)

glide(内置图片加载框架)

wanandroid(素材来源)

MagicViewPager(页面切换效果参考)

联系我

qq:824636515

邮箱:824636515@qq.com

项目地址:https://github.com/wenjiangit/LoopBanner