只是扩展taraloca的答案 . 您必须添加以下行才能使其正常工作 . I have made the image name static. Please ensure you use taraloca's timestamp variable incase you need dynamic image name.
// Storage Permissions
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
private void verifyStoragePermissions() {
// Check if we have write permission
int permission = ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permission != PackageManager.PERMISSION_GRANTED) {
// We don't have permission so prompt the user
ActivityCompat.requestPermissions(this, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);
}else{
takeScreenshot();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (requestCode == REQUEST_EXTERNAL_STORAGE) {
takeScreenshot();
}
}
}
作为参考,捕获屏幕(而不仅仅是您的应用程序活动)的一种方法是捕获 framebuffer (设备/ dev / graphics / fb0) . 要做到这一点,你必须拥有root权限,或者你的app必须是一个带有signature permissions("A permission that the system grants only if the requesting application is signed with the same certificate as the application that declared the permission")的应用程序 - 除非你编译自己的ROM,否则这种可能性很小 .
// Some constants
final static String SCREENSHOTS_LOCATIONS = Environment.getExternalStorageDirectory().toString() + "/screenshots/";
// Get device dimmensions
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
// Get root view
View view = mCurrentUrlMask.getRootView();
// Create the bitmap to use to draw the screenshot
final Bitmap bitmap = Bitmap.createBitmap(size.x, size.y, Bitmap.Config.ARGB_4444);
final Canvas canvas = new Canvas(bitmap);
// Get current theme to know which background to use
final Activity activity = getCurrentActivity();
final Theme theme = activity.getTheme();
final TypedArray ta = theme
.obtainStyledAttributes(new int[] { android.R.attr.windowBackground });
final int res = ta.getResourceId(0, 0);
final Drawable background = activity.getResources().getDrawable(res);
// Draw background
background.draw(canvas);
// Draw views
view.draw(canvas);
// Save the screenshot to the file system
FileOutputStream fos = null;
try {
final File sddir = new File(SCREENSHOTS_LOCATIONS);
if (!sddir.exists()) {
sddir.mkdirs();
}
fos = new FileOutputStream(SCREENSHOTS_LOCATIONS
+ System.currentTimeMillis() + ".jpg");
if (fos != null) {
if (!bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos)) {
Log.d(LOGTAG, "Compress/Write failed");
}
fos.flush();
fos.close();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
8
如果你想从 fragment 截取屏幕截图,请按照以下步骤操作:
覆盖 onCreateView() :
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_one, container, false);
mView = view;
}
public void shareScreenShotM(View view, NestedScrollView scrollView){
bm = takeScreenShot(view,scrollView); //method to take screenshot
File file = savePic(bm); // method to save screenshot in phone.
}
方法takeScreenShot():
public Bitmap takeScreenShot(View u, NestedScrollView z){
u.setDrawingCacheEnabled(true);
int totalHeight = z.getChildAt(0).getHeight();
int totalWidth = z.getChildAt(0).getWidth();
Log.d("yoheight",""+ totalHeight);
Log.d("yowidth",""+ totalWidth);
u.layout(0, 0, totalWidth, totalHeight);
u.buildDrawingCache();
Bitmap b = Bitmap.createBitmap(u.getDrawingCache());
u.setDrawingCacheEnabled(false);
u.destroyDrawingCache();
return b;
}
方法savePic():
public static File savePic(Bitmap bm){
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
File sdCardDirectory = new File(Environment.getExternalStorageDirectory() + "/Foldername");
if (!sdCardDirectory.exists()) {
sdCardDirectory.mkdirs();
}
// File file = new File(dir, fileName);
try {
file = new File(sdCardDirectory, Calendar.getInstance()
.getTimeInMillis() + ".jpg");
file.createNewFile();
new FileOutputStream(file).write(bytes.toByteArray());
Log.d("Fabsolute", "File Saved::--->" + file.getAbsolutePath());
Log.d("Sabsolute", "File Saved::--->" + sdCardDirectory.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
}
return file;
}
FrameLayout layDraw = (FrameLayout) findViewById(R.id.layDraw); /*Your root view to be part of screenshot*/
layDraw.buildDrawingCache();
Bitmap bmp = layDraw.getDrawingCache();
private void takeScreenshot() {
Date now = new Date();
android.text.format.DateFormat.format("yyyy-MM-dd_hh:mm:ss", now);
try {
// image naming and path to include sd card appending name you choose for file
String mPath = Environment.getExternalStorageDirectory().toString() + "/" + now + ".jpg";
// create bitmap screen capture
View v1 = getWindow().getDecorView().getRootView();
v1.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(v1.getDrawingCache());
v1.setDrawingCacheEnabled(false);
File imageFile = new File(mPath);
FileOutputStream outputStream = new FileOutputStream(imageFile);
int quality = 100;
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream);
outputStream.flush();
outputStream.close();
openScreenshot(imageFile);
} catch (Throwable e) {
// Several error may come out with file handling or DOM
e.printStackTrace();
}
}
这就是你打开最近生成的图像的方法:
private void openScreenshot(File imageFile) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
Uri uri = Uri.fromFile(imageFile);
intent.setDataAndType(uri, "image/*");
startActivity(intent);
}
24 回答
对于那些想要捕获GLSurfaceView的人来说,getDrawingCache或绘图到画布方法将不起作用 .
在渲染帧之后,您必须阅读OpenGL帧缓冲区的内容 . 有一个很好的答案here
只是扩展taraloca的答案 . 您必须添加以下行才能使其正常工作 . I have made the image name static. Please ensure you use taraloca's timestamp variable incase you need dynamic image name.
并且在AndroidManifest.xml文件中,以下条目必须:
编辑:怜悯与downvotes . 2010年,当我回答这个问题时,情况确实如此 .
允许屏幕截图的所有程序仅适用于root电话 .
在清单中添加权限
如需支持 Marshmallow 或更高版本,请在活动onCreate方法中添加以下代码
如果你想捕获像RelativeLayout或LinearLayout等视图或布局,只需使用代码:
现在您可以通过以下方式将此位图保存在设备存储上:
你可以尝试这样做,
从布局或视图中获取位图缓存,通过执行类似首先你必须
setDrawingCacheEnabled
到布局(linearlayout或relativelayout,或视图)然后
然后用位图做任何你想做的事 . 将其转换为图像文件,或将位图的uri发送到其他地方 .
参数视图是根布局对象 .
作为参考,捕获屏幕(而不仅仅是您的应用程序活动)的一种方法是捕获 framebuffer (设备/ dev / graphics / fb0) . 要做到这一点,你必须拥有root权限,或者你的app必须是一个带有signature permissions("A permission that the system grants only if the requesting application is signed with the same certificate as the application that declared the permission")的应用程序 - 除非你编译自己的ROM,否则这种可能性很小 .
从我测试的几个设备中捕获的每个帧缓冲区包含 exactly 一个屏幕截图 . 人们已经报道它包含更多,我想这取决于帧/显示尺寸 .
我试图连续读取帧缓冲区,但它似乎返回固定数量的字节读取 . 在我的情况下是(3 410 432)字节,这足以存储854 * 480 RGBA(3 279 360字节)的显示帧 . 是的,从fb0输出的二进制帧在我的设备中是 RGBA . 这很可能取决于设备 . 这对你解码它很重要=)
在我的设备中 /dev/graphics/fb0 权限是这样的,只有root和组图形中的用户才能读取fb0 .
graphics 是一个受限制的组,因此您可能只能使用su命令使用root电话访问fb0 .
Android应用有 user id (uid) = app_## 和 group id (guid) = app_## .
adb shell 有 uid = shell 和 guid = shell ,它拥有比应用程序更多的权限 . 您可以在/system/permissions/platform.xml中实际检查这些权限
这意味着您将能够在没有root的情况下在adb shell中读取fb0,但是如果没有root,您将无法在应用程序中读取它 .
此外,在AndroidManifest.xml上提供READ_FRAME_BUFFER和/或ACCESS_SURFACE_FLINGER权限对常规应用程序无效,因为这些仅适用于' signature '应用程序 .
另请查看 closed thread 以获取更多详细信息 .
ADD PERMISSION
除了捕获屏幕截图,如果我们也想播放音调 . 我们可以使用以下代码
调用此方法,传入您想要屏幕截图的最外层ViewGroup:
我的解决方案是:
和
图像保存在外部存储文件夹中 .
在android中截取视图的截图 .
Mualig的回答非常好,但我有同样的问题Ewoks描述,我没有得到背景 . 所以有时候足够好,有时我会在黑色背景上得到黑色文字(取决于主题) .
这个解决方案主要基于Mualig代码和我在Robotium中找到的代码 . 我通过直接调用draw方法来放弃使用绘图缓存 . 在此之前,我将尝试从当前活动中获取可绘制的背景以首先绘制它 .
如果你想从
fragment
截取屏幕截图,请按照以下步骤操作:onCreateView()
:shareScreenShotM)()
:对于活动,您只需使用
View v1 = getWindow().getDecorView().getRootView();
而不是mView
我创建了一个简单的库,它从
View
获取屏幕截图,并为您提供一个Bitmap对象或将其直接保存到您想要的任何路径https://github.com/abdallahalaraby/Blink
简短的方法是
此问题的大多数答案都使用
Canvas
绘图方法或绘图缓存方法 . 但是,View.setDrawingCache() method is deprecated in API 28 . 目前推荐的用于制作屏幕截图的API是API 24提供的PixelCopy类(但接受Window
参数的方法可从API 26 == Android 8.0 Oreo获得) . 以下是用于检索Bitmap
的示例Kotlin代码:基于上面的@JustinMorris和@NiravDangi的答案https://stackoverflow.com/a/8504958/2232148,我们必须采用视图的背景和前景并将它们组装成如下:
quality参数采用Bitmap.Config的常量,通常为
Bitmap.Config.RGB_565
或Bitmap.Config.ARGB_8888
.Note: works only for rooted phone
以编程方式,您可以运行
adb shell /system/bin/screencap -p /sdcard/img.png
,如下所示然后将
img.png
读作Bitmap
并按照您的意愿使用 .您可以尝试以下库:http://code.google.com/p/android-screenshot-library/ Android屏幕截图库(ASL)支持以编程方式从Android设备捕获屏幕截图,而无需具有root访问权限 . 相反,ASL使用在后台运行的本机服务,每次设备启动时通过Android调试桥(ADB)启动一次 .
此方法需要 No root permission 或 no big coding .
在使用以下命令的adb shell上,您可以拍摄屏幕截图 .
这个命令不需要任何root权限,所以你也可以从android应用程序的java代码执行 .
有关android中keyevent代码的更多信息,请参阅http://developer.android.com/reference/android/view/KeyEvent.html
我们在这里使用过 . KEYCODE_SYSRQ 其值为120并用于系统请求/打印屏幕键 .
正如CJBS所说,输出图片将保存在 /sdcard/Pictures/Screenshots 中
For system applications only!
注意:系统应用程序不需要运行“su”来执行此命令 .
以下代码允许我的屏幕截图存储在SD卡上,以后用于满足您的任何需求:
首先,您需要添加适当的权限来保存文件:
这是代码(在Activity中运行):
这就是你打开最近生成的图像的方法:
如果要在片段视图上使用它,请使用:
代替
在 takeScreenshot() 功能
Note :
如果对话框包含曲面视图,则此解决方案不起作用 . 有关详细信息,请检查以下问题的答案:
Android Take Screenshot of Surface View Shows Black Screen