สำหรับบทความนี้ขอต่อเนื่องจากบทความเดิมเสียหน่อย [Android Code] การเซฟภาพหน้าจอแบบทั้งหน้าหรือบางส่วนที่ต้องการ ซึ่งเป็นการแคปภาพหน้าจอในแอปพลิเคชันของผู้ที่หลงเข้ามาอ่าน
แต่ทว่าถ้าต้องการเซฟภาพที่เป็น Dialog ล่ะ? จะต้องทำยังไง? เพราะว่าคำสั่งจากบทความดังกล่าวนั้นไม่สามารถทำได้เลย ดังนั้นจึงเป็นที่มาของบทความนี้ที่จะเพิ่มเติมในส่วนที่ว่านี้
จุดสำคัญนั้นอยู่ที่การดึง View จาก Dialog มานั่นเอง ซึ่งจะมีคำสั่งดังนี้
Dialog dialog = .....
...
View dialogView = dialog.getWindow().getDecorView();
dialogView.setDrawingCacheEnabled(true);
Bitmap bm = Bitmap.createBitmap(dialogView.getDrawingCache());
dialogView.setDrawingCacheEnabled(false);
เท่านี้ก็จะได้ bm ที่เป็น Bitmap สำหรับภาพจาก Dialog แล้วถ้าอยากได้ภาพทั้งหน้าจอและ Dialog ล่ะ?
สาเหตุที่เจ้าของบล็อกทำบทความนี้นั้นมาจากผู้ที่หลงเข้ามาอ่านท่านนึงได้ถามมาว่าจะบันทึกภาพหน้าจอทั้งๆที่มี Dialog แสดงอยู่ด้วยอย่างไร และเจ้าของบล็อกก็เห็นว่าน่าสนใจดีและบทความอันเก่าก็ไม่สามารถทำได้
สำหรับคำตอบของปัญหานี้ เจ้าของบล็อกใช้วิธีการเก็บภาพจากหน้าจอแอปพลิเคชันและ Dialog แยกกันเป็นสองส่วน (เพราะมันดันเก็บได้ทีละส่วนนี่สิ) เมิ่อได้ Bitmap ของทั้งสองส่วนแล้วก็ค่อยนำมาซ้อนกันนั่นเอง เท่านี้ก็ได้ภาพหน้าจอแอปพลิเคชันที่มี Dialog อยู่ด้วยแล้ว~
Dialog dialog = .....
// Get bitmap from root layout
View view = findViewById(android.R.id.content).getRootView();
view.setDrawingCacheEnabled(true);
Bitmap bm1 = Bitmap.createBitmap(view.getDrawingCache());
view.setDrawingCacheEnabled(false);
// Get bitmap from dialog layout
View dialogView = dialog.getWindow().getDecorView();
dialogView.setDrawingCacheEnabled(true);
Bitmap bm2 = Bitmap.createBitmap(dialogView.getDrawingCache());
dialogView.setDrawingCacheEnabled(false);
// Merge bitmap
Bitmap bitmap = Bitmap.createBitmap(bm1.getWidth()
, bm1.getHeight(), bm1.getConfig());
Canvas c = new Canvas(bitmap);
c.drawBitmap(bm1, new Matrix(), null);
c.translate((bm1.getWidth() / 2) - (bm2.getWidth() / 2)
, (bm1.getHeight() / 2) - (bm2.getHeight() / 2));
c.drawBitmap(bm2, new Matrix(), null);
// Clear bitmap
bm1.recycle();
bm2.recycle();
เท่านี้ก็จะได้ bitmap ที่เป็น Bitmap สำหรับภาพหน้าจอแอปพลิเคชันรวมไปถึง Dialog แล้วสำหรับตัวอย่างในบทความนี้ก็จะให้กดที่ภาพแล้วจะมี Dialog ขึ้นมาพร้อมกับมีปุ่ม Save ให้กดเพื่อบันทึกภาพ (ทำมาจาก Custom Dialog นั่นเอง สามารถดูเพิ่มเติมได้จาก [Android Code] การสร้าง Custom Dialog) เมื่อผู้ใช้กดก็จะทำการบันทึกภาพเก็บไว้ในเครื่อง โดยจะอยู่ในโฟลเดอร์ Pictures ของเครื่อง ส่วนชื่อไฟล์ภาพที่บันทึกก็จะอิงจากเวลาและวันที่ ณ ตอนที่กดบันทึกภาพ
Main.java
package app.akexorcist.screenshotdialog;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;
import android.app.Activity;
import android.app.Dialog;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.text.format.DateFormat;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;
public class Main extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ImageView imgDialog = (ImageView)findViewById(R.id.imgDialog);
imgDialog.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
final Dialog dialog = new Dialog(Main.this);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(R.layout.customdialog);
dialog.setCancelable(true);
Button btnSave = (Button)dialog.findViewById(R.id.btnSave);
btnSave.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
saveScreen(dialog);
}
});
dialog.show();
}
});
}
public void saveScreen(Dialog dialog) {
// Get bitmap from root layout
View view = findViewById(android.R.id.content).getRootView();
view.setDrawingCacheEnabled(true);
Bitmap bm1 = Bitmap.createBitmap(view.getDrawingCache());
view.setDrawingCacheEnabled(false);
// Get bitmap from dialog layout
View dialogView = dialog.getWindow().getDecorView();
dialogView.setDrawingCacheEnabled(true);
Bitmap bm2 = Bitmap.createBitmap(dialogView.getDrawingCache());
dialogView.setDrawingCacheEnabled(false);
// Merge bitmap
Bitmap bitmap = Bitmap.createBitmap(bm1.getWidth()
, bm1.getHeight(), bm1.getConfig());
Canvas c = new Canvas(bitmap);
c.drawBitmap(bm1, new Matrix(), null);
c.translate((bm1.getWidth() / 2) - (bm2.getWidth() / 2)
, (bm1.getHeight() / 2) - (bm2.getHeight() / 2));
c.drawBitmap(bm2, new Matrix(), null);
// Clear bitmap
bm1.recycle();
bm2.recycle();
try {
// Save bitmap to storage
Date d = new Date();
String filename = (String)DateFormat.format("hhmmss-MMddyyyy"
, d.getTime());
File dir = new File(Environment.getExternalStorageDirectory()
, "/Pictures/" + filename + ".jpg");
FileOutputStream out = new FileOutputStream(dir);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);
out.write(bos.toByteArray());
// Clear bitmap
bitmap.recycle();
// Update image to media system
Intent intent =
new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
intent.setData(Uri.fromFile(dir));
sendBroadcast(intent);
Toast.makeText(getApplicationContext(), "Saved!"
, Toast.LENGTH_SHORT).show();
} catch(FileNotFoundException e) {
e.printStackTrace();
} catch(IOException e) {
e.printStackTrace();
}
}
}
สำหรับในตัวอย่างเจ้าของบล็อกเพิ่มเข้าไปบางส่วน เพื่อให้รวมภาพทั้งสองเข้าด้วยกันแล้วทำการบันทึกภาพลงในเครื่อง แล้วทำการอัปเดตให้กับ Media Scanner เพื่อให้ภาพแสดงใน Gallery ทันที แล้วแสดงผ่าน Toast เพื่อให้รู้ว่าบันทึกภาพเรียบร้อยแล้ว และส่วนที่สำคัญก็คือการ Recycle เหล่า Bitmap ที่เก็บไว้ทั้งหลายครับ เมื่อ Bitmap ตัวไหนใช้เรียบร้อยแล้วก็ควรจะทำการ Recycle เพื่อเคลียร์หน่วยความจำซะ ไม่เช่นนั้นจะ Memory Leak
main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:id="@+id/imgDialog"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:scaleType="centerCrop"
android:src="@drawable/profile" />
</RelativeLayout>
customdialog.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="30dp" >
<ImageView
android:layout_width="200dp"
android:layout_height="60dp"
android:scaleType="fitCenter"
android:src="@drawable/photo" />
<Button
android:id="@+id/btnSave"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Save" />
</LinearLayout>
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="app.akexorcist.screenshotdialog"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="10"
android:targetSdkVersion="19" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".Main"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
ดาวน์โหลดไฟล์ตัวอย่าง
• Screenshot Dialog [GitHub]
• Screenshot Dialog [Google Drive]
• Screenshot Dialog [Sleeping For Less]