最近項目打板了,板子跑起來后發現Launcher的所有程序界面不能全屏(兩邊有黑框,只在中上部顯示),但是主界面看上去是全屏顯示的(后面證實也非全屏顯示。)
我們的屏是21寸的,分辨率為1980*1080。
最開始以為是uboot里的屏幕參數沒設置好,后面check之后發現沒問題。沒辦法,只有去看Launcher的代碼。
首先,在我最開始就有一個誤解,這個誤解浪費我很多時間。由於最開始的時候主界面(也就是workspace)是沒有黑框的,所以我一直認為workspace的代碼是沒問題的。
后面經驗證主界面也沒有按屏幕的實際分辨率顯示!Workspace.java中構造函數有如下代碼:
1 final float smallestScreenDim = res.getConfiguration().smallestScreenWidthDp; 2 cellCountX = 1; 3 while (CellLayout.widthInPortrait(res, cellCountX + 1) <= smallestScreenDim) { 4 5 cellCountX++; 6 } 7 8 cellCountY = 1; 9 while (actionBarHeight + CellLayout.heightInLandscape(res, cellCountY + 1) 10 <= smallestScreenDim - systemBarHeight) { 11 cellCountY++; 12 } 13 }
smallestScreenDim 按字面理解意思應該是屏幕寬度的最小值(以DP為單位),cellCountX初始化為1,然后通過一個while循環去計算X、Y方向各能放多少個應用。
我們看看widthInPortrait方法:
1 static int widthInPortrait(Resources r, int numCells) { 2 // We use this method from Workspace to figure out how many rows/columns Launcher should 3 // have. We ignore the left/right padding on CellLayout because it turns out in our design 4 // the padding extends outside the visible screen size, but it looked fine anyway. 5 int cellWidth = r.getDimensionPixelSize(R.dimen.workspace_cell_width); 6 int minGap = Math.min(r.getDimensionPixelSize(R.dimen.workspace_width_gap), 7 r.getDimensionPixelSize(R.dimen.workspace_height_gap)); 8 return minGap * (numCells - 1) + cellHeight * numCells; 9 }
getDimensionPixelSize方法實際上是把dimens.xml中設置的cellWidth大小由dp轉換成px!
widthInPortrait計算后的返回值會與smallestScreenDim進行比較,如果比smallestScreenDim 小,那么說明能夠再放一個APP,cellCount進行加一。
循環比較之后就會得出在該屏幕上能放多少行,多少列個應用。
既然cellWidth的單位為px,那與通過他計算后得到的值進行比較的smallestScreenDim單位應該也是px,而不是像他字面所說的dp!
通過加log進一步確認,我發現android4.0默認的smallestScreenDim為720!也就是720px,而我的屏實際像素寬度為1920!
將smallestScreenDim強制設置為1920后all apps界面能全屏了,主界面的workspace也大了很多!說明之前主界面的全屏都是假象。。。
我們可以在代碼里得到屏幕的寬度,然后賦值給smallestScreenDim以便於支持更多的屏幕。 至於之前的主界面為什么沒有黑色的邊框,我估計是壁紙設置的原因,具體細節沒去深究了。
后面發現系統默認的圖標在大屏幕上顯示效果不太好,有點偏小,直接修改res/values-sw600dp/dimens.xml中的app_icon_size。
改完make之后發現圖標並沒有變大。。。
跟蹤代碼Launcher.java[onCreate]--->[setLauncher]--->LauncherApplication[onCreate]--->[new LauncherModel]--->[createIconBitmap]
1 static Bitmap createIconBitmap(Drawable icon, Context context) { 2 synchronized (sCanvas) { // we share the statics :-( 3 if (sIconWidth == -1) { 4 initStatics(context); 5 } 6 7 int width = sIconWidth; 8 int height = sIconHeight; 9 10 Log.i("Info","In createIconBitmap width is: "+width); 11 Log.i("Info","In createIconBitmap height is: "+height); 12 if (icon instanceof PaintDrawable) { 13 Log.i("Info","Icon type is PaintDrawable" ); 14 PaintDrawable painter = (PaintDrawable) icon; 15 painter.setIntrinsicWidth(width); 16 painter.setIntrinsicHeight(height); 17 } else if (icon instanceof BitmapDrawable) { 18 // Ensure the bitmap has a density. 19 Log.i("Info","Icon type is BitmapDrawable" ); 20 BitmapDrawable bitmapDrawable = (BitmapDrawable) icon; 21 Bitmap bitmap = bitmapDrawable.getBitmap(); 22 if (bitmap.getDensity() == Bitmap.DENSITY_NONE) { 23 bitmapDrawable.setTargetDensity(context.getResources().getDisplayMetrics()); 24 } 25 } 26 int sourceWidth = icon.getIntrinsicWidth(); 27 int sourceHeight = icon.getIntrinsicHeight(); 28 Log.i("Info","IntrinsicWidth is: "+sourceWidth); 29 Log.i("Info","IntrinsicHeight is: "+sourceHeight); 30 if (sourceWidth > 0 && sourceHeight > 0) { 31 // There are intrinsic sizes. 32 if (width < sourceWidth || height < sourceHeight) { 33 // It's too big, scale it down. 34 final float ratio = (float) sourceWidth / sourceHeight; 35 if (sourceWidth > sourceHeight) { 36 height = (int) (width / ratio); 37 } else if (sourceHeight > sourceWidth) { 38 width = (int) (height * ratio); 39 } 40 } else if (sourceWidth < width && sourceHeight < height) { 41 // Don't scale up the icon 42 //width = sourceWidth; 43 //height = sourceHeight; 44 width = sIconWidth; 45 height = sIconHeight; 46 } 47 } 48 49 // no intrinsic size --> use default size 50 int textureWidth = sIconTextureWidth; 51 int textureHeight = sIconTextureHeight; 52 Log.i("Info","textureWidth is: "+textureWidth); 53 Log.i("Info","textureHeight is: "+textureHeight); 54 55 final Bitmap bitmap = Bitmap.createBitmap(textureWidth, textureHeight, 56 Bitmap.Config.ARGB_8888); 57 final Canvas canvas = sCanvas; 58 canvas.setBitmap(bitmap); 59 60 final int left = (textureWidth-width) / 2; 61 final int top = (textureHeight-height) / 2; 62 63 if (false) { 64 // draw a big box for the icon for debugging 65 canvas.drawColor(sColors[sColorIndex]); 66 if (++sColorIndex >= sColors.length) sColorIndex = 0; 67 Paint debugPaint = new Paint(); 68 debugPaint.setColor(0xffcccc00); 69 canvas.drawRect(left, top, left+width, top+height, debugPaint); 70 } 71 72 sOldBounds.set(icon.getBounds()); 73 icon.setBounds(left, top, left+width, top+height); 74 icon.draw(canvas); 75 icon.setBounds(sOldBounds); 76 canvas.setBitmap(null); 77 78 return bitmap; 79 } 80 } 81 private static void initStatics(Context context) { 82 final Resources resources = context.getResources(); 83 final DisplayMetrics metrics = resources.getDisplayMetrics(); 84 final float density = metrics.density; 85 86 //default is 72*density 87 sIconWidth = sIconHeight = (int) resources.getDimension(R.dimen.app_icon_size); 88 sIconTextureWidth = sIconTextureHeight = sIconWidth; 89 90 sBlurPaint.setMaskFilter(new BlurMaskFilter(5 * density, BlurMaskFilter.Blur.NORMAL)); 91 sGlowColorPressedPaint.setColor(0xffffc300); 92 sGlowColorPressedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30)); 93 sGlowColorFocusedPaint.setColor(0xffff8e00); 94 sGlowColorFocusedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30)); 95 96 ColorMatrix cm = new ColorMatrix(); 97 cm.setSaturation(0.2f); 98 sDisabledPaint.setColorFilter(new ColorMatrixColorFilter(cm)); 99 sDisabledPaint.setAlpha(0x88); 100 }
經過分析,發現在這個方法里對圖片大小進行了判斷,如果大於默認的圖片大小96dp,那么強制將圖片大小設置為96dp!
稍作修改圖標就能放大了,細節不說了,大家看看代碼就知道了。