Android ICON產生及最佳化

來源:互聯網
上載者:User

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——

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.