youth5201314 / banner

🔥🔥🔥Banner 2.0 来了!Android广告图片轮播控件,内部基于ViewPager2实现,Indicator和UI都可以自定义。
Apache License 2.0
12.92k stars 2.51k forks source link

老哥不更新了吗?我看issue这边好多问题都没解决,我在kotlin使用adapter时也出了些问题,不过好在翻之前的issus找到了办法,虽然后面自定义adapter时又出了点问题,不过好在最后都解决了,我就在这个issus里面整理一下,希望能帮后来的人少走点弯路吧🤔 #1130

Closed SaltedFish-Extreme closed 10 months ago

SaltedFish-Extreme commented 2 years ago

我是使用kotlin开发的,java的使用在md文档里说的也比较清楚了,这里我就光说说我在kotlin中使用banner时的一些事情

首先说说默认使用方法 一开始不管怎样肯定要先在需要banner的地方使用下面这段来添加banner控件

<com.youth.banner.Banner
        android:id="@+id/banner"
        android:layout_width="match_parent"
        android:layout_height="230dp"
        android:scaleType="fitXY" />

之后,就要在代码里懒加载banner控件,这里我就在fragment中使用了

private val banner: Banner<String, BannerImageAdapter<String>> by lazy { requireView().findViewById(R.id.banner) }

Banner的泛型里需要传两个字段,第一个就是数据源类型,这里用的字符串类型,第二个就是adapter了,这里使用默认的BannerImageAdapter,需要接收一个字符串泛型,这样就可以使用默认的BannerImageAdapter来设置adapter,设置adapter使用

banner.setAdapter(object : BannerImageAdapter<String>(bannerImages) {
                        override fun onBindView(holder: BannerImageHolder, data: String, position: Int, size: Int) {
                            Glide.with(this@HomeFragment)
                                .load(data)
                                .into(holder.imageView)
                        }
                    })

需要传进来的bannerImages参数是字符串集合,我这里的集合里的是图片URL路径字符串,重写onBindView方法,这里使用Glide来加载图片到banner里,比较简单,效果如图所示,右下角的指示器标点不大明显,md文档以及后面会有属性设置 image

接下来就说说自定义adapter了,这里我使用的是demo中演示过的标题加图片的方式,使用kotlin来做

首先就先自定义一个banner布局文件,这里复制修改的demo中的布局文件

<?xml version="1.0" encoding="utf-8"?><!--自定义带标题的banner布局-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/image"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:contentDescription="@android:string/unknownName"
        android:scaleType="centerCrop" />

    <TextView
        android:id="@+id/bannerTitle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:background="@color/black_translucent"
        android:ellipsize="marquee"
        android:focusable="true"
        android:focusableInTouchMode="true"
        android:gravity="center_vertical"
        android:padding="10dp"
        android:singleLine="true"
        android:textColor="@color/white"
        android:textIsSelectable="true" />
</RelativeLayout>

这里贴的本来带的跑马灯效果的代码没删,可以把除了android:layout_alignParentBottom之外为true的属性和android:ellipsize给删除

接下来就自定义一个带标题的adapter类,数据源dataListBannerResponse数据类的List集合

class ImageTitleAdapter(dataList: List<BannerResponse>) : BannerAdapter<BannerResponse, ImageTitleAdapter.ImageTitleHolder>(dataList) {

    inner class ImageTitleHolder(view: View) : RecyclerView.ViewHolder(view) {
        val imageView: ImageView = view.findViewById(R.id.image)
        val title: TextView = view.findViewById(R.id.bannerTitle)
    }

    override fun onCreateHolder(parent: ViewGroup, viewType: Int): ImageTitleHolder {
        return ImageTitleHolder(LayoutInflater.from(parent.context).inflate(R.layout.banner_image_title, parent, false))
    }

    override fun onBindView(holder: ImageTitleHolder, data: BannerResponse, position: Int, size: Int) {
        Glide.with(holder.imageView).load(data.imagePath).into(holder.imageView)
        holder.title.text = data.title
    }
}

这里只是将banner数据类的imagePath用Glide显示到xml中的ImageView上,还有将title赋值给TextView上

BannerResponse数据类如下

data class BannerResponse(val imagePath: String, val title: String)

只是设置了图片路径和标题两个字段

接下来就比较关键了,懒加载banner控件

private val banner: Banner<BannerResponse, ImageTitleAdapter> by lazy { requireView().findViewById(R.id.banner) }

Banner的泛型里传的第一个就是BannerResponse数据源类型,不需要加List,第二个就是刚才自定义的ImageTitleAdapter,这样就剩最后一步设置adapter了,使用

banner.setAdapter(ImageTitleAdapter(List<BannerResponse>))

来设置数据源添加到adapter中,这里的List<BannerResponse>是我从网络获取的数据源集合,也可以模拟假数据放进集合添加进来

最后说一下指示器的配置

banner.apply {
//设置圆点指示器
indicator = CircleIndicator(context)
//设置被选中颜色
setIndicatorSelectedColorRes(android.R.color.holo_blue_bright)
//设置位置
setIndicatorGravity(IndicatorConfig.Direction.RIGHT)
//设置边距
setIndicatorMargins(IndicatorConfig.Margins(0, 0, BannerConfig.INDICATOR_MARGIN, BannerUtils.dp2px(15f)))
}

大概就是这么多了,md文档里有很详细的属性介绍了,我大概就能用到这么多了,最后上一下效果图 image 好了,希望能帮到大家吧😉

Lw1244204021 commented 2 years ago

赞,主要是懒加载那里,要用到泛型,不好想

SaltedFish-Extreme commented 2 years ago

赞,主要是懒加载那里,要用到泛型,不好想

😉当时这个地方也难倒我了😂

Terran-Marine commented 2 years ago

非常感谢,我遇到同样问题,正想着怎么加范型呢.

SaltedFish-Extreme commented 2 years ago

非常感谢,我遇到同样问题,正想着怎么加范型呢.

😂能帮到你就好了

xuexixuexijpg commented 2 years ago

建议再加一个怎么设置滑动冲突,比如常见的ViewPager2里的RecycleView的头布局为banner

SaltedFish-Extreme commented 2 years ago

建议再加一个怎么设置滑动冲突,比如常见的ViewPager2里的RecycleView的头布局为banner

我这只是在kotlin里的常规用法的issues😅 我也没有在vp的rv里使用过banner,只是在主页用 BRVAHBRV 的时候用过,BRVAH可以直接使用addHeader设置一个头布局,BRV麻烦一点,不过文档也很清楚,BRV的使用可以参考下我 玩安卓项目 的用法,实现方法有很多,你甚至可以直接用coordinateLayout来嵌套实现,怎么方便怎么来😁

SaltedFish-Extreme commented 2 years ago

建议再加一个怎么设置滑动冲突,比如常见的ViewPager2里的RecycleView的头布局为banner

说起来viewpager使用大多数是填充fragment的,直接使用FragmentStateAdapter,很少是在rv操作的,那样太麻烦了,一个扩展函数封装好,直接使用更方便 image

xuexixuexijpg commented 2 years ago

建议再加一个怎么设置滑动冲突,比如常见的ViewPager2里的RecycleView的头布局为banner

说起来viewpager使用大多数是填充fragment的,直接使用FragmentStateAdapter,很少是在rv操作的,那样太麻烦了,一个扩展函数封装好,直接使用更方便 image

这个我知道,其实我想说的就是fragment里的recycleview里的banner的嵌套或多嵌套能不能很方便实现,我现在就在摸鱼看看怎么搞这个,哈哈

SaltedFish-Extreme commented 2 years ago

这个我知道,其实我想说的就是fragment里的recycleview里的banner的嵌套或多嵌套能不能很方便实现,我现在就在摸鱼看看怎么搞这个,哈哈

加头布局就行啊🤔用BRVBRVAH框架都能很方便的实现,或者自定义一个添加头尾布局的RecyclerView,我有个地方就用的轮子哥的自定义rv😁

com13117340768 commented 1 year ago

我这边按你的添加 late init 也不行还是报错,我用viewBinding 设置就好了,直接点出来。

1,在build.gradle的android下添加 buildFeatures { viewBinding = true }

2,在MainActivity private val activityViewBinding: ActivityMainBinding by lazy { ActivityMainBinding.inflate(layoutInflater) } setContentView(activityViewBinding.root)

3, activityViewBinding.bannerLayout1.apply{ ....... }

SaltedFish-Extreme commented 1 year ago

我这边按你的添加 late init 也不行还是报错,我用viewBinding 设置就好了,直接点出来。

嗯,方法有很多,只要能实现就好了,我好像没有用late init,用by lazy做的,后面不大用这个轮播图了😂