Android實現將View轉化為圖片並儲存到本地
阿新 • • 發佈:2019-01-30
一、概述
app中有需求需要將View轉化為圖片並儲存到本地,這裡分兩種情況:
1.View本身已經顯示在介面上
2.View還沒有新增到介面上或者沒有顯示(繪製)過
二、實現方法
對於上述的第一種情況我使用下面程式碼即可:
private void viewSaveToImage(View view) { view.setDrawingCacheEnabled(true); view.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH); view.setDrawingCacheBackgroundColor(Color.WHITE); // 把一個View轉換成圖片 Bitmap cachebmp = loadBitmapFromView(view); FileOutputStream fos; String imagePath = ""; try { // 判斷手機裝置是否有SD卡 boolean isHasSDCard = Environment.getExternalStorageState().equals( android.os.Environment.MEDIA_MOUNTED); if (isHasSDCard) { // SD卡根目錄 File sdRoot = Environment.getExternalStorageDirectory(); File file = new File(sdRoot, Calendar.getInstance().getTimeInMillis()+".png"); fos = new FileOutputStream(file); imagePath = file.getAbsolutePath(); } else throw new Exception("建立檔案失敗!"); cachebmp.compress(Bitmap.CompressFormat.PNG, 90, fos); fos.flush(); fos.close(); } catch (Exception e) { e.printStackTrace(); } LogUtil.e("imagePath="+imagePath); view.destroyDrawingCache(); } 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; }
也可以按下面做:
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);
}
用例:
Bitmap bitmap = getBitmapByView(contentLly);//contentLly是佈局檔案
ImageUtils.savePhotoToSDCard(bitmap, "/sdcard/test", "test");
如果是第二種,還這樣使用的話,就會報錯了,因為View在新增到容器中之前並沒有得到實際的大小,所以首先需要指定View的大小:
DisplayMetrics metric = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metric);
int width = metric.widthPixels; // 螢幕寬度(畫素)
int height = metric.heightPixels; // 螢幕高度(畫素)
View mingpianView = LayoutInflater.from(this).inflate(R.layout.view_team_mingpian, null, false);
layoutView(mingpianView, width, height);
//然後View和其內部的子View都具有了實際大小,也就是完成了佈局,相當與新增到了介面上。接著就可以建立點陣圖並在上面繪製了:
private void layoutView(View v, int width, int height) {
// 指定整個View的大小 引數是左上角 和右下角的座標
v.layout(0, 0, width, height);
int measuredWidth = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
int measuredHeight = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.AT_MOST);
/** 當然,measure完後,並不會實際改變View的尺寸,需要呼叫View.layout方法去進行佈局。
* 按示例呼叫layout函式後,View的大小將會變成你想要設定成的大小。
*/
v.measure(measuredWidth, measuredHeight);
v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
}
在int measuredHeight = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.AT_MOST);
這裡我有點不懂後面函式的取值。在自定義view裡onMeasure()裡有根據MeasureSpec.getMode()的型別來準確得到設定view的長寬
.makeMeasureSpec(height, View.MeasureSpec.AT_MOST);卻貌似取了 自適應和前一個int引數的最小值。
後面我發現有可能合成出超出螢幕的長圖,就直接吧前一個int引數賦值成一個很大的數字。。。
MainActivity
public class MainActivity extends Activity {
ImageView aaa ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DisplayMetrics metric = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metric);
int width = metric.widthPixels; // 螢幕寬度(畫素)
int height = metric.heightPixels; // 螢幕高度(畫素)
View view = LayoutInflater.from(this).inflate(R.layout.view_photo, null, false);
layoutView(view, width, height);
final ScrollView tv = (ScrollView) view.findViewById(R.id.textView);
aaa = (ImageView) findViewById(R.id.aaa);
final Runnable runnable = new Runnable() {
@Override
public void run() {
viewSaveToImage(tv);
}
};
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Handler().post(runnable);
}
});
}
//然後View和其內部的子View都具有了實際大小,也就是完成了佈局,相當與新增到了介面上。接著就可以建立點陣圖並在上面繪製了:
private void layoutView(View v, int width, int height) {
// 整個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());
}
public void viewSaveToImage(View view) {
Log.e("ssh","a");
/**
* View元件顯示的內容可以通過cache機制儲存為bitmap
* 我們要獲取它的cache先要通過setDrawingCacheEnable方法把cache開啟,
* 然後再呼叫getDrawingCache方法就可 以獲得view的cache圖片了
* 。buildDrawingCache方法可以不用呼叫,因為呼叫getDrawingCache方法時,
* 若果 cache沒有建立,系統會自動呼叫buildDrawingCache方法生成cache。
* 若果要更新cache, 必須要呼叫destoryDrawingCache方法把舊的cache銷燬,才能建立新的。
*/
// view.setDrawingCacheEnabled(true);
// view.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
//設定繪製快取背景顏色
// view.setDrawingCacheBackgroundColor(Color.WHITE);
// 把一個View轉換成圖片
Bitmap cachebmp = loadBitmapFromView(view);
aaa.setImageBitmap(cachebmp);//直接展示轉化的bitmap
//儲存在本地 產品還沒決定要不要儲存在本地
FileOutputStream fos;
try {
// 判斷手機裝置是否有SD卡
boolean isHasSDCard = Environment.getExternalStorageState().equals(
android.os.Environment.MEDIA_MOUNTED);
if (isHasSDCard) {
// SD卡根目錄
File sdRoot = Environment.getExternalStorageDirectory();
Log.e("ssh",sdRoot.toString());
File file = new File(sdRoot, "test.png");
fos = new FileOutputStream(file);
} else
throw new Exception("建立檔案失敗!");
//壓縮圖片 30 是壓縮率,表示壓縮70%; 如果不壓縮是100,表示壓縮率為0
cachebmp.compress(Bitmap.CompressFormat.PNG, 90, fos);
fos.flush();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
view.destroyDrawingCache();
}
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;
}
}
參考: