app首页 Banner轮播图取色,背景和状态栏颜色渐变

app首页 Banner轮播图取色,背景和状态栏颜色渐变
目前购物推荐banner轮播和读书、听书类等App都会有此种效果
效果可以增加关注点和界面UI的统一性,体验比较舒服

效果图(截自喜马拉雅小说Tab板块)如下:

ximalaya_notes_tab_palette_color.jpg

最后实现的效果:

img_palette_shop_banner_a.png
img_palette_shop_banner_b.png
img_palette_shop_banner_c.png
img_palette_shop_banner_d.png
img_palette_shop_banner_e.png

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文件夹并放入图片

    image

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将数据转换并配对到背景中。

  • 示例Demo

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

推荐阅读更多精彩内容