Jak programowo zrobić zrzut ekranu na Androida?

Odpowiedzi:

448

Oto kod, który pozwolił mi zapisać mój zrzut ekranu na karcie SD i wykorzystać go później do jakichkolwiek potrzeb:

Najpierw musisz dodać odpowiednie uprawnienie do zapisania pliku:

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

A to jest kod (działający w działaniu):

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

I w ten sposób możesz otworzyć ostatnio wygenerowany obraz:

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

Jeśli chcesz użyć tego w widoku fragmentu, użyj:

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

zamiast

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

na funkcji takeScreenshot ()

Uwaga :

To rozwiązanie nie działa, jeśli okno dialogowe zawiera widok powierzchni. Aby uzyskać szczegółowe informacje, sprawdź odpowiedź na następujące pytanie:

Android Zrzut ekranu z widoku powierzchni pokazuje czarny ekran

taraloca
źródło
23
Cześć, Czy możesz opisać, co to jest mCurrentUrlMask? Próbowałem tego kodu, ale zawsze daje mi wyjątek NullPointerException w Bitmap.createBitmap (v1.getDrawingCache ()). Czy ktoś może powiedzieć, co robię źle.? Każda pomoc jest mile widziana. Dzięki.
Mitesh Sardhara
4
@MiteshSardhara mCurrentUrlMaskmusi być Viewodkąd jest unikalną klasą w interfejsie API Androida, która ma tę getRootView()metodę. Prawdopodobnie jest to widok w interfejsie użytkownika.
gipi
6
Czy możesz mi powiedzieć, co to jest, mCurrentUrlMask?
Jayeshkumar Sojitra
37
Insted View v1 = mCurrentUrlMask.getRootView();użyłem View v1 = getWindow().getDecorView().getRootView();i to działa dla mnie.
enadun
9
Ta odpowiedź zawiera zrzut ekranu samej aplikacji - a nie „ekranu telefonu” zadanego w pytaniu - lub robię coś złego.
AlikElzin-kilaka
126

Wywołaj tę metodę, przekazując najbardziej zewnętrzną grupę ViewGroup, z której chcesz zrzut ekranu:

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
źródło
9
To wydaje się być czystszym kodem niż zaakceptowana odpowiedź. Czy to też działa?
jophde
2
Używałem go przez jakiś czas w kilku różnych aplikacjach i nie miałem żadnych problemów.
JustinMorris,
3
Jeśli chcesz uzyskać zrzut ekranu telefonu, w którym aplikacja jest w tle, co podajesz jako view? '
AlikElzin-kilaka
2
Przekazywanie getWindow().getDecorView().getRootView()jako widok powoduje wykonanie zrzutu ekranu samej aplikacji - nie ekranu.
AlikElzin-kilaka
Ta odpowiedź zawiera zrzut ekranu samej aplikacji - a nie „ekranu telefonu” zadanego w pytaniu - lub robię coś złego.
AlikElzin-kilaka
42

Uwaga: działa tylko dla zrootowanego telefonu

Programowo możesz uruchomić adb shell /system/bin/screencap -p /sdcard/img.pngjak poniżej

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

następnie przeczytaj img.pngjako Bitmapi użyj według własnego uznania.

Viswanath Lekshmanan
źródło
Czy potrzebuje dostępu do roota?
powiększenie
3
Tak, potrzebujesz dostępu do roota. Proszę sprawdzić uwagę przy nagłówku
Viswanath Lekshmanan
Cześć, mam System.err : java.io.IOException: Error running exec(). Command: [su] Working Directory: null Environment: null , moje urządzenie to Android 5.0
Eddy
@Eddy To zależy od twojego urządzenia
Demian
Czy istnieje sposób na bezpośrednie odczytanie wyniku bez zapisywania wyniku w pliku, a następnie ponowne odczytanie? stackoverflow.com/questions/43914035
Yazan W Yusuf
35

EDYCJA: zmiłuj się nad głosującymi. Tak było w 2010 roku, kiedy odpowiedziałem na pytanie.

Wszystkie programy zezwalające na zrzuty ekranu działają tylko na zrootowanych telefonach.

NRD
źródło
Wygląda na to, że w dzisiejszych czasach jest to możliwe na Androidach z chipsetem opartym na Tegra
NRD
4.0.3 - to prawdopodobnie jeden z tych nowych szkolnych tabletów Tegra
NRD
AFAIK, gdy urządzenia mają standardową aplikację do przechwytywania zrzutów ekranu, jest to aplikacja ze specjalnymi uprawnieniami do podpisywania, która pozwala przechwytywać bufor ramki (bufor zawierający piksele ekranu). Więc to prawda, jeśli twoja pamięć ROM ma taką aplikację, nie będziesz musiał być zrootowany, ale tylko ta aplikacja może przechwytywać, a nie twoja.
Rui Marques,
2
Ściśle mówiąc, wraz z kontem użytkownika „powłoki” root ADB zawsze miało na to pozwolenie, ponieważ taki był zamierzony przypadek użycia. To, co nie było w przeszłości dostępne (z wyjątkiem sporadycznych kompilacji jako pomyłki), było sposobem na to, aby identyfikator użytkownika aplikacji to zrobił.
Chris Stratton
26

Ta metoda nie wymaga uprawnień administratora ani dużego kodowania .


W powłoce adb za pomocą poniższego polecenia możesz zrobić zrzut ekranu.

input keyevent 120

To polecenie nie wymaga żadnych uprawnień roota, więc możesz wykonać je również z kodu Java aplikacji na Androida.

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

Więcej informacji o kluczowym kodzie w Androidzie można znaleźć na stronie http://developer.android.com/reference/android/view/KeyEvent.html

Tutaj wykorzystaliśmy. KEYCODE_SYSRQ jego wartość wynosi 120 i jest używana dla klucza żądania systemu / ekranu drukowania.


Jak powiedział CJBS, obraz wyjściowy zostanie zapisany w / sdcard / Pictures / Screenshots

Jeegar Patel
źródło
Obraz wyjściowy zostanie zapisany tutaj:/sdcard/Pictures/Screenshots
CJBS
czy to wymaga uprawnień roota?
Taranmeet Singh,
1
czy to działa na piance? czy będzie to działało w tle usługi @JeegarPatel
karanatwal.github.io
2
nie działał programowo, ale działa z powłoki. Próbowałem z nugatem.
mehmet6parmak
1
su -c "input keyevent 120"jest ok !!
ipcjs
17

Odpowiedź Mualiga jest bardzo dobra, ale miałem ten sam problem, który opisuje Ewoks, nie dostaję tła. Czasami więc jest wystarczająco dobry, a czasem pojawia się czarny tekst na czarnym tle (w zależności od tematu).

To rozwiązanie jest mocno oparte na kodzie Mualig i kodzie, który znalazłem w Robotium. Odrzucam użycie pamięci podręcznej rysowania, dzwoniąc bezpośrednio do metody rysowania. Wcześniej postaram się wyciągnąć tło z bieżącej aktywności, aby narysować je jako pierwsze.

// 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
źródło
Mam podgląd listy z Androidem: cacheColorHint = "# 00000000" w mojej działalności i używam tego kodu do zrzutów ekranu, nadal mam czarne tło, ponieważ znalazłem, że tło, które pochodzi z motywu, jest czarne, jak mogę sobie z tym poradzić widok listy?
Wangchao0721,
Działanie aktywność = getCurrentActivity podając Eroor niezdefiniowaną metodę.
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();
    }
}

Dodaj uprawnienie do manifestu

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

Aby obsługiwać Marshmallow lub nowsze wersje, dodaj poniższy kod w metodzie działania onCreate

ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},00);
Crazy Coder
źródło
Wymaga: <wykorzystuje-pozwolenie android: nazwa = "android.permission.WRITE_EXTERNAL_STORAGE" />
AndroidGuy
4
Ta odpowiedź zawiera zrzut ekranu samej aplikacji - a nie „ekranu telefonu” zadanego w pytaniu - czy robię coś złego?
AlikElzin-kilaka
Co jeśli potrzebuję zrzutu ekranu elementu widoku listy?
Anshul Tyagi,
chcę uchwycić z adaptera jakiś pomysł, jak to zrobić?
Deep Dave
16

Jako odniesienie, jednym ze sposobów przechwytywania ekranu (a nie tylko aktywności aplikacji) jest przechwycenie bufora ramki (device / dev / graphic / fb0). Aby to zrobić, musisz mieć uprawnienia administratora lub aplikacja musi być aplikacją z uprawnieniami do podpisu („Zezwolenie, które system przyznaje tylko wtedy, gdy wnioskująca aplikacja jest podpisana tym samym certyfikatem co aplikacja, która zadeklarowała pozwolenie”) - bardzo mało prawdopodobne, chyba że skompilowałeś własny ROM.

Każde przechwycenie bufora ramki, z kilku testowanych urządzeń, zawierało dokładnie jeden zrzut ekranu. Ludzie zgłaszali, że zawiera więcej, myślę, że zależy to od rozmiaru ramki / wyświetlacza.

Próbowałem ciągle czytać bufor ramki, ale wydaje się, że zwraca określoną ilość odczytanych bajtów. W moim przypadku jest to (3 410 432) bajtów, co wystarcza do przechowywania ramki wyświetlania 854 * 480 RGBA (3 279 360 bajtów). Tak, ramka w formacie binarnym wyprowadzana z fb0 to RGBA w moim urządzeniu. Najprawdopodobniej będzie to zależeć od urządzenia. Będzie to ważne, aby go zdekodować =)

W moim urządzeniu / dev / graphic / fb0 uprawnienia są tak, że tylko root i użytkownicy z grafiki grupowej mogą odczytać fb0.

grafika jest grupą ograniczoną, więc prawdopodobnie będziesz uzyskiwać dostęp do fb0 tylko przy użyciu zrootowanego telefonu za pomocą polecenia su.

Aplikacje na Androida mają identyfikator użytkownika (identyfikator użytkownika) = aplikacja _ ## i identyfikator grupy (identyfikator GUID) = aplikacja _ ## .

adb shell ma uid = shell i guid = shell , który ma znacznie więcej uprawnień niż aplikacja. Możesz faktycznie sprawdzić te uprawnienia na /system/permissions/platform.xml

Oznacza to, że będziesz mógł odczytać fb0 w powłoce adb bez roota, ale nie będziesz czytać jej w aplikacji bez rootowania.

Ponadto udzielenie uprawnień READ_FRAME_BUFFER i / lub ACCESS_SURFACE_FLINGER w AndroidManifest.xml nie zrobi nic w przypadku zwykłej aplikacji, ponieważ będą one działać tylko w przypadku aplikacji „ podpisowych ”.

Sprawdź także ten zamknięty wątek, aby uzyskać więcej informacji.

Rui Marques
źródło
2
Działa to (działało?) Na niektórych telefonach, ale należy pamiętać, że telefony oparte na GPU niekoniecznie zapewniają liniowy bufor ramki dla procesora aplikacji.
Chris Stratton
15

Moje rozwiązanie to:

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

i

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

Obrazy są zapisywane w folderze pamięci zewnętrznej.

validcat
źródło
1
Powinieneś zamknąć FileOutputStream w ostatnim bloku. Jeśli napotkasz wyjątek, strumień nie zostanie zamknięty.
Wotuu
Do viewczego przekazujesz ImageUtils.loadBitmapFromView(this, view)?
AlikElzin-kilaka
1
dlaczego używasz v.layout (0, 0, v.getMeasuredWidth (), v.getMeasuredHeight ()); ? Czy to nie zmienia widoku (v)?
serj
11

Możesz wypróbować następującą bibliotekę: http://code.google.com/p/android-screenshot-library/ Biblioteka zrzutów ekranu Androida (ASL) umożliwia programowe przechwytywanie zrzutów ekranu z urządzeń z Androidem bez konieczności posiadania uprawnień dostępu root. Zamiast tego ASL wykorzystuje natywną usługę działającą w tle, uruchamianą przez Android Debug Bridge (ADB) raz na urządzenie.

Kuba
źródło
1
Próbowałem tego. Ale wystarczy zrzut ekranu z uruchomionej aplikacji. Nie mogę pomóc, jeśli chcę zrobić zrzut ekranu z ekranu głównego. jak zrobić zrzut ekranu ekranu głównego z tym kodem?
Jana
1
@ Janardhanan.S: O to pyta pytanie. Czy możesz opracować nową odpowiedź zamiast zadawać osobne pytanie.
trgraglia
3
Ten sam problem ze mną .. „Usługa natywna nie działa !!”
Yogesh Maheshwari,
1
To samo ze mną „Usługa natywna nie działa !!” .... czy ktoś może tutaj dodać tekst pomocy?
Pankaj Kumar
1
to samo tutaj! „Usługa natywna nie działa !!” aw najnowszej wersji 1.2 używają klas API LEVEL 19, takich jak na przykład Socket.
user347187
10

Na podstawie odpowiedzi @JustinMorris powyżej i @NiravDangi tutaj https://stackoverflow.com/a/8504958/2232148 musimy wziąć tło i pierwszy plan widoku i złożyć je w następujący sposób:

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

Parametr jakości zajmuje stałą Bitmap.Config, zwykle albo Bitmap.Config.RGB_565czy Bitmap.Config.ARGB_8888.

Oliver Hausler
źródło
rysowanie płótna w białym kolorze na wypadek, gdyby tło było zerowe, załatwiło sprawę. Dzięki 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();
}

}

DODAJ ZEZWOLENIE

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Vaishali Sutariya
źródło
Ta odpowiedź zawiera zrzut ekranu samej aplikacji - a nie „ekranu telefonu” zadanego w pytaniu - czy robię coś złego?
AlikElzin-kilaka
7

Możesz spróbować zrobić coś takiego,

Uzyskiwanie bufora bitmapy z układu lub widoku, wykonując coś takiego: Najpierw musisz setDrawingCacheEnabledprzejść do układu (liniowy układ lub układ względny lub widok)

następnie

Bitmap bm = layout.getDrawingCache()

Następnie rób co chcesz z bitmapą. Przekształć go w plik obrazu lub wyślij bitmapę do innego miejsca.

Kevin Tan
źródło
1
To najlepsza metoda, jeśli piszesz mapę bitową w swojej aplikacji. Uważaj też na metody opóźniające się przed pobraniem pamięci podręcznej ... jak Powiadomienie ... () dla widoków listy.
trgraglia,
Nie tylko to. Układ musi być najpierw wyświetlony na ekranie. W końcu dostajesz „pamięć podręczną”. Próbowałem ukryć widok i robić zrzuty ekranu w tle (teoretycznie), ale to nie działało.
Kevin Tan
Zdecydowanie bardziej wydajne niż inne rozwiązania
sivi
6

Dla tych, którzy chcą przechwycić GLSurfaceView, metoda getDrawingCache lub rysowanie na płótnie nie będzie działać.

Musisz przeczytać zawartość bufora ramki OpenGL po wyrenderowaniu ramki. Jest to dobra odpowiedź tutaj

rockeye
źródło
6

Stworzyłem prostą bibliotekę, która pobiera zrzut ekranu z Viewi albo daje obiekt Bitmap, albo zapisuje go bezpośrednio do dowolnej ścieżki, którą chcesz

https://github.com/abdallahalaraby/Blink

Abdallah Alaraby
źródło
Czy wymaga zrootowanego telefonu?
Nilesh Agrawal,
1
Nie wymaga
rootowania
W użyciu wspomniałeś, Screenshot.takeScreenshot(view, mPath); imageView.setImageBitmap(Screenshot.getBitmapScreenshot(view, mPath)); jak uzyskać widok bieżącej działalności. Nie chcę używać identyfikatora xml.
Nilesh Agrawal,
użyj takeScreenshotForScreen()zamiast tego.
Abdallah Alaraby
6

Krótka droga jest

FrameLayout layDraw = (FrameLayout) findViewById(R.id.layDraw); /*Your root view to be part of screenshot*/
layDraw.buildDrawingCache();
Bitmap bmp = layDraw.getDrawingCache();
Chintan Khetiya
źródło
5

Po prostu rozszerzam odpowiedź taraloca. Musisz dodać następujące wiersze, aby działało. Nazwa obrazu stała się statyczna. Upewnij się, że używasz zmiennej znacznika czasu Taraloca, ponieważ potrzebujesz dynamicznej nazwy obrazu.

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

A w pliku AndroidManifest.xml należy wprowadzić następujące wpisy:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
TechBee
źródło
4

Jeśli chcesz zrobić zrzut ekranu, fragment wykonaj następujące czynności:

  1. Zastąp 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. Logika robienia zrzutu ekranu:

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

Do aktywności możesz po prostu użyć View v1 = getWindow().getDecorView().getRootView();zamiastmView

Parsania Hardik
źródło
3

Większość odpowiedzi na to pytanie używa Canvasmetody rysowania lub pamięci podręcznej rysowania. Jednak View.setDrawingCache()metoda jest przestarzała w API 28 . Obecnie zalecanym API do tworzenia zrzutów ekranu jest PixelCopyklasa dostępna z API 24 (ale metody, które akceptują Windowparametry, są dostępne z API 26 == Android 8.0 Oreo). Oto przykładowy kod Kotlin do pobierania 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ý
źródło
Problem z PixelCopy w stosunku do rozwiązania drawingCache polega na tym, że wydaje się, że przechwytuje tylko widoczny piksel. reszta jest dla mnie czarna. Nie można więc udostępniać rzeczy, które można przewijać i które są częściowo poza ramką. Czy masz na to rozwiązanie?
Henning
Masz rację. Podobnie może to powodować problem, jeśli nad widokiem pokaże się inny widok Chcę zrzut ekranu (np. Gdy szuflada jest otwarta). W takich przypadkach używam starej metody Canvas :(
Miloš Černilovský
1
Czy można zrobić zrzut ekranu z dowolnej działającej aplikacji za pomocą PixelCopy?
Amir Rezaei,
2

Tylko do aplikacji systemowych!

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

Uwaga: aplikacje systemowe nie muszą uruchamiać „su”, aby wykonać to polecenie.

GilCol
źródło
2

Widok parametrów jest obiektem układu głównego.

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
źródło
2

Zrzut ekranu z przewijaniem całej strony

Jeśli chcesz przechwycić pełny zrzut ekranu (który zawiera mniej więcej widok przewijania), sprawdź tę bibliotekę

https://github.com/peter1492/LongScreenshot

Wszystko, co musisz zrobić, to zaimportować Gradel i stworzyć obiekt BigScreenshot

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

Oddzwonienie zostanie odebrane z bitmapą Zrzutów ekranu wykonanych podczas automatycznego przewijania grupy widoków ekranu i na końcu połączonych razem.

@Override public void getScreenshot(Bitmap bitmap) {}

Które można zapisać w galerii lub jakikolwiek sposób użycia jest konieczny po ich zakończeniu

Piotr
źródło
1

Wykonaj zrzut ekranu widoku w Androidzie.

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
źródło
-1

jeśli chcesz uchwycić widok lub układ, taki jak RelativeLayout lub LinearLayout itp., po prostu użyj kodu:

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

teraz możesz zapisać tę bitmapę w pamięci urządzenia poprzez:

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
źródło