如何以编程方式在Android上截屏?


494

如何通过代码从电话屏幕的选定区域截屏,而不是通过任何程序截屏?


4
不是来自模拟器。我需要制作部分程序的屏幕截图,并在同一程序中对其进行处理。
korovaisdead 2010年


Answers:


447

这是使我的屏幕截图存储在SD卡上,以后可用于您需要的代码:

首先,您需要添加适当的权限来保存文件:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

这是代码(在Activity中运行):

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

如果要在片段视图上使用此功能,请使用:

View v1 = getActivity().getWindow().getDecorView().getRootView();

代替

View v1 = getWindow().getDecorView().getRootView();

takeScreenshot()函数上

注意事项

如果对话框包含表面视图,则此解决方案不起作用。有关详细信息,请检查以下问题的答案:

Android拍摄Surface View屏幕截图显示黑屏


23
嗨,您能描述什么是mCurrentUrlMask吗?我已经试过了这段代码,但是它总是在Bitmap.createBitmap(v1.getDrawingCache())上给我NullPointerException,有人可以告诉我我做错了吗?任何帮助表示赞赏。谢谢。
Mitesh Sardhara

4
@MiteshSardhara mCurrentUrlMask必须为一个,View因为它是具有该getRootView()方法的Android API中的唯一类。可能是UI中的视图。
gipi 2013年

6
您能告诉我什么是mCurrentUrlMask吗?
Jayeshkumar Sojitra

37
insted的的View v1 = mCurrentUrlMask.getRootView();我用View v1 = getWindow().getDecorView().getRootView();它为我工作。
enadun 2014年

9
此答案仅截取了应用程序的屏幕截图,而不是问题中询问的“电话屏幕”,或者我做错了什么。
AlikElzin-kilaka 2015年

126

调用此方法,并传入要截屏的最外面的ViewGroup:

public Bitmap screenShot(View view) {
    Bitmap bitmap = Bitmap.createBitmap(view.getWidth(),
            view.getHeight(), Config.ARGB_8888);
    Canvas canvas = new Canvas(bitmap);
    view.draw(canvas);
    return bitmap;
}

9
这似乎是比接受的答案更干净的代码。效果还好吗?
jophde 2014年

2
我已经在一些不同的应用程序中使用了一段时间,并且没有任何问题。
JustinMorris 2014年

3
如果您想获取手机的屏幕快照(您的应用程序位于背景中),您将通过什么作为view?`
AlikElzin-kilaka 2015年

2
getWindow().getDecorView().getRootView()作为视图传递时,只会截取应用程序而不是屏幕的屏幕截图。
AlikElzin-kilaka

此答案仅截取了应用程序的屏幕截图,而不是问题中询问的“电话屏幕”,或者我做错了什么。
AlikElzin-kilaka 2015年

42

注意:仅适用于根电话

以编程方式,您可以adb shell /system/bin/screencap -p /sdcard/img.png按以下方式运行

Process sh = Runtime.getRuntime().exec("su", null,null);
OutputStream os = sh.getOutputStream();
os.write(("/system/bin/screencap -p " + "/sdcard/img.png").getBytes("ASCII"));
os.flush();
os.close();
sh.waitFor();    

然后阅读img.png并按Bitmap您的意愿使用。


需要root权限吗?
2014年

3
是的,您需要root访问权限。请检查标题中的注释
Viswanath Lekshmanan 2014年

嗨,我有一个System.err : java.io.IOException: Error running exec(). Command: [su] Working Directory: null Environment: null ,我的设备是android 5.0
Eddy 2015年

@Eddy取决于您的设备
Demian

有没有一种方法可以直接读取输出,而无需将结果保存到文件中然后再次读取?stackoverflow.com/questions/43914035
Yazan W Yusuf

35

编辑:怜悯唐装。在2010年,我回答了这个问题。

所有允许截图的程序都只能在有根手机上运行。


看起来这些天在基于Tegra芯片组的Android上是可能的
GDR

4.0.3 -那么它可能是这些新学校的Tegra平板电脑之一
GDR

当设备具有用于捕获屏幕截图的常规应用程序时,它是具有特殊签名特权的应用程序,可让其捕获帧缓冲区(包含屏幕像素的缓冲区)。因此,的确如此,如果您的ROM拥有这样的应用程序,则无需植根,只有该应用程序可以进行捕获,而无需您进行捕获。
Rui Marques 2012年

2
严格来说,与根ADB的“外壳”用户帐户一起,始终有权执行此操作,因为这是预期的用例。历史上不可用(除了偶尔的构建错误)是应用程序用户ID的一种方式。
克里斯·斯特拉顿

26

此方法不需要root许可不需要大的编码


在adb shell上,使用以下命令可以进行屏幕截图。

input keyevent 120

此命令不需要任何root权限,因此您也可以从android应用程序的java代码执行相同的命令。

Process process;
process = Runtime.getRuntime().exec("input keyevent 120");

有关android中的keyevent代码的更多信息,请参见http://developer.android.com/reference/android/view/KeyEvent.html

这里我们用过。 KEYCODE_SYSRQ,其值为120,用于系统请求/打印屏幕键。


正如CJBS所说,输出图片将保存在/ sdcard / Pictures / Screenshots中


输出的图片将保存在这里:/sdcard/Pictures/Screenshots
CJBS 2015年

需要root权限吗?
Taranmeet Singh

1
可以在棉花糖上使用吗?还是在服务后台@JeegarPatel中工作
karanatwal.github.io

2
不能以编程方式工作,但可以从Shell进行工作。尝试过牛轧糖。
mehmet6parmak

1
su -c "input keyevent 120"没关系!
ipcjs '17

17

Mualig的回答很好,但是我遇到了Ewoks所描述的相同问题,但我没有得到背景知识。因此有时效果不错,有时我会在黑色背景上出现黑色文字(取决于主题)。

该解决方案主要基于Mualig代码和我在Robotium中找到的代码。我通过直接调用draw方法来放弃使用绘图缓存。在此之前,我将尝试先从当前活动中获取背景可绘制对象。

// 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();
}

我的活动中有一个带有android:cacheColorHint =“#00000000”的列表视图,并且使用此代码进行屏幕截图,我仍然得到黑色背景,因为我发现从主题获得的背景是黑色,我该如何处理列表显示?
Wangchao0721 2012年

Activity activity = getCurrentActivity提供Eroor未定义的方法。
Shabbir Dhangot

17
private void captureScreen() {
    View v = getWindow().getDecorView().getRootView();
    v.setDrawingCacheEnabled(true);
    Bitmap bmp = Bitmap.createBitmap(v.getDrawingCache());
    v.setDrawingCacheEnabled(false);
    try {
        FileOutputStream fos = new FileOutputStream(new File(Environment
                .getExternalStorageDirectory().toString(), "SCREEN"
                + System.currentTimeMillis() + ".png"));
        bmp.compress(CompressFormat.PNG, 100, fos);
        fos.flush();
        fos.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

在清单中添加权限

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

对于支持棉花糖或更高版本,请在活动onCreate方法中添加以下代码

ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},00);

要求:<uses-permission android:name =“ android.permission.WRITE_EXTERNAL_STORAGE” />
AndroidGuy 2015年

4
此答案仅截取了应用程序的屏幕截图,而不是问题中询问的“电话屏幕”,还是我做错了?
AlikElzin-kilaka

如果我需要列表视图项目的屏幕截图,该怎么办?
Anshul Tyagi

我想从适配器中捕获任何想法,我该怎么办?
Deep Dave

16

作为参考,捕获屏幕(而不仅仅是您的应用活动)的一种方法是捕获帧缓冲区(设备/ dev / graphics / fb0)。为此,您必须具有root特权,或者您的应用程序必须是具有签名权限的应用程序(“仅当发出请求的应用程序使用与声明该权限的应用程序相同的证书的系统才会授予该权限”)-除非您编译自己的ROM,否则可能性很小。

从我测试过的两个设备中捕获的每个帧缓冲区都恰好包含一个屏幕截图。人们报告说它包含更多,我想这取决于帧/显示器的大小。

我试图连续读取帧缓冲区,但似乎返回固定数量的已读取字节。在我的情况下,这是(3 410 432)字节,足以存储854 * 480 RGBA(3 279 360字节)的显示帧。是的,从fb0输出的二进制帧是RGBA在我的设备中。这很可能取决于设备。这对您进行解码很重要=)

在我的设备中,/ dev / graphics / fb0权限是允许的,因此只有root用户和来自组图形的用户才能读取fb0。

图形是一个受限制的组,因此您可能只能使用su命令通过有根电话访问fb0。

Android应用具有用户ID(uid)= app _ ##组ID(guid)= app _ ##

亚行外壳uid = shellguid = shell,比应用程序具有更多的权限。您实际上可以在/system/permissions/platform.xml中检查那些权限

这意味着您可以在没有root的情况下在adb shell中读取fb0,但在没有root的应用程序中将无法读取它。

另外,在AndroidManifest.xml上授予READ_FRAME_BUFFER和/或ACCESS_SURFACE_FLINGER权限对常规应用程序无效,因为它们仅适用于“ 签名 ”应用程序。

还要检查此关闭的线程以获取更多详细信息。


2
在某些手机上这行得通(工作吗?),但请注意,基于GPU的手机不一定为应用处理器提供线性帧缓冲区。
克里斯·斯特拉顿

15

我的解决方案是:

public static Bitmap loadBitmapFromView(Context context, View v) {
    DisplayMetrics dm = context.getResources().getDisplayMetrics(); 
    v.measure(MeasureSpec.makeMeasureSpec(dm.widthPixels, MeasureSpec.EXACTLY),
            MeasureSpec.makeMeasureSpec(dm.heightPixels, MeasureSpec.EXACTLY));
    v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
    Bitmap returnedBitmap = Bitmap.createBitmap(v.getMeasuredWidth(),
            v.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
    Canvas c = new Canvas(returnedBitmap);
    v.draw(c);

    return returnedBitmap;
}

public void takeScreen() {
    Bitmap bitmap = ImageUtils.loadBitmapFromView(this, view); //get Bitmap from the view
    String mPath = Environment.getExternalStorageDirectory() + File.separator + "screen_" + System.currentTimeMillis() + ".jpeg";
    File imageFile = new File(mPath);
    OutputStream fout = null;
    try {
        fout = new FileOutputStream(imageFile);
        bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fout);
        fout.flush();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        fout.close();
    }
}

图像保存在外部存储文件夹中。


1
您应该在finally块中关闭FileOutputStream。如果您遇到异常,则此流将不会关闭。
沃图

什么是view你传递到ImageUtils.loadBitmapFromView(this, view)
AlikElzin-kilaka 2015年

1
为什么使用v.layout(0,0,v.getMeasuredWidth(),v.getMeasuredHeight()); ?这不会改变视图(v)吗?
serj

11

您可以尝试以下库:http : //code.google.com/p/android-screenshot-library/ Android屏幕截图库(ASL)可以以编程方式从Android设备捕获屏幕截图,而无需具有root用户访问权限。相反,ASL使用在后台运行的本机服务,该服务在每次设备启动时通过Android调试桥(ADB)启动。


1
我尝试过这个,但是它只需要运行的应用程序的屏幕截图。如果我想截取主屏幕的截图,则无济于事。您如何使用该代码拍摄主屏幕的屏幕截图?
Jana

1
@ Janardhanan.S:这就是问题的所在。您能否用一个新的答案而不是问一个单独的问题来详细说明。
trgraglia

3
我也遇到同样的问题。“本地服务未运行!”
Yogesh Maheshwari,2012年

1
和我一样“本地服务未运行!” ....有人可以在此处添加帮助文本吗?
Pankaj Kumar

1
同样在这里!“本地服务未运行!” 在最新的1.2版中,它们使用API​​ LEVEL 19类,例如Socket。
user347187

10

基于上面@JustinMorris和@NiravDangi的答案https://stackoverflow.com/a/8504958/2232148,我们必须获取视图的背景和前景,并像这样组装它们:

public static Bitmap takeScreenshot(View view, Bitmap.Config quality) {
    Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), quality);
    Canvas canvas = new Canvas(bitmap);

    Drawable backgroundDrawable = view.getBackground();
    if (backgroundDrawable != null) {
        backgroundDrawable.draw(canvas);
    } else {
        canvas.drawColor(Color.WHITE);
    }
    view.draw(canvas);

    return bitmap;
}

quality参数采用Bitmap.Config常量,通常为Bitmap.Config.RGB_565Bitmap.Config.ARGB_8888


在背景为空的情况下用白色绘制画布对我有用。感谢Oliver
Shaleen

8
public class ScreenShotActivity extends Activity{

private RelativeLayout relativeLayout;
private Bitmap myBitmap;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    relativeLayout = (RelativeLayout)findViewById(R.id.relative1);
    relativeLayout.post(new Runnable() {
        public void run() {

            //take screenshot
            myBitmap = captureScreen(relativeLayout);

            Toast.makeText(getApplicationContext(), "Screenshot captured..!", Toast.LENGTH_LONG).show();

            try {
                if(myBitmap!=null){
                    //save image to SD card
                    saveImage(myBitmap);
                }
                Toast.makeText(getApplicationContext(), "Screenshot saved..!", Toast.LENGTH_LONG).show();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        }
    });

}

public static Bitmap captureScreen(View v) {

    Bitmap screenshot = null;
    try {

        if(v!=null) {

            screenshot = Bitmap.createBitmap(v.getMeasuredWidth(),v.getMeasuredHeight(), Config.ARGB_8888);
            Canvas canvas = new Canvas(screenshot);
            v.draw(canvas);
        }

    }catch (Exception e){
        Log.d("ScreenShotActivity", "Failed to capture screenshot because:" + e.getMessage());
    }

    return screenshot;
}

public static void saveImage(Bitmap bitmap) throws IOException{

    ByteArrayOutputStream bytes = new ByteArrayOutputStream();
    bitmap.compress(Bitmap.CompressFormat.PNG, 40, bytes);
    File f = new File(Environment.getExternalStorageDirectory() + File.separator + "test.png");
    f.createNewFile();
    FileOutputStream fo = new FileOutputStream(f);
    fo.write(bytes.toByteArray());
    fo.close();
}

}

添加权限

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

此答案仅截取了应用程序的屏幕截图,而不是问题中所要求的“电话屏幕”,还是我做错了?
AlikElzin-kilaka 2015年

7

您可以尝试做这样的事情,

通过执行诸如“首先要获得”这样的操作,从布局或视图中获取位图缓存 setDrawingCacheEnabled布局”(线性布局或相对布局,或视图)之类的操作来

然后

Bitmap bm = layout.getDrawingCache()

然后,您可以对位图进行任何操作。要么将其转换为图像文件,要么将位图的uri发送到其他地方。


1
如果您正在编写位图,这是最好的方法。另外,请注意在获取缓存之前有延迟的方法...像列表视图的Notify ...()一样。
trgraglia 2011年

不仅如此。布局必须首先显示在屏幕上。这毕竟是您获得的“缓存”。试图隐藏视图并在后台拍摄屏幕截图(理论上),但是没有用。
凯文·谭

比其他解决方案有效得多
sivi

6

对于那些想要捕获GLSurfaceView的人,getDrawingCache或“绘制到画布”方法将不起作用。

渲染帧后,您必须读取OpenGL帧缓冲区的内容。这是一个很好的答案在这里


6

我创建了一个简单的库,该库从中获取了屏幕截图,View并为您提供了位图对象或将其直接保存到所需的任何路径

https://github.com/abdallahalaraby/Blink


是否需要扎根电话?
Nilesh Agrawal,2015年

1
无需生根:)
Abdallah Alaraby 2015年

在使用中,您提到了Screenshot.takeScreenshot(view, mPath); imageView.setImageBitmap(Screenshot.getBitmapScreenshot(view, mPath)); 如何查看当前活动。我不想使用xml的ID。
Nilesh Agrawal,2015年

使用takeScreenshotForScreen()代替。
阿卜杜拉·阿拉拉比

6

捷径是

FrameLayout layDraw = (FrameLayout) findViewById(R.id.layDraw); /*Your root view to be part of screenshot*/
layDraw.buildDrawingCache();
Bitmap bmp = layDraw.getDrawingCache();

5

只是扩展了taraloca的答案。您必须添加以下代码行才能使其正常运行。我已将图像名称设为静态。如果需要动态图像名称,请确保使用taraloca的timestamp变量。

    // 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();
        }
    }
}

在AndroidManifest.xml文件中,必须输入以下内容:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

4

如果要从中获取屏幕截图,请fragment 按照以下步骤操作:

  1. 覆写 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;
            }
  2. 截图的逻辑:

     button.setOnClickListener(new View.OnClickListener() {
     @Override
     public void onClick(View v) {
         View view =  mView.findViewById(R.id.scrollView1);
          shareScreenShotM(view, (NestedScrollView) view); 
     }
  3. 方法shareScreenShotM)()

    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.
        }
  4. 方法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;
            }
  5. 方法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;
       }

对于活动,您可以简单地使用View v1 = getWindow().getDecorView().getRootView();而不是mView


3

此问题的大多数答案使用Canvas绘图方法或绘图缓存方法。但是,View.setDrawingCache()API 28中不推荐使用方法。当前,推荐的用于制作屏幕截图的API是PixelCopyAPI 24中可用的类(但是Window可以从API 26 == Android 8.0 Oreo中获得接受参数的方法)。这是用于检索的示例Kotlin代码Bitmap

@RequiresApi(Build.VERSION_CODES.O)
fun saveScreenshot(view: View) {
    val window = (view.context as Activity).window
    if (window != null) {
        val bitmap = Bitmap.createBitmap(view.width, view.height, Bitmap.Config.ARGB_8888)
        val locationOfViewInWindow = IntArray(2)
        view.getLocationInWindow(locationOfViewInWindow)
        try {
            PixelCopy.request(window, Rect(locationOfViewInWindow[0], locationOfViewInWindow[1], locationOfViewInWindow[0] + view.width, locationOfViewInWindow[1] + view.height), bitmap, { copyResult ->
                if (copyResult == PixelCopy.SUCCESS) {
                    saveBitmap(bitmap)
                }
                // possible to handle other result codes ...
            }, Handler())
        } catch (e: IllegalArgumentException) {
            // PixelCopy may throw IllegalArgumentException, make sure to handle it
        }
    }
}

通过DrawingCache解决方案的PixelCopy的问题在于,它似乎只能捕获可见像素。剩下的对我来说是黑色的。因此,无法共享可滚动且部分超出框架的内容。您对此有解决方案吗?
亨宁

你是对的。同样,如果要截图的视图上方显示另一个视图(例如,打开抽屉时),可能会导致问题。在这种情况下,我只是用旧帆布方法:(
米洛什Černilovský

1
是否可以使用PixelCopy在任何正在运行的应用程序上进行屏幕截图?
阿米尔·雷扎伊

2

仅用于系统应用程序!

Process process;
process = Runtime.getRuntime().exec("screencap -p " + outputPath);
process.waitFor();

注意:系统应用程序无需运行“ su”即可执行此命令。


2

参数视图是根布局对象。

public static Bitmap screenShot(View view) {
                    Bitmap bitmap = null;
                    if (view.getWidth() > 0 && view.getHeight() > 0) {
                        bitmap = Bitmap.createBitmap(view.getWidth(),
                                view.getHeight(), Bitmap.Config.ARGB_8888);
                        Canvas canvas = new Canvas(bitmap);
                        view.draw(canvas);
                    }
                    return bitmap;
                }

2

对于全页滚动截图

如果要捕获完整的View屏幕截图(其中包含滚动视图左右),请在此库中进行检查

https://github.com/peter1492/LongScreenshot

您要做的就是导入Gradel,并创建一个BigScreenshot对象

BigScreenshot longScreenshot = new BigScreenshot(this, x, y);

在自动滚动浏览整个屏幕视图组并最终组装在一起时,将收到带有截屏的位图的回调。

@Override public void getScreenshot(Bitmap bitmap) {}

可以将其保存到图库中,也可以在以后使用


1

拍摄android中视图的屏幕截图。

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

-1

如果要捕获视图或布局(例如RelativeLayout或LinearLayout等),请使用以下代码:

LinearLayout llMain = (LinearLayout) findViewById(R.id.linearlayoutMain);
Bitmap bm = loadBitmapFromView(llMain);

现在您可以通过以下方式将此位图保存在设备存储中:

FileOutputStream outStream = null;
File f=new File(Environment.getExternalStorageDirectory()+"/Screen Shots/");
f.mkdir();
String extStorageDirectory = f.toString();
File file = new File(extStorageDirectory, "my new screen shot");
pathOfImage = file.getAbsolutePath();
try {
    outStream = new FileOutputStream(file);
    bm.compress(Bitmap.CompressFormat.PNG, 100, outStream);
    Toast.makeText(getApplicationContext(), "Saved at "+f.getAbsolutePath(), Toast.LENGTH_LONG).show();
    addImageGallery(file);
    //mail.setEnabled(true);
    flag=true;
} catch (FileNotFoundException e) {e.printStackTrace();}
try {
    outStream.flush();
    outStream.close();
} catch (IOException e) {e.printStackTrace();}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.