Wie mache ich programmgesteuert einen Screenshot auf Android?

495

Wie kann ich einen Screenshot eines ausgewählten Bereichs des Telefonbildschirms nicht mit einem Programm, sondern mit Code erstellen?

korovaisdead
quelle
4
Nicht vom Emulator. Ich muss einen Screenshot eines Teils meines Programms machen und damit im selben Programm etwas machen.
Korovaisdead
1
Eine weitere gute Referenz: stackoverflow.com/a/10296881/439171
Italo Borssatto

Antworten:

448

Hier ist der Code, mit dem mein Screenshot auf einer SD-Karte gespeichert und später für alle Ihre Anforderungen verwendet werden konnte:

Zunächst müssen Sie eine entsprechende Berechtigung hinzufügen, um die Datei zu speichern:

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

Und dies ist der Code (der in einer Aktivität ausgeführt wird):

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

Und so können Sie das kürzlich generierte Bild öffnen:

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

Wenn Sie dies in der Fragmentansicht verwenden möchten, verwenden Sie:

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

anstatt

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

auf takeScreenshot () Funktion

Hinweis :

Diese Lösung funktioniert nicht, wenn Ihr Dialogfeld eine Oberflächenansicht enthält. Für Details überprüfen Sie bitte die Antwort auf die folgende Frage:

Android Screenshot der Oberflächenansicht zeigt schwarzen Bildschirm

Taraloca
quelle
23
Hallo, kannst du beschreiben, was mCurrentUrlMask ist? Ich habe diesen Code ausprobiert, aber er gibt mir immer eine NullPointerException bei Bitmap.createBitmap (v1.getDrawingCache ()). Kann jemand sagen, was ich falsch mache? Jede Hilfe wird geschätzt. Vielen Dank.
Mitesh Sardhara
4
@MiteshSardhara mCurrentUrlMaskmuss eine Vieweindeutige Klasse in der Android-API sein, die über die getRootView()Methode verfügt. Wahrscheinlich ist eine Ansicht in der Benutzeroberfläche.
Gipi
6
Können Sie mir bitte sagen, was mCurrentUrlMask ist?
Jayeshkumar Sojitra
37
Insted von habe View v1 = mCurrentUrlMask.getRootView();ich verwendet View v1 = getWindow().getDecorView().getRootView();und es funktioniert für mich.
Enadun
9
Diese Antwort macht nur einen Screenshot der App - nicht des in der Frage gestellten "Telefonbildschirms" - oder mache ich etwas falsch.
AlikElzin-Kilaka
126

Rufen Sie diese Methode auf und übergeben Sie die äußerste ViewGroup, von der Sie einen Screenshot erhalten möchten:

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;
}
Justin Morris
quelle
9
Dies scheint ein sauberer Code zu sein als die akzeptierte Antwort. Funktioniert es auch?
Jophde
2
Ich habe es eine Weile in verschiedenen Apps verwendet und hatte keine Probleme.
Justin Morris
3
Wenn Sie einen Screenshot des Telefons erhalten möchten, auf dem sich Ihre App im Hintergrund befindet, was übergeben Sie als view? `
AlikElzin-kilaka
2
Wenn Sie getWindow().getDecorView().getRootView()die Ansicht übergeben, wird nur ein Screenshot der App erstellt - nicht des Bildschirms.
AlikElzin-Kilaka
Diese Antwort macht nur einen Screenshot der App - nicht des in der Frage gestellten "Telefonbildschirms" - oder mache ich etwas falsch.
AlikElzin-Kilaka
42

Hinweis: Funktioniert nur für gerootete Telefone

Programmatisch können Sie adb shell /system/bin/screencap -p /sdcard/img.pngwie folgt ausführen

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

dann lesen Sie , img.pngwie Bitmapund verwenden wie Sie es wünschen.

Viswanath Lekshmanan
quelle
Benötigt es Root-Zugriff?
Zoom
3
Ja, Sie benötigen Root-Zugriff. Bitte überprüfen Sie die Anmerkung in der Überschrift
Viswanath Lekshmanan
Hallo, ich habe eine System.err : java.io.IOException: Error running exec(). Command: [su] Working Directory: null Environment: null , mein Gerät ist Android 5.0
Eddy
@ Eddie Es hängt von Ihrem Gerät ab
Demian
Gibt es eine Möglichkeit, die Ausgabe direkt zu lesen, ohne das Ergebnis in einer Datei zu speichern und dann erneut zu lesen? stackoverflow.com/questions/43914035
Yazan W Yusuf
35

EDIT: Erbarme dich der Abstimmungen. Es war 2010 wahr, als ich die Frage beantwortete.

Alle Programme, die Screenshots ermöglichen, funktionieren nur auf gerooteten Telefonen.

DDR
quelle
Es sieht so aus, als ob es heutzutage auf Androids mit Tegra-basiertem Chipsatz möglich ist
DDR
4.0.3 - dann ist es wahrscheinlich eines dieser Tegra-Tablets der neuen Schule
DDR
AFAIK Wenn Geräte über eine Standard-App zum Erfassen von Screenshots verfügen, handelt es sich um eine App mit speziellen Signaturberechtigungen, mit der der Framebuffer erfasst werden kann (ein Puffer mit den Bildschirmpixeln). Wenn Ihr ROM über eine solche App verfügt, müssen Sie also nicht gerootet sein, sondern nur diese App kann Captures erstellen, nicht Ihre.
Rui Marques
2
Genau genommen hatte das "Shell" -Nutzerkonto von root ADB immer die Erlaubnis, dies zu tun, da dies der beabsichtigte Anwendungsfall war. Was historisch nicht verfügbar war (außer bei gelegentlichen Builds als Fehler), war eine Möglichkeit für Anwendungsbenutzer- IDs, dies zu tun.
Chris Stratton
26

Für diese Methode ist keine Root-Berechtigung oder keine große Codierung erforderlich.


Auf der ADB-Shell können Sie mit dem folgenden Befehl einen Screenshot machen.

input keyevent 120

Für diesen Befehl ist keine Root-Berechtigung erforderlich, sodass Sie ihn auch über den Java-Code der Android-Anwendung ausführen können.

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

Weitere Informationen zum Keyevent-Code in Android finden Sie unter http://developer.android.com/reference/android/view/KeyEvent.html

Hier haben wir verwendet. KEYCODE_SYSRQ Der Wert ist 120 und wird für die Systemanforderungs- / Druckbildschirmtaste verwendet.


Wie CJBS sagte, wird das Ausgabebild in / sdcard / Pictures / Screenshots gespeichert

Jeegar Patel
quelle
Das Ausgabebild wird hier gespeichert:/sdcard/Pictures/Screenshots
CJBS
Benötigt es Root-Berechtigung?
Taranmeet Singh
1
wird es auf Marshmallow funktionieren? oder wird es im Service-Hintergrund funktionieren @JeegarPatel
karanatwal.github.io
2
nicht programmgesteuert gearbeitet, sondern aus der Shell. Versucht mit Nougat.
mehmet6parmak
1
su -c "input keyevent 120"ist in Ordnung!!
ipcjs
17

Die Antwort von Mualig ist sehr gut, aber ich hatte das gleiche Problem, das Ewoks beschreibt. Ich verstehe den Hintergrund nicht. Manchmal ist es also gut genug und manchmal bekomme ich schwarzen Text über schwarzem Hintergrund (je nach Thema).

Diese Lösung basiert stark auf Mualig-Code und dem Code, den ich in Robotium gefunden habe. Ich verwerfe die Verwendung des Zeichencaches, indem ich direkt die Zeichenmethode aufrufe. Vorher werde ich versuchen, den Hintergrund aus der aktuellen Aktivität zu zeichnen, um ihn zuerst zu zeichnen.

// 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
quelle
Ich habe eine Listenansicht mit android: cacheColorHint = "# 00000000" in meiner Aktivität, und ich verwende diesen Code für Screenshots. Ich habe immer noch einen schwarzen Hintergrund, da ich festgestellt habe, dass der Hintergrund, der vom Thema stammt, schwarz ist. Wie kann ich damit umgehen? Listenansicht?
Wangchao0721
Aktivität Aktivität = getCurrentActivity gibt Eroor undefinierte Methode.
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();
    }
}

Fügen Sie die Berechtigung im Manifest hinzu

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

Fügen Sie zur Unterstützung von Marshmallow oder höheren Versionen den folgenden Code in die Aktivität onCreate-Methode ein

ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},00);
Verrückter Codierer
quelle
Benötigt: <Verwendet-Erlaubnis android: name = "android.permission.WRITE_EXTERNAL_STORAGE" />
AndroidGuy
4
Diese Antwort macht nur einen Screenshot der App - nicht des in der Frage gestellten "Telefonbildschirms" - oder mache ich etwas falsch?
AlikElzin-Kilaka
Was ist, wenn ich einen Screenshot eines Listenansichtsobjekts benötige?
Anshul Tyagi
Ich möchte vom Adapter eine Idee erfassen, wie ich es tun kann.
Deep Dave
16

Als Referenz besteht eine Möglichkeit, den Bildschirm (und nicht nur Ihre App-Aktivität) zu erfassen, darin, den Framebuffer (Gerät / dev / Grafik / fb0) zu erfassen . Dazu müssen Sie entweder über Root-Rechte verfügen oder Ihre App muss eine App mit Signaturberechtigungen sein ("Eine Berechtigung, die das System nur erteilt, wenn die anfordernde Anwendung mit demselben Zertifikat signiert ist wie die Anwendung, die die Berechtigung deklariert hat") Sehr unwahrscheinlich, es sei denn, Sie haben Ihr eigenes ROM kompiliert.

Jede Framebuffer-Erfassung von einigen Geräten, die ich getestet habe, enthielt genau einen Screenshot. Die Leute haben berichtet, dass es mehr enthält, ich denke, es hängt von der Rahmen- / Anzeigegröße ab.

Ich habe versucht, den Framebuffer kontinuierlich zu lesen, aber er scheint für eine feste Anzahl gelesener Bytes zurückzukehren. In meinem Fall sind das (3 410 432) Bytes, was ausreicht, um einen Anzeigerahmen von 854 * 480 RGBA (3 279 360 Bytes) zu speichern. Ja, der von fb0 ausgegebene Frame in Binärform ist RGBA in meinem Gerät. Dies hängt höchstwahrscheinlich von Gerät zu Gerät ab. Dies ist wichtig für Sie, um es zu dekodieren =)

In meinem Gerät / dev / graphics / fb0 sind die Berechtigungen so, dass nur root und Benutzer aus Gruppengrafiken die fb0 lesen können.

Grafik ist eine eingeschränkte Gruppe, daher werden Sie wahrscheinlich nur mit einem gerooteten Telefon mit dem Befehl su auf fb0 zugreifen.

Android-Apps haben die Benutzer-ID (uid) = app _ ## und die Gruppen- ID (guid) = app _ ## .

Die adb-Shell verfügt über uid = shell und guid = shell , die viel mehr Berechtigungen als eine App haben. Sie können diese Berechtigungen tatsächlich unter /system/permissions/platform.xml überprüfen

Dies bedeutet, dass Sie fb0 in der ADB-Shell ohne Root lesen können, aber nicht in der App ohne Root.

Wenn Sie READ_FRAME_BUFFER- und / oder ACCESS_SURFACE_FLINGER-Berechtigungen für AndroidManifest.xml erteilen, funktioniert dies für eine reguläre App nicht, da diese nur für Signatur -Apps funktionieren .

Überprüfen Sie auch diesen geschlossenen Thread für weitere Details.

Rui Marques
quelle
2
Dies funktioniert auf einigen Telefonen (funktioniert?). Beachten Sie jedoch, dass GPU-basierte Telefone dem Anwendungsprozessor nicht unbedingt einen linearen Framebuffer zur Verfügung stellen.
Chris Stratton
15

Meine Lösung ist:

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

und

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

Bilder werden im externen Speicherordner gespeichert.

gültige Katze
quelle
1
Sie sollten den FileOutputStream in einem finally-Block schließen. Wenn Sie jetzt auf eine Ausnahme stoßen, wird der Stream nicht geschlossen.
Wotuu
An was viewgehst du ImageUtils.loadBitmapFromView(this, view)?
AlikElzin-Kilaka
1
Warum verwenden Sie v.layout (0, 0, v.getMeasuredWidth (), v.getMeasuredHeight ())? ? Ändert das nicht die Ansicht (v)?
Serj
11

Sie können die folgende Bibliothek ausprobieren: http://code.google.com/p/android-screenshot-library/ Mit der Android Screenshot Library (ASL) können Screenshots von Android-Geräten programmgesteuert erfasst werden, ohne dass Root-Zugriffsrechte erforderlich sind. Stattdessen verwendet ASL einen nativen Dienst, der im Hintergrund ausgeführt wird und einmal pro Gerätestart über die Android Debug Bridge (ADB) gestartet wird.

Kuba
quelle
1
Ich habe es versucht. Aber es macht nur einen Screenshot der laufenden App. Es kann nicht helfen, wenn ich einen Screenshot des Homescreens machen möchte. Wie macht man einen Screenshot des Homescreens mit diesem Code?
Jana
1
@ Janardhanan.S: Darum geht es in der Frage. Können Sie eine neue Antwort erarbeiten, anstatt eine separate Frage zu stellen?
Trgraglia
3
Gleiches Problem mit mir .. "Native Service läuft nicht !!"
Yogesh Maheshwari
1
Das gleiche gilt für mich "Native Service läuft nicht !!" .... kann hier jemand den Hilfetext hinzufügen?
Pankaj Kumar
1
hier gilt das gleiche! "Native Service läuft nicht !!" und in ihrer neuesten Version 1.2 verwenden sie API LEVEL 19-Klassen, wie zum Beispiel Socket.
user347187
10

Basierend auf der Antwort von @JustinMorris oben und @NiravDangi hier https://stackoverflow.com/a/8504958/2232148 müssen wir den Hintergrund und den Vordergrund einer Ansicht nehmen und sie wie folgt zusammenstellen:

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

Der Qualitätsparameter nimmt eine Konstante von Bitmap.Config an, normalerweise entweder Bitmap.Config.RGB_565oder Bitmap.Config.ARGB_8888.

Oliver Hausler
quelle
Das Zeichnen einer Leinwand mit weißer Farbe für den Fall, dass der Hintergrund null ist, hat den Trick für mich getan. Vielen Dank 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();
}

}

ERLAUBNIS HINZUFÜGEN

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Vaishali Sutariya
quelle
Diese Antwort macht nur einen Screenshot der App - nicht des in der Frage gestellten "Telefonbildschirms" - oder mache ich etwas falsch?
AlikElzin-Kilaka
7

Sie können versuchen, so etwas zu tun,

Abrufen eines Bitmap-Cache aus einem Layout oder einer Ansicht, indem Sie beispielsweise "Zuerst müssen Sie" ausführen setDrawingCacheEnabled Folgendes ausführen: ein Layout erstellen (ein lineares Layout oder ein relatives Layout oder eine Ansicht).

dann

Bitmap bm = layout.getDrawingCache()

Dann machen Sie mit der Bitmap, was Sie wollen. Entweder verwandeln Sie es in eine Bilddatei oder senden Sie die Uri der Bitmap an einen anderen Ort.

Kevin Tan
quelle
1
Dies ist die beste Methode, wenn Sie Ihre App auf eine Bitmap schreiben. Achten Sie auch auf Methoden, bei denen es zu Verzögerungen kommt, bevor Sie den Cache belegen ... wie Notify ... () für Listenansichten.
Trgraglia
Nicht nur, dass. Das Layout muss zuerst auf dem Bildschirm angezeigt werden. Es ist der "Cache", den Sie immerhin bekommen. Ich habe versucht, die Ansicht zu verbergen und Screenshots im Hintergrund zu machen (theoretisch), aber es hat nicht funktioniert.
Kevin Tan
Weitaus effizienter als andere Lösungen
Sivi
6

Für diejenigen, die eine GLSurfaceView erfassen möchten, funktioniert die Methode getDrawingCache oder Zeichnen auf Leinwand nicht.

Sie müssen den Inhalt des OpenGL-Framebuffers lesen, nachdem der Frame gerendert wurde. Es gibt eine gute Antwort hier

Rockeye
quelle
6

Ich habe eine einfache Bibliothek erstellt, die einen Screenshot von einem macht View und Ihnen entweder ein Bitmap-Objekt gibt oder es direkt in einem beliebigen Pfad speichert

https://github.com/abdallahalaraby/Blink

Abdallah Alaraby
quelle
Benötigt es ein gerootetes Telefon?
Nilesh Agrawal
1
Kein Rooting erforderlich :)
Abdallah Alaraby
In der Verwendung wurde erwähnt, Screenshot.takeScreenshot(view, mPath); imageView.setImageBitmap(Screenshot.getBitmapScreenshot(view, mPath)); wie Sie einen Überblick über die aktuelle Aktivität erhalten. Ich möchte nicht die ID der XML verwenden.
Nilesh Agrawal
Verwenden Sie takeScreenshotForScreen()stattdessen.
Abdallah Alaraby
6

Kurzer Weg ist

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

Nur Taralocas Antwort erweitern. Sie müssen folgende Zeilen hinzufügen, damit es funktioniert. Ich habe den Bildnamen statisch gemacht. Stellen Sie sicher, dass Sie die Zeitstempelvariable von taraloca verwenden, falls Sie einen dynamischen Bildnamen benötigen.

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

Und in der Datei AndroidManifest.xml müssen folgende Einträge vorhanden sein:

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

Wenn Sie einen Screenshot von machen möchten, gehen Sie fragment wie folgt vor:

  1. Überschreiben 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. Logik zum Screenshot:

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

Für Aktivitäten können Sie einfach View v1 = getWindow().getDecorView().getRootView();anstelle von verwendenmView

Parsania Hardik
quelle
3

Die meisten Antworten auf diese Frage verwenden die CanvasZeichenmethode oder die Zeichencache-Methode. Die View.setDrawingCache()Methode ist jedoch in API 28 veraltet . Derzeit ist die empfohlene API zum Erstellen von Screenshots die PixelCopyvon API 24 verfügbare Klasse (die Methoden, die WindowParameter akzeptieren , sind jedoch von API 26 == Android 8.0 Oreo verfügbar). Hier ist ein Beispiel für einen Kotlin-Code zum Abrufen eines 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ý
quelle
Das Problem mit PixelCopy über die DrawingCache-Lösung ist, dass nur sichtbare Pixel erfasst werden. der Rest ist schwarz für mich. Es ist also nicht möglich, Dinge zu teilen, die scrollbar sind und teilweise außerhalb des Rahmens liegen. Haben Sie eine Lösung dafür?
Henning
Du hast recht. Ebenso kann es zu einem Problem kommen, wenn eine andere Ansicht über der Ansicht angezeigt wird, die ich scannen möchte (z. B. wenn die Schublade geöffnet ist). In diesen Fällen verwende ich nur die alte Canvas-Methode :(
Miloš Černilovský
1
Ist es möglich, mit PixelCopy einen Screenshot auf einer laufenden App zu machen?
Amir Rezaei
2

Nur für Systemanwendungen!

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

Hinweis: Systemanwendungen müssen "su" nicht ausführen, um diesen Befehl auszuführen.

GilCol
quelle
2

Die Parameteransicht ist das Stammlayoutobjekt.

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
quelle
2

Für einen ganzseitigen Bildlauf-Screenshot

Wenn Sie einen vollständigen Screenshot der Ansicht (der eine Bildlaufansicht oder so enthält) aufnehmen möchten, überprüfen Sie diese Bibliothek

https://github.com/peter1492/LongScreenshot

Sie müssen lediglich Gradel importieren und ein Objekt von BigScreenshot erstellen

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

Ein Rückruf wird mit der Bitmap der aufgenommenen Screenshots empfangen, während automatisch durch die Bildschirmansichtsgruppe gescrollt und am Ende zusammengesetzt wird.

@Override public void getScreenshot(Bitmap bitmap) {}

Welche in der Galerie gespeichert werden können oder welche Verwendung auch immer benötigt wird, ist deren Nachbearbeitung erforderlich

Peter
quelle
1

Machen Sie einen Screenshot einer Ansicht 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;
}
Mohit Singh
quelle
-1

Wenn Sie eine Ansicht oder ein Layout wie RelativeLayout oder LinearLayout usw. erfassen möchten, verwenden Sie einfach den folgenden Code:

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

Jetzt können Sie diese Bitmap im Gerätespeicher speichern, indem Sie:

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
quelle