Android之佈局(layout)轉化成圖片(bitmap)
以前和IOS同事討論過怎麼截圖的操作,當時也不明白,怎麼可能將列表截圖呢?畢竟列表可以上下滑動呀!
最近有個需求,原生布局的介面,生成一個體檢報告,我知道這個介面用H5做是可以生成pdf列印的。但已經使用原生做了,並且印表機可以列印bitmap轉的byte陣列檔案。在此記錄:佈局轉圖片。
佈局檔案沒有超出螢幕高度:
private Bitmap getViewBitmap(View v) { v.clearFocus(); v.setPressed(false); boolean willNotCache = v.willNotCacheDrawing(); v.setWillNotCacheDrawing(false); int color = v.getDrawingCacheBackgroundColor(); v.setDrawingCacheBackgroundColor(0); if (color != 0) { v.destroyDrawingCache(); } v.buildDrawingCache(); Bitmap cacheBitmap = v.getDrawingCache(); if (cacheBitmap == null) { return null; } Bitmap bitmap = Bitmap.createBitmap(cacheBitmap); v.destroyDrawingCache(); v.setWillNotCacheDrawing(willNotCache); v.setDrawingCacheBackgroundColor(color); return bitmap; }
佈局超出了螢幕的高度(Scrollview處理):
public static Bitmap getBitmapByView(ScrollView scrollView) { int h = 0; Bitmap bitmap = null; for (int i = 0; i < scrollView.getChildCount(); i++) { h += scrollView.getChildAt(i).getHeight(); } bitmap = Bitmap.createBitmap(scrollView.getWidth(), h, Bitmap.Config.RGB_565); final Canvas canvas = new Canvas(bitmap); scrollView.draw(canvas); return bitmap; }
以上兩種方法則可以滿足layout生成bitmap,然後bitmap可以再生成圖片:
public static void savePhotoToSDCard(Bitmap photoBitmap, String path, String photoName) { if (checkSDCardAvailable()) { File dir = new File(path); if (!dir.exists()) { dir.mkdirs(); } File photoFile = new File(path, photoName + ".png"); FileOutputStream fileOutputStream = null; try { fileOutputStream = new FileOutputStream(photoFile); if (photoBitmap != null) { if (photoBitmap.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream)) { fileOutputStream.flush(); } } } catch (FileNotFoundException e) { photoFile.delete(); e.printStackTrace(); } catch (IOException e) { photoFile.delete(); e.printStackTrace(); } finally { try { fileOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } //檢查是否有SD卡 public static boolean checkSDCardAvailable() { return android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED); }
使用方法:
//contentLly是佈局檔案 Bitmap bitmap = getBitmapByView(contentLly); ImageUtils.savePhotoToSDCard(bitmap, "/sdcard/file", "img");
按照指定的寬高(或指定比例)來重新設定bitmap
//把傳進來的bitmap物件轉換為寬度為x,長度為y的bitmap物件 public static Bitmaptransform(Bitmap b, float x, float y) { int w = b.getWidth(); int h = b.getHeight(); float sx = (float) x / w; float sy = (float) y / h; Matrix matrix = new Matrix(); // 也可以按兩者之間最大的比例來設定放大比例,這樣不會是圖片壓縮 // float bigerS = Math.max(sx, sy); // matrix.postScale(bigerS, bigerS); // 長和寬放大縮小的比例 matrix.postScale(sx, sy); Bitmap resizeBmp = Bitmap.createBitmap(b, 0, 0, w, h, matrix, true); return resizeBmp; }
對於沒有在螢幕上顯示的控制元件獲取bitmap
//然後View和其內部的子View都具有了實際大小,也就是完成了佈局,相當與新增到了介面上。接著就可以建立點陣圖並在上面繪製了: private void layoutView(View v) { DisplayMetrics metric = new DisplayMetrics(); mActivity.getWindowManager().getDefaultDisplay().getMetrics(metric); int width = metric.widthPixels;// 螢幕寬度(畫素) int height = metric.heightPixels;// 螢幕高度(畫素) // 整個View的大小 引數是左上角 和右下角的座標 v.layout(0, 0, width, height); int measuredWidth = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY); int measuredHeight = View.MeasureSpec.makeMeasureSpec(10000, View.MeasureSpec.AT_MOST); /** 當然,measure完後,並不會實際改變View的尺寸,需要呼叫View.layout方法去進行佈局。 * 按示例呼叫layout函式後,View的大小將會變成你想要設定成的大小。 */ v.measure(measuredWidth, measuredHeight); v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight()); } private Bitmap loadBitmapFromView(View v) { int w = v.getWidth(); int h = v.getHeight(); Bitmap bmp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(bmp); c.drawColor(Color.WHITE); /** 如果不設定canvas畫布為白色,則生成透明 */ v.layout(0, 0, w, h); v.draw(c); return bmp; }
使用方法:
//相當與新增到了介面上 layoutView(contentLly); //獲取bitmap資料 loadBitmapFromView(contentLly);
免費獲取安卓開發架構的資料(包括Fultter、高階UI、效能優化、架構師課程、 NDK、Kotlin、混合式開發(ReactNative+Weex)和一線網際網路公司關於android面試的題目彙總可以加:936332305 / 連結:點選連結加入【安卓開發架構】: https://jq.qq.com/?_wv=1027&k=515xp64

image