app首页 Banner轮播图取色,背景和状态栏颜色渐变
目前购物推荐banner轮播和读书、听书类等App都会有此种效果
效果可以增加关注点和界面UI的统一性,体验比较舒服
效果图(截自喜马拉雅小说Tab
板块)如下:
最后实现的效果:
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文件
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
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" />
<com.youth.banner.Banner
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" />
</RelativeLayout>
这里ImageVIew使用的图片如下(透明背景):
-
下载后创建drawable-xxhdpi文件夹并放入图片
3. 创建数据
//Banner数据的集合
var mBannerList: ArrayList<String> = 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<ColorInfo> = 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.SuppressLint
import android.content.Context
import android.graphics.Bitmap
import android.widget.ImageView
import androidx.palette.graphics.Palette
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.request.target.Target
import com.youth.banner.loader.ImageLoader
/**
* 继承重写banner图片加载器
*/
class BannerImageLoader : ImageLoader {
//存放Banner数据和颜色的集合
var colorList: ArrayList<ColorInfo> = ArrayList()
constructor(colorList: ArrayList<ColorInfo>) : 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<Bitmap> {
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<Bitmap>?,
isFirstResource: Boolean
): Boolean {
return false
}
override fun onResourceReady(
resource: Bitmap?,
model: Any?,
target: Target<Bitmap>?,
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将数据转换并配对到背景中。