1. 程式人生 > >Android實現將View轉化為圖片並儲存到本地

Android實現將View轉化為圖片並儲存到本地

一、概述

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;  
	} 
}

參考: