Android仿某看书Banner轮播背景渐变效果

龙旋

共 12029字,需浏览 25分钟

 · 2021-12-27

最近发现一个比较有意思的效果,于是想自己操作实践下。效果图如下:



实现的效果:




1、实现思路


  • 使用Banner+ 透明的 ImageView 进行搭配实现。

  • 使用Palette来将Banner中每一个Bitmap进行取色,将最亮的色值取出。

  • 将取出的色值配置到背景ImageView上。


2、开始实现


1. 导入依赖

//banner依赖implementation 'com.youth.banner:banner:1.4.10'
//palette依赖implementation 'com.android.support:palette-v7:23.4.0'


2. 编写xml文件

                 android:layout_width="match_parent"                android:layout_height="match_parent">
android:id="@+id/view_bg" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#999999" android:paddingTop="100dp" android:scaleType="fitXY" android:src="@drawable/banner_head_bg" android:visibility="visible" />
android:id="@+id/view_banner" android:layout_width="match_parent" android:layout_height="150dp" android:layout_marginTop="25dp" app:image_scale_type="fit_xy" app:indicator_height="6dp" app:indicator_width="6dp" />


这里ImageVIew使用的图片如下(透明背景):


下载后创建drawable-xxhdpi文件夹并放入图片



注意这上面有一张图片。


3. 创建数据

      //Banner数据的集合      var mBannerList: ArrayList = ArrayList()
//添加Banner的数据 mBannerList.add("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1556532613936&di=3769695217e3424f18c3d23966ecd4dc&imgtype=0&src=http%3A%2F%2Fpic.90sjimg.com%2Fback_pic%2Fqk%2Fback_origin_pic%2F00%2F04%2F19%2F70e2846ebc02ae10161f25bf7f5461a1.jpg"); mBannerList.add("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1556532665664&di=9ead9eb8a9fe2af9a01b0dd39f3e41f4&imgtype=0&src=http%3A%2F%2Fbpic.588ku.com%2Fback_pic%2F05%2F37%2F28%2F475a43591370453.jpg"); mBannerList.add("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1556532613934&di=0be1c6bbf0441bd19ef6d4e3ce799263&imgtype=0&src=http%3A%2F%2Fpic96.nipic.com%2Ffile%2F20160430%2F7036970_215739900000_2.jpg"); mBannerList.add("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1556532613936&di=4dd453940f49d9801826e6b820490957&imgtype=0&src=http%3A%2F%2Fpic161.nipic.com%2Ffile%2F20180410%2F26429156_154754410034_2.jpg"); mBannerList.add("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1556532613935&di=39c387012e3d8fa2eef90129eaf83c5c&imgtype=0&src=http%3A%2F%2Fpic25.nipic.com%2F20121211%2F7031681_170238437383_2.jpg");


创建实体类用来存放通过Palette获取到的每个Banner的色值


Palette介绍


它能让你从图像中提取突出的颜色。这个类能提取以下几种颜色:

  1. Vibrant (充满活力的)  2. Vibrant dark (充满活力的黑)  3. Vibrant light (充满活力的亮)  4. Muted (柔和的)  5. Muted dark (柔和的黑)  6. Muted lighr (柔和的亮)
package com.lcz.coolweatherjetpack;
/** * banner图片颜色渐变Bean * Vibrant (有活力) * Vibrant dark(有活力 暗色) * Vibrant light(有活力 亮色) * Muted (柔和) * Muted dark(柔和 暗色) * Muted light(柔和 亮色) */public class ColorInfo { private String imgUrl; private int vibrantColor = 0xFF999999; private int vibrantDarkColor = 0xFF999999; private int vibrantLightColor = 0xFF999999; private int mutedColor = 0xFF999999; private int mutedDarkColor = 0xFF999999; private int mutedLightColor = 0xFF999999;
public String getImgUrl() { return imgUrl; }
public void setImgUrl(String imgUrl) { this.imgUrl = imgUrl; }
public int getVibrantColor() { return vibrantColor; }
public void setVibrantColor(int vibrantColor) { this.vibrantColor = vibrantColor; }
public int getVibrantDarkColor() { return vibrantDarkColor; }
public void setVibrantDarkColor(int vibrantDarkColor) { this.vibrantDarkColor = vibrantDarkColor; }
public int getVibrantLightColor() { return vibrantLightColor; }
public void setVibrantLightColor(int vibrantLightColor) { this.vibrantLightColor = vibrantLightColor; }
public int getMutedColor() { return mutedColor; }
public void setMutedColor(int mutedColor) { this.mutedColor = mutedColor; }
public int getMutedDarkColor() { return mutedDarkColor; }
public void setMutedDarkColor(int mutedDarkColor) { this.mutedDarkColor = mutedDarkColor; }
public int getMutedLightColor() { return mutedLightColor; }
public void setMutedLightColor(int mutedLightColor) { this.mutedLightColor = mutedLightColor; }}


创建集合用来存放数据

//存放Banner背景颜色的集合var mColorList: ArrayList = ArrayList()


将Banner中的每一条数据都存储集合中,方便后续通过Palette进行取色。

  count = mBannerList.size        mColorList.clear()
for (i in 0..count + 1) { val info = ColorInfo() if (i == 0) { info.imgUrl = mBannerList.get(count - 1) } else if (i == count + 1) { info.imgUrl = mBannerList.get(0) } else { info.imgUrl = mBannerList.get(i - 1) } mColorList.add(info)        }


数据都创建完成后就可以创建Banner的图片加载器了~


4. 创建Banner图片加载器,并使用Palette获取Banner图片色值并进行保存

Palette取色方法:


取出来的值为RGB值

        //获取Palette 调色板        // 这里的bitmap就是需要取色的图片        val palette = Palette.from(bitmap).generate()        //充满活力的色调        val Vibrantrgb = palette.getVibrantSwatch()!!.rgb        //充满活力的亮色调        val LightVibrantrgb = palette.getLightVibrantSwatch()!!.rgb        //充满活力的暗色调        val DarkVibrantrgb = palette.getDarkVibrantSwatch()!!.rgb        //柔和的色调        val Mutedrgb = palette.getMutedSwatch()!!.rgb        //柔和的亮色调        val LightMutedrgb = palette.getLightMutedSwatch()!!.rgb        //柔和的暗色调        val DarkMutedrgb = palette.getDarkMutedSwatch()!!.rgb


创建BannerImageLoader类:

package com.lcz.coolweatherjetpack
import android.annotation.SuppressLintimport android.content.Contextimport android.graphics.Bitmapimport android.widget.ImageViewimport androidx.palette.graphics.Paletteimport com.bumptech.glide.Glideimport com.bumptech.glide.load.DataSourceimport com.bumptech.glide.load.engine.GlideExceptionimport com.bumptech.glide.load.resource.bitmap.RoundedCornersimport com.bumptech.glide.request.RequestListenerimport com.bumptech.glide.request.RequestOptionsimport com.bumptech.glide.request.target.Targetimport com.youth.banner.loader.ImageLoader
/** * 继承重写banner图片加载器 */class BannerImageLoader : ImageLoader {
//存放Banner数据和颜色的集合 var colorList: ArrayList = ArrayList()
constructor(colorList: ArrayList) : super() { this.colorList = colorList }
@SuppressLint("CheckResult") override fun displayImage(context: Context?, path: Any?, imageView: ImageView?) { if (path != null) { //设置Imageview的Pinging值 (美观) imageView!!.setPadding(30, 0, 30, 0);
Glide.with(context!!).asBitmap().load(path.toString()) //通过listener监听方法 将Banner中的每一张网络图片转换为Bitmap,并通过Bitmap进行取值 .listener(object : RequestListener { override fun onLoadFailed( e: GlideException?, model: Any?, target: Target?, isFirstResource: Boolean ): Boolean { return false }
override fun onResourceReady( resource: Bitmap?, model: Any?, target: Target?, dataSource: DataSource?, isFirstResource: Boolean ): Boolean { setColorList(resource!!, path.toString()) return false } //通过RequestOptions.bitmapTransform(RoundedCorners(20)) 设置图片为圆角 }).apply(RequestOptions.bitmapTransform(RoundedCorners(20))).into(imageView!!); } }
//将Banner中的每一张图片进行取值,并存放到ColorInfo类中 private fun setColorList(bitmap: Bitmap, imgUrl: String) { if (colorList == null) { return } //初始化Palette val palette = Palette.from(bitmap).generate() for (i in 0 until colorList.size) { if (colorList.get(i).getImgUrl().equals(imgUrl)) { // imgUrl作为识别标志 if (palette.getVibrantSwatch() != null) { //获取充满活力的色调 colorList.get(i).setVibrantColor(palette.getVibrantSwatch()!!.getRgb()) } if (palette.getDarkVibrantSwatch() != null) { colorList.get(i).setVibrantDarkColor(palette.getDarkVibrantSwatch()!!.getRgb()) } if (palette.getLightVibrantSwatch() != null) { colorList.get(i).setVibrantLightColor( palette.getLightVibrantSwatch()!!.getRgb() ) } if (palette.getMutedSwatch() != null) { colorList.get(i).setMutedColor(palette.getMutedSwatch()!!.getRgb()) } if (palette.getDarkMutedSwatch() != null) { colorList.get(i).setMutedDarkColor(palette.getDarkMutedSwatch()!!.getRgb()) } if (palette.getLightVibrantSwatch() != null) { colorList.get(i).setMutedLightColor(palette.getLightVibrantSwatch()!!.getRgb()) } } } }
/** * Vibrant (有活力) * Vibrant dark(有活力 暗色) * Vibrant light(有活力 亮色) * Muted (柔和) * Muted dark(柔和 暗色) * Muted light(柔和 亮色) */ fun getVibrantColor(position: Int): Int { return colorList[position].vibrantColor }
fun getVibrantDarkColor(position: Int): Int { return colorList[position].vibrantDarkColor }
fun getVibrantLightColor(position: Int): Int { return colorList[position].vibrantLightColor }
fun getMutedColor(position: Int): Int { return colorList[position].mutedColor }
fun getMutedDarkColor(position: Int): Int { return colorList[position].mutedDarkColor }
fun getMutedLightColor(position: Int): Int { return colorList[position].mutedLightColor }}


在加载器中将色值取出并存放到集合中,接下来就可以在Banner的每次滑动中把对应的色值配对到背景中了。


5. 监听Banner滑动,根据下标获取对应色值,将颜色配置到背景ImageView中。


通过Banner的setOnPageChangeListener进行监听


  • onPageScrolled:滚动中

  • onPageSelected:滚动选择中


在监听中使用通过ColorUtils 获取当前banner和下一个banner的色值。并将获取到的值配对到背景和状态栏中。

  var IsInit = true
private fun initView() { binding!!.viewBanner.setOnPageChangeListener(object : ViewPager.OnPageChangeListener { override fun onPageScrolled( position: Int, positionOffset: Float, positionOffsetPixels: Int ) { if (positionOffset > 1) { //会出现极个别大于1的数据 return } //修正position,解决两头颜色错乱,来自Banner控件源码 if (position === 0) { position == count } if (position > count) { position == 1 } if (count > 0) { val pos = (position + 1) % count //很关键 //通过ColorUtils 获取当前banner的Vibrant颜色值 val vibrantColor = ColorUtils.blendARGB( imageLoader.getVibrantColor(pos), imageLoader.getVibrantColor(pos + 1), positionOffset ) //给背景和状态栏都配置颜色 binding!!.viewBg.setBackgroundColor(vibrantColor)
} }
override fun onPageSelected(position: Int) { if (IsInit) { // 第一次,延时加载才能拿到颜色 IsInit = false Handler().postDelayed(Runnable { LogUtils.d("第一次加载") val vibrantColor: Int = imageLoader.getVibrantColor(1) binding!!.viewBg.setBackgroundColor(vibrantColor)
}, 500) } }
override fun onPageScrollStateChanged(state: Int) {
}
})
/** * 设置状态栏颜色 * * @param activity */ fun setStatusBarColor(activity: Activity, color: Int) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { val window: Window = activity.window //状态栏改变颜色。 window.setStatusBarColor(color) //状态栏改变颜色。 LogUtils.d("color:$color") }    }


6. 将加载器使用到Banner中。

 binding!!.viewBanner.setImageLoader(imageLoader)            //设置图片集合            .setImages(mBannerList)            //设置banner动画效果            // banner.setBannerAnimation(Transformer.DepthPage);            //设置轮播时间            .setDelayTime(3000)            //banner设置方法全部调用完毕时最后调用            .start()


3、总结


Banner轮播+背景渐变整体实现效果不难,重点在于通过Palette取色完成后,在滑动的监听中通过ColorUtils将数据转换并配对到背景中。


示例源码:

https://github.com/zt80hou/ColorfullBannerDemo


到这里就结束啦。

浏览 115
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报