Come fare uno screenshot a livello di codice su Android?


495

Come posso fare uno screenshot di un'area selezionata dello schermo del telefono non da alcun programma ma dal codice?


4
Non dall'emulatore. Devo fare uno screenshot di parte del mio programma e farlo con lo stesso programma.
korovaisdead,

1
Un altro riferimento buono: stackoverflow.com/a/10296881/439171
Italo Borssatto

Risposte:


448

Ecco il codice che ha permesso di archiviare il mio screenshot su una scheda SD e di utilizzarlo in seguito per qualsiasi necessità:

Innanzitutto, è necessario aggiungere un'autorizzazione adeguata per salvare il file:

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

E questo è il codice (in esecuzione in un'attività):

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

Ed è così che puoi aprire l'immagine generata di recente:

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

Se si desidera utilizzarlo nella vista frammento, utilizzare:

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

invece di

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

sulla funzione takeScreenshot ()

Nota :

Questa soluzione non funziona se la finestra di dialogo contiene una vista di superficie. Per i dettagli, controlla la risposta alla seguente domanda:

Android Cattura schermata di Surface View Mostra la schermata nera


23
Ciao, puoi descrivere cos'è mCurrentUrlMask? Ho provato questo codice ma mi dà sempre NullPointerException su Bitmap.createBitmap (v1.getDrawingCache ()), Qualcuno può dire cosa sto facendo di sbagliato.? Qualsiasi aiuto è apprezzato. Grazie.
Mitesh Sardhara,

4
@MiteshSardhara mCurrentUrlMaskdeve essere una Viewpoiché è la classe unica nell'API di Android che ha il getRootView()metodo. Probabilmente è una vista nell'interfaccia utente.
gipi,

6
Potete per favore dirmi cos'è, mCurrentUrlMask?
Jayeshkumar Sojitra,

37
Invece di View v1 = mCurrentUrlMask.getRootView();ho usato View v1 = getWindow().getDecorView().getRootView();e funziona per me.
enadun,

9
Questa risposta prende uno screenshot solo dell'app, non dello "schermo del telefono" come richiesto nella domanda - o sto facendo qualcosa di sbagliato.
AlikElzin-Kilaka,

126

Chiama questo metodo, passando nel ViewGroup più esterno di cui desideri una schermata di:

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
Questo sembra essere un codice più pulito della risposta accettata. Si esibisce anche?
jophde,

2
L'ho usato per un po 'in alcune app diverse e non ho avuto problemi.
JustinMorris,

3
Se vuoi ottenere uno screenshot del telefono, in cui la tua app è in background, cosa passi come view? `
AlikElzin-kilaka,

2
Passando getWindow().getDecorView().getRootView()come vista si ottiene uno screenshot della sola app, non dello schermo.
AlikElzin-Kilaka

Questa risposta prende uno screenshot solo dell'app, non dello "schermo del telefono" come richiesto nella domanda - o sto facendo qualcosa di sbagliato.
AlikElzin-Kilaka,

42

Nota: funziona solo per il telefono rootato

A livello di programmazione, è possibile eseguire adb shell /system/bin/screencap -p /sdcard/img.pngcome di seguito

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

quindi leggi img.pngcome Bitmape usa come desideri.


È necessario l'accesso come root?
zoom

3
Sì, è necessario l'accesso come root. Si prega di controllare la nota alla voce
Viswanath Lekshmanan,

Ciao, ho un System.err : java.io.IOException: Error running exec(). Command: [su] Working Directory: null Environment: null , il mio dispositivo è Android 5.0
Eddy,

@Eddy Dipende dal tuo dispositivo
Demian

C'è un modo per leggere direttamente l'output senza salvare il risultato in un file e poi rileggerlo? stackoverflow.com/questions/43914035
Yazan W Yusuf,

35

EDIT: abbi pietà dei downvotes. Era vero nel 2010 quando ho risposto alla domanda.

Tutti i programmi che consentono schermate funzionano solo su telefoni con root.


Sembra che in questi giorni sia possibile sugli Androidi con chipset basato su Tegra
RDT

4.0.3 - quindi è probabilmente una di queste compresse tegra di nuova scuola
RDT

AFAIK quando i dispositivi hanno un'app stock per catturare schermate è un'app con privilegi di firma speciali che le consentono di catturare il framebuffer (un buffer con contiene i pixel dello schermo). Quindi è vero, se la tua ROM ha una tale app, non avrai bisogno di eseguire il root, ma solo quell'app può effettuare acquisizioni, non la tua.
Rui Marques,

2
A rigor di termini, insieme all'account utente "shell" di ADB di root ha sempre avuto il permesso di farlo poiché quello era il caso d'uso previsto. Ciò che non era storicamente disponibile (ad eccezione di build occasionali come errore) era un modo per gli ID utente dell'applicazione di farlo.
Chris Stratton,

26

Per questo metodo non sono richiesti permessi di root o grandi codifiche .


Sulla shell adb usando il comando qui sotto puoi fare uno screenshot.

input keyevent 120

Questo comando non richiede alcun permesso di root, quindi puoi eseguire lo stesso anche dal codice java dell'applicazione Android.

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

Maggiori informazioni sul codice keyevent in Android vedi http://developer.android.com/reference/android/view/KeyEvent.html

Qui abbiamo usato. KEYCODE_SYSRQ il suo valore è 120 e utilizzato per il tasto Richiesta sistema / Stampa schermo.


Come ha detto CJBS, l'immagine in uscita verrà salvata in / sdcard / Pictures / Screenshot


L'immagine in uscita verrà salvata qui:/sdcard/Pictures/Screenshots
CJBS,

richiede il permesso di root ??
Taranmeet Singh,

1
funzionerà su marshmallow? o funzionerà in background di servizio @JeegarPatel
karanatwal.github.io

2
non ha funzionato a livello di codice, ma funziona dalla shell. Provato con torrone.
mehmet6parmak,

1
su -c "input keyevent 120"va bene !!
ipcjs,

17

La risposta di Mualig è molto buona, ma ho avuto lo stesso problema descritto da Ewoks, non sto ottenendo lo sfondo. Quindi a volte è abbastanza buono ea volte ottengo testo nero su sfondo nero (a seconda del tema).

Questa soluzione è fortemente basata sul codice Mualig e sul codice che ho trovato in Robotium. Sto scartando l'uso del disegno cache chiamando direttamente il metodo draw. Prima cercherò di ottenere lo sfondo disegnabile dall'attività corrente per disegnarlo per primo.

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

Ho una visualizzazione elenco con Android: cacheColorHint = "# 00000000" nella mia attività e utilizzo questo codice per screenshot, ho ancora uno sfondo nero, perché ho scoperto che lo sfondo che arriva dal tema è nero, come posso gestirlo visualizzazione elenco?
Wangchao0721,

Attività attività = getCurrentActivity che fornisce il metodo Eroor non definito.
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();
    }
}

Aggiungi l'autorizzazione nel manifest

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

Per supportare Marshmallow o versioni precedenti, si prega di aggiungere il codice seguente nel metodo onCreate attività

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

Richiede: <usi-permesso android: nome = "android.permission.WRITE_EXTERNAL_STORAGE" />
Android Acquista

4
Questa risposta prende uno screenshot solo dell'app, non dello "schermo del telefono" come richiesto nella domanda - o sto facendo qualcosa di sbagliato?
AlikElzin-Kilaka,

Che dire se ho bisogno di uno screenshot di un elemento di listview?
Anshul Tyagi,

voglio catturare dall'adattatore qualche idea su come posso farlo?
Deep Dave,

16

Come riferimento, un modo per catturare lo schermo (e non solo l'attività della tua app) è catturare il framebuffer (device / dev / graphics / fb0). Per fare ciò devi avere i privilegi di root o la tua app deve essere un'app con permessi di firma ("Un'autorizzazione che il sistema concede solo se l'applicazione richiedente è firmata con lo stesso certificato dell'applicazione che ha dichiarato l'autorizzazione") - che è molto improbabile a meno che tu non abbia compilato la tua ROM.

Ogni acquisizione di framebuffer, da un paio di dispositivi che ho testato, conteneva esattamente uno screenshot. La gente ha segnalato che ne contiene di più, immagino che dipenda dalla dimensione del frame / display.

Ho provato a leggere continuamente il framebuffer ma sembra tornare per un numero fisso di byte letti. Nel mio caso si tratta di (3 410 432) byte, che è sufficiente per memorizzare un frame di visualizzazione di 854 * 480 RGBA (3 279 360 byte). Sì, il frame, in binario, emesso da fb0 è RGBA nel mio dispositivo. Molto probabilmente questo dipenderà da dispositivo a dispositivo. Questo sarà importante per te decodificarlo =)

Nel mio dispositivo / dev / graphics / fb0 le autorizzazioni sono in modo che solo root e gli utenti della grafica di gruppo possano leggere l'fb0.

la grafica è un gruppo limitato, quindi probabilmente accederai a fb0 solo con un telefono rootato usando il comando su.

Le app Android hanno l' id utente (uid) = app _ ## e l' id gruppo (guid) = app _ ## .

adb shell ha uid = shell e guid = shell , che ha molte più autorizzazioni di un'app. Puoi effettivamente controllare tali permessi su /system/permissions/platform.xml

Questo significa che sarai in grado di leggere fb0 nella shell adb senza root ma non lo leggerai all'interno dell'app senza root.

Inoltre, concedere le autorizzazioni READ_FRAME_BUFFER e / o ACCESS_SURFACE_FLINGER su AndroidManifest.xml non farà nulla per un'app normale perché funzioneranno solo con app di ' firma '.

Controlla anche questa discussione chiusa per maggiori dettagli.


2
Funziona (funzionava?) Su alcuni telefoni, ma nota che i telefoni basati su GPU non forniscono necessariamente un framebuffer lineare al processore delle applicazioni.
Chris Stratton,

15

La mia soluzione è:

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

e

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

Le immagini vengono salvate nella cartella di archiviazione esterna.


1
È necessario chiudere FileOutputStream in un blocco finally. Se si riscontra un'eccezione, lo stream non verrà chiuso.
Wotuu,

A cosa viewstai passando ImageUtils.loadBitmapFromView(this, view)?
AlikElzin-Kilaka,

1
perché usi v.layout (0, 0, v.getMeasuredWidth (), v.getMeasuredHeight ()); ? Questo non cambia la vista (v)?
serj

11

Puoi provare la seguente libreria: http://code.google.com/p/android-screenshot-library/ Android Screenshot Library (ASL) consente di acquisire a livello di codice schermate da dispositivi Android senza la necessità di disporre dei privilegi di accesso root. Invece, ASL utilizza un servizio nativo in esecuzione in background, avviato tramite Android Debug Bridge (ADB) una volta all'avvio del dispositivo.


1
Ho provato questo. Ma ci vuole solo lo screenshot dell'app in esecuzione. Non può aiutare se voglio fare uno screenshot alla schermata iniziale. come fare uno screenshot della schermata iniziale con quel codice?
Jana,

1
@ Janardhanan.S: questo è ciò che la domanda sta ponendo. Puoi elaborare una nuova risposta invece di porre una domanda separata.
trgraglia,

3
Lo stesso problema con me .. "Servizio nativo non in esecuzione !!"
Yogesh Maheshwari,

1
Lo stesso con me "Servizio nativo non in esecuzione !!" .... qualcuno può aggiungere il testo di aiuto qui?
Pankaj Kumar,

1
anch'io! "Servizio nativo non in esecuzione !!" e nella loro ultima versione 1.2 usano le classi API LEVEL 19, come ad esempio Socket.
user347187,

10

Sulla base della risposta di @JustinMorris sopra e @NiravDangi qui https://stackoverflow.com/a/8504958/2232148 dobbiamo prendere lo sfondo e il primo piano di una vista e assemblarli in questo modo:

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

Il parametro quality accetta una costante di Bitmap.Config, in genere o Bitmap.Config.RGB_565o Bitmap.Config.ARGB_8888.


disegnare tela con il colore bianco nel caso in cui lo sfondo sia nullo ha fatto il trucco per me. Grazie Oliver
Shaleen il

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

}

AGGIUNGI PERMESSO

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

Questa risposta prende uno screenshot solo dell'app, non dello "schermo del telefono" come richiesto nella domanda - o sto facendo qualcosa di sbagliato?
AlikElzin-Kilaka,

7

Puoi provare a fare qualcosa del genere,

Ottenere una cache bitmap da un layout o una vista facendo qualcosa come First Devi setDrawingCacheEnabledandare a un layout (un linearlayout o relativelayout o una vista)

poi

Bitmap bm = layout.getDrawingCache()

Quindi fai quello che vuoi con la bitmap. O trasformandolo in un file immagine, o invia l'uri della bitmap da qualche altra parte.


1
Questo è il metodo migliore se è la tua app che stai scrivendo su una bitmap. Inoltre, fai attenzione ai metodi che presentano ritardi prima di utilizzare la cache ... come Notifica ... () per le visualizzazioni elenco.
trgraglia,

Non solo quello. Il layout deve essere prima visualizzato sullo schermo. È la "cache" che stai ricevendo dopotutto. Ho provato a nascondere la vista e scattare schermate in background (in teoria), ma non ha funzionato.
Kevin Tan,

Di gran lunga più efficiente di altre soluzioni
sivi il

6

Per coloro che desiderano acquisire un GLSurfaceView, il metodo getDrawingCache o disegno su tela non funzionerà.

Devi leggere il contenuto del framebuffer OpenGL dopo il rendering del frame. C'è una buona risposta qui


6

Ho creato una semplice libreria che prende uno screenshot da un Viewe ti dà un oggetto Bitmap o lo salva direttamente in qualsiasi percorso tu voglia

https://github.com/abdallahalaraby/Blink


Richiede un telefono con root?
Nilesh Agrawal,

1
Non è richiesto il
root

Durante l'utilizzo Screenshot.takeScreenshot(view, mPath); imageView.setImageBitmap(Screenshot.getBitmapScreenshot(view, mPath)); hai menzionato Come visualizzare l'attività corrente. Non voglio usare l'id dell'xml.
Nilesh Agrawal,

usa takeScreenshotForScreen()invece.
Abdallah Alaraby,

6

La via breve è

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

5

Sto solo estendendo la risposta di Taraloca. È necessario aggiungere le seguenti righe per farlo funzionare. Ho reso statico il nome dell'immagine. Assicurati di utilizzare la variabile timestamp di taraloca in caso tu abbia bisogno di un nome immagine dinamico.

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

E nel file AndroidManifest.xml sono necessarie le seguenti voci:

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

4

Se vuoi fare uno screenshot da allora fragment segui questo:

  1. Ignora 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. Logica per fare screenshot:

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

Per l'attività puoi semplicemente usare View v1 = getWindow().getDecorView().getRootView();invece dimView


3

La maggior parte delle risposte a questa domanda utilizza il Canvasmetodo di disegno o il metodo cache di disegno. Tuttavia, il View.setDrawingCache()metodo è obsoleto nell'API 28 . Attualmente l'API consigliata per creare schermate è la PixelCopyclasse disponibile da API 24 (ma i metodi che accettano i Windowparametri sono disponibili da API 26 == Android 8.0 Oreo). Ecco un esempio di codice Kotlin per il recupero di 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
        }
    }
}

Il problema con PixelCopy sulla soluzione drawingCache è che sembra catturare solo pixel visibili. il resto è nero per me. Quindi non è possibile condividere elementi che sono scorrevoli ed è parzialmente fuori dalla cornice. Hai una soluzione per questo?
Henning

Hai ragione. Allo stesso modo può causare un problema se viene visualizzata un'altra vista sopra la vista che voglio fare screenshot (ad esempio quando il cassetto è aperto). In questi casi uso solo il vecchio metodo Canvas :(
Miloš Černilovský

1
È possibile fare screenshot su qualsiasi app in esecuzione usando PixelCopy?
Amir Rezaei,

2

Solo per applicazioni di sistema!

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

Nota: le applicazioni di sistema non devono eseguire "su" per eseguire questo comando.


2

La vista parametri è l'oggetto di layout principale.

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

Schermata di scorrimento a pagina intera

Se vuoi catturare uno screenshot di visualizzazione completa (che contiene una vista di scorrimento o giù di lì), controlla in questa libreria

https://github.com/peter1492/LongScreenshot

Tutto quello che devi fare è importare Gradel e creare un oggetto di BigScreenshot

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

Verrà ricevuto un callback con la bitmap degli screenshot acquisiti mentre si scorre automaticamente il gruppo di visualizzazione dello schermo e alla fine assemblati insieme.

@Override public void getScreenshot(Bitmap bitmap) {}

Che possono essere salvati nella galleria o qualsiasi utilizzo è necessario il loro dopo


1

Cattura uno screenshot di una vista in 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

se vuoi catturare una vista o un layout come RelativeLayout o LinearLayout ecc. usa semplicemente il codice:

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

ora puoi salvare questa bitmap sulla memoria 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();}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.