Android系统中Launcher桌面图标简答来讲就是通过PackageManager获取对应APP的Icon即可,所获取的ICON就是简单地标准图标,对于Android来说,其标准的ICON为72*72简单桌面实现可以直接根据自身ICON标准,对该icon进行放大缩小后绘制即可。不过就目前来说,由于Android并未规定图标的标准样式,所以各家所制作的ICON各式各样,有的就是简单图标,有的是在方形背板基础上绘制ICON。所以各家桌面在自己绘制ICON时,都会对其增加背板,以统一各厂家APP图标,以标准的样式进行展示。如果背板是标准的,那问题也很好办,例如背板80*80的方形,图标缩放为72*72,直接绘制在(4,4)的位置即可。而随着各家桌面的不断进化,对图标绘制的要求也越来越高,各家允许使用自定义的背板,简单来说就是背板可以使方的、圆的、甚至是不规则的图形。这就使得ICON绘制时不能采用预定义配置的方式,需要根据背板的实际样式对ICON进行裁剪后绘制。简单来说就是按照背板的样式裁剪ICON,使ICON在背板中留出一定宽度的边沿后,在背板正中心位置进行绘制。

初拿到这个需求后,稍稍一考虑,很简单!从实现角度分析需求就是按照比背板小的边缘对ICON进行裁剪。分解来说就是:1.如何识别背板的边缘。2.如何进行裁剪。背板的边缘很好识别,通过getAlpha获取背板的Alpha即可。如何裁剪那,有点图像处理知识的就知道,只需要通过简单地4点采样,判断当前点是否需要切掉即可。说干就干,第一版的代码如下:

 /**//*背板留出5像素边*/private static final int EDGE_WIDTH = 5;/*alpha值的最低值,低于该值则认为是透明*/private static final int ALPHA_BLUR = 200;/*** 返回图标按背板裁剪后得Bitmap* @param background 背板的Bitmap* @param icon 图标的Bitmap* */public static Bitmap getBitmapWithNoScale(Drawable background, Bitmap icon){/*首先调整icon大小与背板一致,通过缩放或居中显示*/if(icon.getWidth() > background.getIntrinsicWidth()){icon = Bitmap.createScaledBitmap(icon, background.getIntrinsicWidth(), background.getIntrinsicHeight(), true);}if(icon.getWidth() < background.getIntrinsicWidth() ){Bitmap tmp = null;try {tmp = Bitmap.createBitmap(background.getIntrinsicWidth(), background.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);} catch (OutOfMemoryError e) {// 如果发生了OOM问题, 重新申请一次tmp = Bitmap.createBitmap(background.getIntrinsicWidth(), background.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);e.printStackTrace();}Canvas mCanvas = new Canvas(tmp);mCanvas.drawBitmap(icon,(background.getIntrinsicWidth()-icon.getWidth())/2,(background.getIntrinsicHeight()-icon.getHeight())/2, null);icon = tmp;}return getBitmapAlpha(background, icon);}private static ImageView mGarbage ;/*obj 背板,res 图标*/private static Bitmap getBitmapAlpha(Drawable backgroundDrawable, Bitmap icon){
//        Bitmap myAlpha = obj.extractAlpha();Bitmap background = ((BitmapDrawable)backgroundDrawable).getBitmap();Bitmap alpha2 = background.extractAlpha();int back_width = background.getWidth();int back_height = background.getHeight();int icon_width = icon.getWidth();int icon_height = icon.getHeight();int alpha_arr[] = new int[back_width*back_height];alpha2 = alpha2.copy(Config.ARGB_8888, true);alpha2.getPixels(alpha_arr, 0, back_width, 0, 0, back_width, back_height);int icon_arr[] = new int[icon_width*icon_height];icon.getPixels(icon_arr, 0, icon_width, 0, 0, icon_width, icon_height);int back_startx = 0, back_starty = 0, back_endx = 0, back_endy = 0;/*在图标比背板小的情况下,图标在背板中心位置,相对于背板的位置*/int icon_startx,icon_starty,icon_endx,icon_endy;int icon_offset = 0;if(icon_width < back_width){/*图标比较小哈,将其居中显示裁剪*/Log.e("pluszhang","get icon smaller");back_startx = EDGE_WIDTH;back_endx = back_width-EDGE_WIDTH-1;back_starty = EDGE_WIDTH;back_endy = back_height-EDGE_WIDTH-1;icon_offset = back_width-icon_width > EDGE_WIDTH*2?0:EDGE_WIDTH-(back_width-icon_width)/2;}else if(icon_width == back_width){/*直接裁剪即可*/back_startx = EDGE_WIDTH;back_endx = back_width-EDGE_WIDTH-1;back_starty = EDGE_WIDTH;back_endy = back_height-EDGE_WIDTH-1;}for(int i=0; i<icon_height;i++){for(int j=0; j<icon_width;j++){if(i<back_starty||i>back_endy||j<back_startx||j>back_endx){icon_arr[i*icon_width+j] = 0;}else{if((alpha_arr[(i-EDGE_WIDTH)*back_width+j] >> 24 &0xff) < ALPHA_BLUR ||(alpha_arr[(i+EDGE_WIDTH)*back_width+j]  >> 24&0xff)< ALPHA_BLUR ||(alpha_arr[(j-EDGE_WIDTH)+i*back_width]  >> 24&0xff)< ALPHA_BLUR ||(alpha_arr[(j+EDGE_WIDTH)+i*back_width]  >> 24&0xff)< ALPHA_BLUR){icon_arr[i*icon_width+j] = 0;} }}}mGarbage.setBackgroundDrawable(backgroundDrawable);   mGarbage.setImageBitmap(Bitmap.createBitmap(icon_arr, icon_width, icon_height, Config.ARGB_8888));return mGarbage.getDrawingCache();}

以上这段代码是采用切的方法实现对图标处理方法,主要来讲就是首先进行标准化,将ICON与背板处理到相同大小,只缩不放大,防止ICON变形,通过背板的Alpha视图,采样绘制ICON,最终实现对ICON的绘制。通过对上述代码分析,由于对图标采用的是扫描方式进行处理,也就是说80X80的图标,要计算6400次,一个图标还好,要是有2,3百个图标,效率确实有些低。关键是效果不太好,由于该方法采用的是采样的方式,对于背板特别不规则的会导致图标边缘切割有许多毛刺,这个问题是该算法自身的问题,采用切的算法,不会有更好的效果,这是该算法本身决定的,如果要达到最优效果,只有更换算法换一种思路。

既然用切的方法不好,就只能更换一种思路,通过对Canvas,Paint等绘制类的仔细分析,发现另外一种方法,缩,简单来说就是把图标先按照背板边缘绘制,之后对图标进行缩小后,绘制到背板上。利用Canvas,Paint的简单组合,很容易实现图标按背板边缘的绘制,这里及一定要介绍Paint的setXfermode方法,该方法就是根据Canvas背板图片与绘制图片的分层及相与、或关系,绘制不同的部分。具体模式对应关系如下:

需要注意的是dst与src的关系,Canvas上原有的Bitmap是dst,而后绘制的Bitmap为src通过不同的Paint可以取得不同的二者剪切、层叠效果。我们简单实用剪切覆盖效果就可以,也就是mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));

跨过这个坎后,就是最后需要注意的就是,先缩后缩的问题了,就是在使用ICON按背板裁剪后,缩小,会对ICON进行压缩,导致内部有毛边,效果不好,采用缩的思路继续向下走,进一步分析各步骤,发现先对背板进行缩放,后对ICON按照缩小后的背板进行裁剪,合成,这样既使用的算法的优势,又避免了后期进行ICON缩放的弊端。废话不多说,代码奉上:

    public static void init(Context context) {mCanvas = new Canvas();mPaint = new Paint();mPaint.setFilterBitmap(false);mPaint.setAntiAlias(true);mPaint.setDither(true);mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));}/**//* 背板留出5像素边 */private static final int EDGE_WIDTH = 5;/* alpha值的最低值,低于该值则认为是透明 */private static final int ALPHA_BLUR = 200;/*** 返回图标按背板裁剪后得Bitmap* * @param background*            背板的Bitmap* @param icon*            图标的Bitmap* */public static Bitmap getBitmapWithNoScale(Drawable background, Bitmap icon){Bitmap background_bit = ((BitmapDrawable)background).getBitmap();background_bit = background_bit.copy(Bitmap.Config.ARGB_8888,true);Bitmap copy = background_bit.createScaledBitmap(background_bit, background_bit.getWidth()-EDGE_WIDTH*2, background_bit.getHeight()-EDGE_WIDTH*2, true);if(icon.getWidth() < background_bit.getWidth() ){Bitmap tmp = null;try {tmp = Bitmap.createBitmap(background_bit.getWidth(), background_bit.getHeight(), Bitmap.Config.ARGB_8888);} catch (OutOfMemoryError e) {// 如果发生了OOM问题, 重新申请一次tmp = Bitmap.createBitmap(background_bit.getWidth(), background_bit.getHeight(), Bitmap.Config.ARGB_8888);e.printStackTrace();}Canvas mCanvas = new Canvas(tmp);mCanvas.drawBitmap(icon,(background_bit.getWidth()-icon.getWidth())/2,(background_bit.getHeight()-icon.getHeight())/2, null);icon = tmp;}else{if(icon.getWidth() > background.getIntrinsicWidth()){icon = Bitmap.createScaledBitmap(icon, background.getIntrinsicWidth(), background.getIntrinsicHeight(),true);}else{icon = icon.copy(Config.ARGB_8888, true);}}mCanvas.setBitmap(icon);mCanvas.drawBitmap(copy, EDGE_WIDTH, EDGE_WIDTH, mPaint);mCanvas.setBitmap(null);icon = icon.createBitmap(icon, EDGE_WIDTH, EDGE_WIDTH, background_bit.getWidth()-EDGE_WIDTH*2, background_bit.getWidth()-EDGE_WIDTH*2);mCanvas.setBitmap(background_bit);mCanvas.drawBitmap(icon, EDGE_WIDTH,EDGE_WIDTH,null);mCanvas.setBitmap(null);return background_bit;        }

——欢迎转载,请注明出处http://blog.csdn.net/zyplus——

Android ICON生成及优化相关推荐

  1. 【Android 安装包优化】Android 中使用 SVG 图片 ( SVG 矢量图简介 | Android 中生成 Vector 矢量图资源 )

    文章目录 一.SVG 矢量图简介 二.Android 中生成 Vector 矢量图资源 三.参考资料 一.SVG 矢量图简介 Android SVG 参考文档 : https://developer. ...

  2. 转:Android应用开发性能优化完全分析

    转自:http://blog.csdn.net/yanbober/article/details/48394201 1 背景 其实有点不想写这篇文章的,但是又想写,有些矛盾.不想写的原因是随便上网一搜 ...

  3. Android布局原理与优化

    Android布局原理与优化 目录: 绘制原理 CPU与GPU Android 图形系统的整体架构 RenderThread 硬件加速和软件绘制 invalidate软件绘制流程 invalidate ...

  4. Android应用开发性能优化完全分析

    1 背景 其实有点不想写这篇文章的,但是又想写,有些矛盾.不想写的原因是随便上网一搜一堆关于性能的建议,感觉大家你一总结.我一总结的都说到了很多优化注意事项,但是看过这些文章后大多数存在一个问题就是只 ...

  5. application中 android:icon 和 android:roundIcon 的区别

    8.0系统的应用图标适配 为什么要进行应用图标适配? 可能有些朋友觉得困惑,应用图标这种东西从Android远古时代就已经有了,而且功能格外的简单,就是放张图片而已,这有什么好适配的呢?但实际上,在当 ...

  6. 技术|Android安装包极限优化

    技术|Android安装包极限优化 版权声明  1.本文版权归原作者所有,转载需注明作者信息及原文出处.  2.本文作者:赵裕(vimezhao),永久链接:https://github.com/vi ...

  7. android生成apk流程,Android Studio生成APK的基本流程

    Android Studio生成APK的基本流程 2020年08月14日 | 萬仟网移动技术 | 我要评论 Android Studio生成APK流程修改版本号和文件名安全加固(可选)生成签名apk修 ...

  8. Android应用程序性能优化

    1 背景 其实有点不想写这篇文章的,但是又想写,有些矛盾.不想写的原因是随便上网一搜一堆关于性能的建议,感觉大家你一总结.我一总结的都说到了很多优化注意事项,但是看过这些文章后大多数存在一个问题就是只 ...

  9. Android ART模式预优化那些事

    Android预优化那些事 Preopt ART Dalvik APK的预优化原理和作用 Android预优化那些事 1.什么是Android预优化 2.Android预优化的原理 3.Android ...

  10. Android一键生成包含.dex的Jar及动态加载方案

    Android一键生成包含.dex的Jar及动态加载方案 背景:谈到动态加载相信很多小伙伴都会想到 热更新 及 动态加载dex 的技术,最近也因为项目重构的需求,折腾了下这方面的技术点,以前研究过但时 ...

最新文章

  1. splay + 线段树 ---- P3765总统选举 [带修改的动态区间众数 摩尔投票+n棵splay]
  2. php怎么根据接口文档实现功能,CodeIgniter+swagger实现 PHP API接口文档自动生成功能...
  3. Light OJ 1078
  4. 操作Zookeeper
  5. vue3-antd-admin开源学习-后台管理框架
  6. kvm实战之搭建一个web服务来进行ks.cfg文件的引导(三)
  7. ifconfig eth0网卡配置
  8. CORDIC算法 arctan反正切计算原理及C语言定点实现
  9. 怎样保留应届生身份?应届生的身份有多重要?
  10. 敏捷开发“松结对编程”系列之十五:L型代码结构(编程篇之一)
  11. c语言二级指针与二维数组
  12. wagon-maven-plugin插件实现自动化构建部署到服务器
  13. python太极代码_Python : Turtle绘图-太极图(代码)
  14. 在Windows10中对于文件做MD5校验
  15. 英语听力,口语常见的三个简读/略读/变读
  16. Mac干货 如何快速的在Mac上安装Windows双系统?虚拟机Parallels Desktop +Bootcamp安装
  17. Linux MySQL数据库冷迁移采坑记录
  18. GIS BigBook1 —— 《地理信息系统与科学》
  19. 一个自学网络安全攻防的弱鸟简单描述下关于压力测试如何实现的
  20. 电脑组装的配件及其功能

热门文章

  1. 计算机学院毕业语录,毕业的句子简单到哭的_毕业语录
  2. (附源码)计算机毕业设计SSM音乐鉴赏网站前端开发
  3. Xcode 建立 UIKit 项目(Hello World)
  4. Python遥感开发之GDAL读写遥感影像
  5. SPIR-V 研究:编译器基本原理(一)
  6. QQ昵称修改颜色,彩色昵称太酷了
  7. android 7.1 开机速度优化记录
  8. Hystrix学习——(2)雪崩效应
  9. VS2017--无法添加引用--提示“未能完成操作。不支持此接口”
  10. Flutter 项目实战 网络请求MD5+时间戳+验证签名 十一