找回密码
 立即注册
首页 业界区 安全 屏保多DHU下同步字体颜色

屏保多DHU下同步字体颜色

涣爹卮 2025-6-27 16:28:55
需求:不同DHU多屏场景下,设置同一系列屏保,屏保中间组件字体颜色需要动态读取背后壁纸主色亮度,根据背后亮度动态设置字体颜色
偏亮的=黑色,偏暗的=白色
1、取色
读取亮度需要先对bitmap解码,通过 Color.colorToHSV 方法读取亮度值
1.gif
2.gif
  1. private fun generate(newMap: Bitmap): FloatArray {
  2.         val hsvColorArray = FloatArray(3)
  3.         Palette.from(newMap).generate().apply {
  4.             val dominantColor = getDominantColor(Color.BLACK)
  5.             Color.colorToHSV(dominantColor, hsvColorArray)
  6.         }
  7.         return hsvColorArray
  8.     }
复制代码
View Code随后直接根据亮度值返回对应颜色
3.gif
4.gif
  1. // hsvColorArray[2]
  2. private fun getColor(num: Float = 0f) = if (num >= 0.7) {
  3.         CommonUtils.COLOR_BLACK
  4.     } else {
  5.         CommonUtils.COLOR_WHITE
  6.     }
复制代码
View Code2、裁剪
取色的bitmap是字体背后对应的区域,而不是整个壁纸,所以需要进行计算裁剪
5.gif
6.gif
  1. private fun createRectBitmap(bitmap: Bitmap, isDim: Boolean): Bitmap {
  2.         return if (isDim) {
  3.             Bitmap.createBitmap(
  4.                 bitmap,
  5.                 dimWidth / 2 - rectWidth / 2, dimHeight / 2 - rectHeight / 2,
  6.                 rectWidth, rectHeight
  7.             )
  8.         } else {
  9.             Bitmap.createBitmap(
  10.                 bitmap, mWidth / 2 - rectWidth / 2, rectTopMargin, rectWidth, rectHeight
  11.             )
  12.         }
  13.     }
复制代码
View Code不同屏幕尺寸不一样,布局不一样,所以对应要裁剪的区域也不一样,这里需要统一适配
bitmap建议使用 Glide 加载,效果更高
对bitmap进行裁剪取色都属于耗时操作,需要放在子线程处理,缓存使用map存放,key使用屏幕的displayId
3、预加载
每个系列好几张图片,每个DHU可能有多个屏幕(比如CSD屏存在主副驾屏),加上DIM屏属于QNX系统,不太方便实现该功能,所以也需要CSD去实现同步
基于上面要求,缓存量很大,所以需要在初始化时使用多线程处理
7.gif
8.gif
  1. object ColorPickManager {
  2.     private const val TAG = "ColorPickManager"
  3.     private val suitMap = hashMapOf<Int, MutableList<String>>()
  4.     private val suitIdObserver = Observer<Int> {
  5.         loadSuitData(it)
  6.     }
  7.     @JvmStatic
  8.     fun init() {
  9.         Log.d(TAG, "$TAG init ${VehicleManager.getVehicleType()}")
  10.         initSuitData()
  11.         LocalResourceManager.observeUsageSuitId(suitIdObserver)
  12.     }
  13.     private fun initSuitData() {
  14.         val list = mutableListOf<DisplayParameter>()
  15.         if (VehicleManager.isA()) {
  16.             list.add(DisplayParameter.DISPLAY_PSD)
  17.             list.add(DisplayParameter.DISPLAY_CSD)
  18.             list.add(DisplayParameter.DISPLAY_TV)
  19.             list.add(DisplayParameter.DISPLAY_DIM)
  20.         } else if (VehicleManager.isB()) {
  21.             list.add(DisplayParameter.DISPLAY_CONSOLE)
  22.             list.add(DisplayParameter.DISPLAY_CSD)
  23.             list.add(DisplayParameter.DISPLAY_TV)
  24.             list.add(DisplayParameter.DISPLAY_DIM)
  25.         } else {
  26.             Log.w(TAG, "initSuitData 不支持的车型 ${VehicleManager.getVehicleType()}")
  27.         }
  28.         list.forEach {
  29.             Log.d(TAG, "initSuitData ${it.displayName} suitMap[${it.displayId}]")
  30.             suitMap[it.displayId] = mutableListOf()
  31.         }
  32.     }
  33.     /** 当前屏保套系 */
  34.     private fun loadSuitData(suitId: Int) {
  35.         Log.d(TAG, "loadSuitData suitId=$suitId")
  36.         MainScope().launch(Dispatchers.IO) {
  37.             LocalResourceManager.getSuitsWithPicturesById(suitId)?.apply {
  38.                 Log.d(TAG, "loadSuitData suitMapSize=${suitMap.size}")
  39.                 suitMap.keys.forEach { addCacheData(it, this) }
  40.             }
  41.         }
  42.     }
  43.     private fun addCacheData(displayId: Int, suitsWithPictures: SuitWithPictures) {
  44.         val suit = suitsWithPictures.suit
  45.         val pictures = suitsWithPictures.pictures
  46.         suitMap[displayId]?.clear()
  47.         val pathList = mutableListOf<String>()
  48.         if (ResourceLoadManager.isDynamic(suit.type)) {
  49.             pathList.add(suit.path)
  50.         } else if (ResourceLoadManager.TYPE_CUSTOM != suit.type) {
  51.             pictures.forEach { pathList.add(convertPath(displayId, it.path)) }
  52.         } else {
  53.             pictures.forEach {
  54.                 val path = when (displayId) {
  55.                     DisplayParameter.DISPLAY_TV.displayId -> {
  56.                         ResourceLoadManager.convertPath2Tv(it.path)
  57.                     }
  58.                     DisplayParameter.DISPLAY_PSD.displayId -> {
  59.                         ResourceLoadManager.convertPath2Psd(it.path)
  60.                     }
  61.                     else -> ResourceLoadManager.convertPath2Csd(it.path)
  62.                 }
  63.                 pathList.add(convertPath(displayId, path))
  64.             }
  65.         }
  66.         pathList.forEach {
  67.             Log.d(TAG, "addCacheData suitMap[$displayId] add $it")
  68.         }
  69.         suitMap[displayId]?.addAll(pathList)
  70.         loadScreensaversFontColorData(displayId)
  71.         loadAmbientLightData(displayId)
  72.     }
  73.     private fun convertPath(displayId: Int, path: String): String {
  74.         return if (displayId == DisplayParameter.DISPLAY_DIM.displayId) {
  75.             ResourceLoadManager.convertPath2Dim(path)
  76.         } else path
  77.     }
  78.     @JvmStatic
  79.     fun syncScreensaversColor(displayId: Int, index: Int) {
  80.         AmbientLightColorPickManager.setAmbientLight(displayId, index)
  81.         FontColorPickManager.syncScreensaversFontColor(displayId, index)
  82.     }
  83.     private fun loadScreensaversFontColorData(displayId: Int) {
  84.         val list = suitMap[displayId]
  85.         if (list.isNullOrEmpty()) {
  86.             Log.w(TAG, "loadScreensaversFontColorData suitMap[$displayId] value is null")
  87.             return
  88.         }
  89.         FontColorPickManager.loadScreensaversFontColorData(displayId, list)
  90.     }
  91. }
复制代码
View Code针对不同车型缓存对应屏幕,监听屏保变化,如果中途切换需要动态更新
4、同步
缓存处理好后,屏保通过计时器轮播,每次轮播从缓存中读取对应的颜色值同步到字体颜色,实现字体动态跟随屏保壁纸切换
5、多屏适配
不同屏幕尺寸不一样,动态获取背后矩形区域不利于提前缓存处理,因为需要布局加载完后才能拿到坐标宽高,而等进入屏保后在获取会导致字体默认显示颜色跟实际取色不一致,进入屏保导致字体颜色切换过程,如果提前缓存便没有这个过程
实现方案:拿到bitmap后拉伸到基准宽高(设计稿给的宽高),然后参考设计稿裁剪矩形区域,这样无论什么尺寸的屏幕,裁剪的区域都一样,颜色也一样,同步屏保时就可以保证没有偏差
优化:图片过大导致内存占比耗时过高等,将所有基准降低三倍处理(不能太低,否则主色会有偏差,导致颜色不对)
9.png

6、多屏预览
预览页要求可以预览所有屏幕的屏保,也包含组件字体颜色的预览,并且主副驾屏幕可以同时进入详情(同一个DHU)
10.png

11.png

字体会自动跟随壁纸亮度切换颜色
 

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册