¿Cómo tomar una captura de pantalla mediante programación en Android?

Respuestas:

448

Aquí está el código que permitió que mi captura de pantalla se almacenara en una tarjeta SD y se usara más tarde para lo que sea que necesite:

Primero, debe agregar un permiso adecuado para guardar el archivo:

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

Y este es el código (que se ejecuta en una Actividad):

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

Y así es como puede abrir la imagen generada recientemente:

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

Si desea usar esto en la vista de fragmentos, use:

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

en vez de

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

en takeScreenshot () función

Nota :

Esta solución no funciona si su cuadro de diálogo contiene una vista de superficie. Para más detalles, consulte la respuesta a la siguiente pregunta:

Captura de pantalla de Android Take de Surface View muestra pantalla en negro

taraloca
fuente
23
Hola, ¿Puedes describir qué es mCurrentUrlMask? He intentado este código pero siempre me está dando NullPointerException en Bitmap.createBitmap (v1.getDrawingCache ()). ¿Alguien puede decir qué estoy haciendo mal? Cualquier ayuda es apreciada. Gracias.
Mitesh Sardhara
44
@MiteshSardhara mCurrentUrlMaskdebe ser una Viewclase única en la API de Android que tiene el getRootView()método. Probablemente es una vista en la interfaz de usuario.
gipi
66
¿Me puede decir qué es, mCurrentUrlMask?
Jayeshkumar Sojitra
37
En lugar de View v1 = mCurrentUrlMask.getRootView();que he utilizado View v1 = getWindow().getDecorView().getRootView();y funciona para mí.
enadun
99
Esta respuesta toma una captura de pantalla de la aplicación, no de la "pantalla del teléfono" como se hizo en la pregunta, o estoy haciendo algo mal.
AlikElzin-kilaka
126

Llame a este método, pasando el ViewGroup más externo del que desea una captura de pantalla:

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;
}
JustinMorris
fuente
99
Este parece ser un código más limpio que la respuesta aceptada. ¿Funciona tan bien?
jophde
2
Lo he usado por un tiempo en algunas aplicaciones diferentes y no he tenido ningún problema.
JustinMorris
3
Si desea obtener una captura de pantalla del teléfono, donde su aplicación está en segundo plano, ¿qué pasa como el view? "
AlikElzin-kilaka
2
Al pasar getWindow().getDecorView().getRootView(), la vista da como resultado una captura de pantalla de la aplicación, no de la pantalla.
AlikElzin-kilaka
Esta respuesta toma una captura de pantalla de la aplicación, no de la "pantalla del teléfono" como se hizo en la pregunta, o estoy haciendo algo mal.
AlikElzin-kilaka
42

Nota: funciona solo para teléfonos rooteados

Programáticamente, puede ejecutar adb shell /system/bin/screencap -p /sdcard/img.pngcomo a continuación

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

luego lea img.pngcomo Bitmapy use como desee.

Viswanath Lekshmanan
fuente
¿Se necesita acceso root?
zoom
3
Sí, necesitas acceso root. Consulte la Nota en el encabezado
Viswanath Lekshmanan
Hola, tengo un System.err : java.io.IOException: Error running exec(). Command: [su] Working Directory: null Environment: null , mi dispositivo es Android 5.0
Eddy
@Eddy Depende de tu dispositivo
Demian
¿Hay alguna manera de leer el resultado directamente sin guardar el resultado en el archivo y luego leerlo de nuevo? stackoverflow.com/questions/43914035
Yazan W Yusuf
35

EDITAR: ten piedad de los votos negativos. Fue cierto en 2010 cuando respondí la pregunta.

Todos los programas que permiten capturas de pantalla solo funcionan en teléfonos rooteados.

RDA
fuente
Parece que en estos días es posible en Android con chipset basado en Tegra
RDA
4.0.3 - entonces probablemente sea una de estas tabletas tegra de la nueva escuela
RDA
AFAIK cuando los dispositivos tienen una aplicación estándar para capturar capturas de pantalla, es una aplicación con privilegios especiales de firma que le permite capturar el framebuffer (un buffer con los píxeles de la pantalla). Por lo tanto, es cierto, si su ROM tiene una aplicación de este tipo, no necesitará estar rooteado, pero solo esa aplicación puede hacer capturas, no la suya.
Rui Marques
2
Estrictamente hablando, junto con la cuenta de usuario "shell" raíz de ADB siempre ha tenido permiso para hacerlo, ya que ese era el caso de uso previsto. Lo que históricamente no estaba disponible (excepto en compilaciones ocasionales como un error) era una forma de identificación de usuario de la aplicación para hacerlo.
Chris Stratton
26

No se requiere permiso de root o no se requiere una gran codificación para este método.


En adb shell con el siguiente comando, puede tomar una captura de pantalla.

input keyevent 120

Este comando no requiere ningún permiso de root, por lo que también puede realizarlo desde el código Java de la aplicación de Android.

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

Más información sobre el código Keyevent en Android, consulte http://developer.android.com/reference/android/view/KeyEvent.html

Aquí lo hemos usado. KEYCODE_SYSRQ su valor es 120 y se utiliza para la tecla Solicitud del sistema / Imprimir pantalla.


Como dijo CJBS, la imagen de salida se guardará en / sdcard / Pictures / Screenshots

Jeegar Patel
fuente
La imagen de salida se guardará aquí:/sdcard/Pictures/Screenshots
CJBS
¿Requiere permiso de root?
Taranmeet Singh
1
¿Funcionará en malvavisco? o funcionará en el fondo de servicio @JeegarPatel
karanatwal.github.io
2
no funcionó programáticamente, pero funciona desde shell. Probado con turrón.
mehmet6parmak
1
su -c "input keyevent 120"esta bien !!
ipcjs
17

La respuesta de Mualig es muy buena, pero tuve el mismo problema que describe Ewoks, no entiendo el fondo. Entonces, a veces es lo suficientemente bueno y a veces obtengo texto negro sobre fondo negro (dependiendo del tema).

Esta solución está fuertemente basada en el código Mualig y el código que encontré en Robotium. Estoy descartando el uso de la memoria caché de dibujo llamando directamente al método de dibujo. Antes de eso, trataré de dibujar el fondo de la actividad actual para dibujarlo primero.

// 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();
}
xamar
fuente
Tengo una vista de lista con Android: cacheColorHint = "# 00000000" en mi actividad, y utilizo este código para capturar la pantalla, todavía tengo un fondo negro, porque encontré que el fondo que se obtiene del tema es negro, ¿cómo puedo lidiar con esto? ¿vista de la lista?
Wangchao0721
Actividad de actividad = getCurrentActivity que proporciona el método indefinido 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();
    }
}

Agregue el permiso en el manifiesto

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

Para admitir Marshmallow o versiones superiores, agregue el siguiente código en la actividad del método Crear

ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},00);
Codificador loco
fuente
Requiere: <usos-permiso android: name = "android.permission.WRITE_EXTERNAL_STORAGE" />
AndroidGuy
44
Esta respuesta toma una captura de pantalla de la aplicación, no de la "pantalla del teléfono" como se hizo en la pregunta, ¿o estoy haciendo algo mal?
AlikElzin-kilaka
¿Qué pasa si necesito captura de pantalla de un elemento de la vista de lista?
Anshul Tyagi
Quiero capturar desde el adaptador alguna idea ¿cómo puedo hacerlo?
Deep Dave
16

Como referencia, una forma de capturar la pantalla (y no solo la actividad de su aplicación) es capturar el framebuffer (dispositivo / dev / graphics / fb0). Para hacer esto, debe tener privilegios de root o su aplicación debe ser una aplicación con permisos de firma ("Un permiso que el sistema otorga solo si la aplicación solicitante está firmada con el mismo certificado que la aplicación que declaró el permiso"), que es muy poco probable a menos que haya compilado su propia ROM.

Cada captura de framebuffer, de un par de dispositivos que he probado, contenía exactamente una captura de pantalla. La gente ha informado que contiene más, supongo que depende del tamaño del marco / pantalla.

Traté de leer el framebuffer continuamente, pero parece volver por una cantidad fija de bytes leídos. En mi caso, eso es (3 410 432) bytes, que es suficiente para almacenar un marco de visualización de 854 * 480 RGBA (3 279 360 bytes). Sí, el marco, en binario, generado desde fb0 es RGBA en mi dispositivo. Esto probablemente dependerá de un dispositivo a otro. Esto será importante para que lo decodifiques =)

En mi dispositivo / dev / graphics / fb0 los permisos son para que solo la raíz y los usuarios de los gráficos de grupo puedan leer el fb0.

graphics es un grupo restringido, por lo que probablemente solo accederá a fb0 con un teléfono rooteado mediante el comando su.

Las aplicaciones de Android tienen la identificación de usuario (uid) = aplicación _ ## y la identificación de grupo (guid) = aplicación _ ## .

adb shell tiene uid = shell y guid = shell , que tiene muchos más permisos que una aplicación. En realidad, puede verificar esos permisos en /system/permissions/platform.xml

Esto significa que podrá leer fb0 en el shell adb sin root, pero no lo leerá dentro de la aplicación sin root.

Además, otorgar permisos READ_FRAME_BUFFER y / o ACCESS_SURFACE_FLINGER en AndroidManifest.xml no hará nada para una aplicación normal porque solo funcionará para aplicaciones de ' firma '.

También revise este hilo cerrado para más detalles.

Rui Marques
fuente
2
Esto funciona (¿funcionó?) En algunos teléfonos, pero tenga en cuenta que los teléfonos basados ​​en GPU no necesariamente proporcionan un buffer de cuadros lineal al procesador de aplicaciones.
Chris Stratton
15

Mi solución es:

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

y

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

Las imágenes se guardan en la carpeta de almacenamiento externo.

validcat
fuente
1
Debería cerrar FileOutputStream en un bloque finalmente. Si encuentra una excepción ahora, la transmisión no se cerrará.
Wotuu
¿A viewqué estás pasando ImageUtils.loadBitmapFromView(this, view)?
AlikElzin-kilaka
1
¿por qué usa v.layout (0, 0, v.getMeasuredWidth (), v.getMeasuredHeight ()); ? ¿Eso no cambia la vista (v)?
serj
11

Puede probar la siguiente biblioteca: http://code.google.com/p/android-screenshot-library/ Android Screenshot Library (ASL) permite capturar capturas de pantalla mediante programación de dispositivos Android sin necesidad de tener privilegios de acceso a la raíz. En cambio, ASL utiliza un servicio nativo que se ejecuta en segundo plano, iniciado a través del Android Debug Bridge (ADB) una vez por inicio de dispositivo.

Kuba
fuente
1
Intenté esto, pero solo toma una captura de pantalla de la aplicación en ejecución. No puedo ayudar si quiero tomar una captura de pantalla de la pantalla de inicio. ¿Cómo tomar una captura de pantalla de la pantalla de inicio con ese código?
Jana
1
@ Janardhanan.S: Esto es lo que pide la pregunta. ¿Puede elaborar una nueva respuesta en lugar de hacer una pregunta por separado?
Trgraglia
3
El mismo problema conmigo ... "¡El servicio nativo no se está ejecutando!"
Yogesh Maheshwari
1
Lo mismo conmigo "¡El servicio nativo no se está ejecutando!" ... ¿alguien puede agregar el texto de ayuda aquí?
Pankaj Kumar
1
¡igual que aquí! "¡Servicio nativo no se ejecuta!" y en su última versión 1.2 usan clases API LEVEL 19, como Socket por ejemplo.
user347187
10

Según la respuesta de @JustinMorris arriba y @NiravDangi aquí https://stackoverflow.com/a/8504958/2232148 debemos tomar el fondo y el primer plano de una vista y ensamblarlos así:

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

El parámetro de calidad toma una constante de Bitmap.Config, normalmente Bitmap.Config.RGB_565o Bitmap.Config.ARGB_8888.

Oliver Hausler
fuente
dibujar lienzo con color blanco en caso de que el fondo sea nulo me sirvió. Gracias 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();
}

}

AGREGAR PERMISO

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Vaishali Sutariya
fuente
Esta respuesta toma una captura de pantalla de la aplicación, no de la "pantalla del teléfono" como se hizo en la pregunta, ¿o estoy haciendo algo mal?
AlikElzin-kilaka
7

Puedes intentar hacer algo como esto,

Obtener un caché de mapa de bits de un diseño o una vista haciendo algo como Primero, setDrawingCacheEnableddebe obtener un diseño (un diseño lineal o un diseño relativo, o una vista)

entonces

Bitmap bm = layout.getDrawingCache()

Luego haces lo que quieras con el mapa de bits. Ya sea convirtiéndolo en un archivo de imagen o enviando la uri del mapa de bits a otro lugar.

Kevin Tan
fuente
1
Este es el mejor método si es su aplicación la que está escribiendo en un mapa de bits. Además, tenga cuidado con los métodos que tienen retrasos antes de tomar el caché ... como Notificar ... () para las vistas de lista.
Trgraglia
No solo eso. El diseño debe mostrarse primero en la pantalla. Es el "caché" que estás obteniendo después de todo. Intenté ocultar la vista y tomar capturas de pantalla en el fondo (en teoría), pero no funcionó.
Kevin Tan
Por mucho más eficiente que otras soluciones
sivi
6

Para aquellos que desean capturar un GLSurfaceView, el método getDrawingCache o el dibujo al lienzo no funcionará.

Debe leer el contenido del framebuffer de OpenGL después de que se haya procesado el marco. Hay una buena respuesta aquí

Rockeye
fuente
6

He creado una biblioteca simple que toma una captura de pantalla de a Viewy le da un objeto de mapa de bits o lo guarda directamente en cualquier ruta que desee

https://github.com/abdallahalaraby/Blink

Abdallah Alaraby
fuente
¿Requiere teléfono rooteado?
Nilesh Agrawal
1
No se requiere enraizamiento :)
Abdallah Alaraby
En uso, mencionaste Screenshot.takeScreenshot(view, mPath); imageView.setImageBitmap(Screenshot.getBitmapScreenshot(view, mPath)); Cómo obtener una vista de la actividad actual. No quiero usar la identificación del xml.
Nilesh Agrawal
utilizar takeScreenshotForScreen()en su lugar.
Abdallah Alaraby
6

Camino corto es

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

Solo extendiendo la respuesta de taraloca. Debe agregar las siguientes líneas para que funcione. He hecho que el nombre de la imagen sea estático. Asegúrese de utilizar la variable de marca de tiempo de taraloca en caso de que necesite un nombre de imagen dinámico.

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

Y en el archivo AndroidManifest.xml las siguientes entradas son obligatorias:

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

Si desea tomar una captura de pantalla, fragment siga esto:

  1. Anular 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. Lógica para tomar captura de pantalla:

     button.setOnClickListener(new View.OnClickListener() {
     @Override
     public void onClick(View v) {
         View view =  mView.findViewById(R.id.scrollView1);
          shareScreenShotM(view, (NestedScrollView) view); 
     }
  3. método 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. Método 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. Método 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;
       }

Para la actividad, simplemente puede usar en View v1 = getWindow().getDecorView().getRootView();lugar demView

Parsania Hardik
fuente
3

La mayoría de las respuestas a esta pregunta utilizan el Canvasmétodo de dibujo o el método de caché de dibujo. Sin embargo, el View.setDrawingCache()método está en desuso en la API 28 . Actualmente, la API recomendada para hacer capturas de pantalla es la PixelCopyclase disponible en API 24 (pero los métodos que aceptan Windowparámetros están disponibles en API 26 == Android 8.0 Oreo). Aquí hay un ejemplo de código de Kotlin para recuperar un 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
        }
    }
}
Miloš Černilovský
fuente
El problema con PixelCopy sobre la solución drawingCache es que parece capturar solo píxeles visibles. El resto es negro para mí. Por lo tanto, no es posible compartir cosas que se pueden desplazar y que están parcialmente fuera del marco. ¿Tienes una solución para esto?
Henning
Tienes razón. Del mismo modo, puede causar un problema si se muestra otra Vista encima de la Vista que deseo capturar (p. Ej., Cuando se abre el cajón). En estos casos, solo uso el antiguo método Canvas :(
Miloš Černilovský
1
¿Es posible tomar capturas de pantalla en cualquier aplicación en ejecución usando PixelCopy?
Amir Rezaei
2

¡Solo para aplicaciones del sistema!

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

Nota: Las aplicaciones del sistema no necesitan ejecutar "su" para ejecutar este comando.

GilCol
fuente
2

La vista de parámetros es el objeto de diseño raíz.

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;
                }
Anil Singhania
fuente
2

Para la captura de pantalla de desplazamiento de página completa

Si desea capturar una captura de pantalla de Vista completa (que contiene una vista de desplazamiento más o menos), consulte esta biblioteca

https://github.com/peter1492/LongScreenshot

Todo lo que tiene que hacer es importar Gradel y crear un objeto de BigScreenshot

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

Se recibirá una devolución de llamada con el mapa de bits de las Capturas de pantalla tomadas mientras se desplaza automáticamente a través del grupo de visualización de pantalla y al final se ensamblan.

@Override public void getScreenshot(Bitmap bitmap) {}

Lo que se puede guardar en la galería o cualquier uso es necesario después de

Peter
fuente
1

Tome una captura de pantalla de una vista en 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;
}
Mohit Singh
fuente
-1

si desea capturar una vista o diseño como RelativeLayout o LinearLayout, etc., simplemente use el código:

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

ahora puede guardar este mapa de bits en el almacenamiento del dispositivo:

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();}
Akshay Paliwal
fuente