Como tirar uma captura de tela programaticamente no Android?

495

Como posso capturar uma captura de tela de uma área selecionada da tela do telefone, não por nenhum programa, mas pelo código?

korovaisdead
fonte
4
Não do emulador. Preciso fazer uma captura de tela de parte do meu programa e fazê-lo no mesmo programa.
precisa saber é o seguinte
1
Outra referência boa: stackoverflow.com/a/10296881/439171
Italo Borssatto

Respostas:

448

Aqui está o código que permite que minha captura de tela seja armazenada em um cartão SD e usada posteriormente para quaisquer que sejam suas necessidades:

Primeiro, você precisa adicionar uma permissão adequada para salvar o arquivo:

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

E este é o código (executando em uma atividade):

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

E é assim que você pode abrir a imagem gerada recentemente:

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 você deseja usar isso na exibição de fragmentos, use:

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

ao invés de

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

na função takeScreenshot ()

Nota :

Esta solução não funciona se o seu diálogo contiver uma visualização de superfície. Para mais detalhes, verifique a resposta à seguinte pergunta:

Android Captura de tela da exibição em superfície mostra a tela preta

taraloca
fonte
23
Olá, você pode descrever o que é o mCurrentUrlMask? Eu tentei esse código, mas ele está sempre me dando NullPointerException em Bitmap.createBitmap (v1.getDrawingCache ()), alguém pode me dizer o que estou fazendo de errado.? Qualquer ajuda é apreciada. Obrigado.
Mitesh Sardhara
4
@MiteshSardhara mCurrentUrlMaskdeve ser uma Viewvez que é a classe exclusiva na API do Android que possui o getRootView()método Provavelmente é uma visão na interface do usuário.
Gipi
6
Você pode me dizer o que é mCurrentUrlMask?
Jayeshkumar Sojitra
37
Insted de View v1 = mCurrentUrlMask.getRootView();eu usei View v1 = getWindow().getDecorView().getRootView();e funciona para mim.
enadun
9
Esta resposta faz uma captura de tela apenas do aplicativo - não da "tela do telefone", conforme solicitado na pergunta - ou estou fazendo algo errado.
AlikElzin-Kilaka
126

Chame esse método, passando o ViewGroup mais externo do qual você deseja uma captura de tela:

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
fonte
9
Este parece ser um código mais limpo do que a resposta aceita. Também funciona?
jophde
2
Eu o uso há algum tempo em alguns aplicativos diferentes e não tive nenhum problema.
precisa saber é o seguinte
3
Se você deseja obter uma captura de tela do telefone, onde seu aplicativo está em segundo plano, o que você passa como o view? `#
AlikElzin-kilaka 15/15/15
2
Passar getWindow().getDecorView().getRootView()como a visualização resulta em uma captura de tela apenas do aplicativo - não da tela.
AlikElzin-Kilaka
Esta resposta faz uma captura de tela apenas do aplicativo - não da "tela do telefone", conforme solicitado na pergunta - ou estou fazendo algo errado.
AlikElzin-Kilaka
42

Nota: funciona apenas para telefone enraizado

Programaticamente, você pode executar adb shell /system/bin/screencap -p /sdcard/img.pngcomo abaixo

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

então leia img.pngcomo Bitmape use como desejar.

Viswanath Lekshmanan
fonte
É necessário acesso root?
zoom
3
Sim, você precisa de acesso root. Por favor, verifique a Nota no cabeçalho
Viswanath Lekshmanan
Oi, eu tenho um System.err : java.io.IOException: Error running exec(). Command: [su] Working Directory: null Environment: null , meu dispositivo é o Android 5.0
Eddy
@Eddy Depende do seu dispositivo
Demian
Existe uma maneira de ler a saída diretamente sem salvar o resultado no arquivo e depois lê-lo novamente? stackoverflow.com/questions/43914035
Yazan W Yusuf
35

EDIT: tenha piedade dos votos negativos. Era verdade em 2010, quando eu respondi a pergunta.

Todos os programas que permitem capturas de tela funcionam apenas em telefones com root.

RDA
fonte
Parece que hoje em dia é possível em Androids com chipset baseado em Tegra
GDR
4.0.3 - então provavelmente é um desses tablets tegra da nova escola
GDR
AFAIK, quando os dispositivos têm um aplicativo padrão para capturar capturas de tela, é um aplicativo com privilégios especiais de assinatura que permitem capturar o buffer de quadros (um buffer com os pixels da tela). Portanto, é verdade, se a sua ROM tiver um aplicativo assim, você não precisará estar enraizado, mas somente esse aplicativo poderá capturar, e não o seu.
Rui Marques
2
A rigor, junto com a conta de usuário "shell" do ADB raiz sempre teve permissão para fazer isso, pois esse era o caso de uso pretendido. O que não estava disponível historicamente (exceto em compilações ocasionais por engano) era uma maneira de os IDs de usuário do aplicativo fazerem isso.
Chris Stratton
26

Nenhuma permissão de raiz ou grande codificação é necessária para este método.


No shell adb, usando o comando abaixo, você pode capturar a tela.

input keyevent 120

Este comando não requer permissão de root, assim você também pode executar o código java do aplicativo Android.

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

Mais sobre o código do evento principal no Android, consulte http://developer.android.com/reference/android/view/KeyEvent.html

Aqui nós usamos. KEYCODE_SYSRQ seu valor é 120 e é usado para a chave Solicitação do sistema / Tela de impressão.


Como disse o CJBS, a imagem de saída será salva em / sdcard / Pictures / Screenshots

Jeegar Patel
fonte
A imagem de saída será salva aqui:/sdcard/Pictures/Screenshots
CJBS
requer permissão root?
Taranmeet Singh
1
vai funcionar no marshmallow? ou ele funcionará em segundo plano de serviço @JeegarPatel
karanatwal.github.io
2
não funcionou programaticamente, mas funciona a partir do shell. Tentei com nougat.
precisa saber é o seguinte
1
su -c "input keyevent 120"está bem !!
Ipcjs
17

A resposta de Mualig é muito boa, mas eu tive o mesmo problema que Ewoks descreve, não estou entendendo nada. Às vezes, é bom o suficiente e às vezes recebo texto em preto sobre fundo preto (dependendo do tema).

Esta solução é fortemente baseada no código Mualig e no código que encontrei no Robotium. Estou descartando o uso do cache de desenho chamando diretamente para o método draw. Antes disso, tentarei extrair o plano de fundo da atividade atual para desenhá-lo primeiro.

// 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
fonte
Eu tenho uma listview com android: cacheColorHint = "# 00000000" em minha atividade e uso esse código para capturar imagens, ainda tenho um plano de fundo preto, porque descobri que o plano de fundo do tema é preto, como posso lidar com isso exibição de lista?
Wangchao0721
Activity activity = getCurrentActivity, fornecendo o método indefinido Eroor.
Shabbir Dhangot
17
private void captureScreen() {
    View v = getWindow().getDecorView().getRootView();
    v.setDrawingCacheEnabled(true);
    Bitmap bmp = Bitmap.createBitmap(v.getDrawingCache());
    v.setDrawingCacheEnabled(false);
    try {
        FileOutputStream fos = new FileOutputStream(new File(Environment
                .getExternalStorageDirectory().toString(), "SCREEN"
                + System.currentTimeMillis() + ".png"));
        bmp.compress(CompressFormat.PNG, 100, fos);
        fos.flush();
        fos.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Adicione a permissão no manifesto

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

Para suportar versões do Marshmallow ou superior, adicione o código abaixo na atividade onCreate method

ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},00);
Crazy Coder
fonte
Requer: <permissão de uso android: name = "android.permission.WRITE_EXTERNAL_STORAGE" />
AndroidGuy
4
Esta resposta faz uma captura de tela apenas do aplicativo - não da "tela do telefone", conforme solicitado na pergunta - ou estou fazendo algo errado?
AlikElzin-Kilaka
E se eu precisar da captura de tela de um item do listview?
Anshul Tyagi
Eu quero capturar no adaptador alguma idéia como posso fazer isso?
Deep Dave
16

Como referência, uma maneira de capturar a tela (e não apenas a atividade do seu aplicativo) é capturar o buffer de quadros (dispositivo / dev / graphics / fb0). Para fazer isso, você deve ter privilégios de root ou seu aplicativo deve ser um aplicativo com permissões de assinatura ("Uma permissão que o sistema concede somente se o aplicativo solicitante for assinado com o mesmo certificado que o aplicativo que declarou a permissão") - que é muito improvável, a menos que você tenha compilado sua própria ROM.

Cada captura de buffer de quadros, de alguns dispositivos que testei, continha exatamente uma captura de tela. As pessoas relataram que ele contém mais, acho que depende do tamanho do quadro / tela.

Tentei ler o framebuffer continuamente, mas parece retornar uma quantidade fixa de bytes lidos. No meu caso, são (3 410 432) bytes, o suficiente para armazenar um quadro de exibição de 854 * 480 RGBA (3 279 360 bytes). Sim, o quadro, em binário, emitido a partir de fb0 é RGBA no meu dispositivo. Provavelmente, isso dependerá de dispositivo para dispositivo. Isso será importante para você decodificá-lo =)

No meu dispositivo / dev / graphics / fb0, as permissões são para que apenas o usuário root e os usuários dos gráficos do grupo possam ler o fb0.

graphics é um grupo restrito, portanto, você provavelmente só acessará o fb0 com um telefone root usando o comando su.

Os aplicativos Android têm o ID do usuário (uid) = app _ ## e o ID do grupo (guid) = app _ ## .

O shell adb possui uid = shell e guid = shell , que tem muito mais permissões que um aplicativo. Você pode realmente verificar essas permissões em /system/permissions/platform.xml

Isso significa que você poderá ler fb0 no shell adb sem raiz, mas não o lerá dentro do aplicativo sem raiz.

Além disso, conceder permissões READ_FRAME_BUFFER e / ou ACCESS_SURFACE_FLINGER no AndroidManifest.xml não fará nada para um aplicativo comum, porque elas só funcionarão para aplicativos de ' assinatura '.

Verifique também este tópico fechado para obter mais detalhes.

Rui Marques
fonte
2
Isso funciona (funcionou?) Em alguns telefones, mas observe que os telefones baseados em GPU não fornecem necessariamente um buffer de estrutura linear para o processador de aplicativos.
Chris Stratton
15

Minha solução é:

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

As imagens são salvas na pasta de armazenamento externo.

validcat
fonte
1
Você deve fechar o FileOutputStream em um bloco final. Se você encontrar uma exceção agora, o fluxo não será fechado.
Wotuu
O que viewvocê está passando ImageUtils.loadBitmapFromView(this, view)?
AlikElzin-Kilaka
1
por que você usa v.layout (0, 0, v.getMeasuredWidth (), v.getMeasuredHeight ()); ? Isso não muda a visão (v)?
serj 28/01
11

Você pode tentar a seguinte biblioteca: http://code.google.com/p/android-screenshot-library/ A Biblioteca de capturas de tela do Android (ASL) permite capturar programaticamente capturas de tela de dispositivos Android sem a necessidade de ter privilégios de acesso root. Em vez disso, o ASL utiliza um serviço nativo em execução em segundo plano, iniciado pelo Android Debug Bridge (ADB) uma vez por inicialização do dispositivo.

Kuba
fonte
1
Eu tentei this.but leva captura de tela do aplicativo em execução sozinho. Não posso ajudar se eu quiser tirar uma captura de tela da tela inicial. Como tirar uma captura de tela da tela inicial com esse código?
Jana
1
@ Janardhanan.S: É isso que a pergunta está pedindo. Você pode elaborar com uma nova resposta em vez de fazer uma pergunta separada.
8132 trgraglia
3
Mesmo problema comigo .. "O serviço nativo não está em execução !!"
Yogesh Maheshwari
1
O mesmo comigo "Serviço nativo não está em execução !!" .... alguém pode adicionar o texto de ajuda aqui?
Pankaj Kumar
1
o mesmo aqui! "Serviço nativo não está em execução !!" e na versão 1.2 mais recente, eles usam as classes API LEVEL 19, como o Socket, por exemplo.
user347187
10

Com base na resposta de @JustinMorris acima e @NiravDangi aqui https://stackoverflow.com/a/8504958/2232148 , devemos pegar o plano de fundo e o primeiro plano de uma visualização e montá-los da seguinte forma:

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

O parâmetro quality recebe uma constante de Bitmap.Config, normalmente Bitmap.Config.RGB_565ou Bitmap.Config.ARGB_8888.

Oliver Hausler
fonte
tela de desenho com cor branca, caso o plano de fundo seja nulo, fez o truque para mim. Obrigado 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();
}

}

ADICIONAR PERMISSÃO

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Vaishali Sutariya
fonte
Esta resposta faz uma captura de tela apenas do aplicativo - não da "tela do telefone", conforme solicitado na pergunta - ou estou fazendo algo errado?
AlikElzin-Kilaka
7

Você pode tentar fazer algo assim,

Obtendo um cache de bitmap a partir de um layout ou exibição, fazendo algo como Primeiro, você precisa setDrawingCacheEnabledde um layout (um layout linear ou layout relativo ou uma exibição)

então

Bitmap bm = layout.getDrawingCache()

Então você faz o que quiser com o bitmap. Transforme-o em um arquivo de imagem ou envie a interface do usuário do bitmap para outro lugar.

Kevin Tan
fonte
1
Esse é o melhor método se você estiver gravando em um bitmap do seu aplicativo. Além disso, cuidado com os métodos que possuem atrasos antes de usar o cache ... como Notify ... () para exibições de lista.
trgraglia
Não é só isso. O layout deve ser exibido na tela primeiro. É o "cache" que você está recebendo afinal. Tentei esconder a vista e tirar screenshots em segundo plano (em teoria), mas não funcionou.
Kevin Tan
De longe mais eficiente do que outras soluções
sivi
6

Para aqueles que desejam capturar um GLSurfaceView, o método getDrawingCache ou desenho para tela não funciona.

Você deve ler o conteúdo do buffer de estrutura OpenGL após a renderização do quadro. Há uma boa resposta aqui

rockeye
fonte
6

Eu criei uma biblioteca simples que tira uma captura de tela de Viewe fornece um objeto Bitmap ou salva diretamente em qualquer caminho que você desejar

https://github.com/abdallahalaraby/Blink

Abdallah Alaraby
fonte
Requer telefone enraizado?
Nilesh Agrawal
1
No enraizamento necessário :)
Abdallah Alaraby
Em uso, você mencionou Screenshot.takeScreenshot(view, mPath); imageView.setImageBitmap(Screenshot.getBitmapScreenshot(view, mPath)); Como obter uma visão da atividade atual. Eu não quero usar o ID do xml.
Nilesh Agrawal
use em takeScreenshotForScreen()vez disso.
Abdallah Alaraby
6

Caminho curto é

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

Apenas estendendo a resposta da taraloca. Você deve adicionar as seguintes linhas para fazê-lo funcionar. Eu fiz o nome da imagem estático. Certifique-se de usar a variável timestamp do taraloca, caso precise de um nome de imagem dinâmico.

    // Storage Permissions
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
        Manifest.permission.READ_EXTERNAL_STORAGE,
        Manifest.permission.WRITE_EXTERNAL_STORAGE
};

private void verifyStoragePermissions() {
    // Check if we have write permission
    int permission = ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);

    if (permission != PackageManager.PERMISSION_GRANTED) {
        // We don't have permission so prompt the user
        ActivityCompat.requestPermissions(this, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);
    }else{
        takeScreenshot();
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);

    if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        if (requestCode == REQUEST_EXTERNAL_STORAGE) {
            takeScreenshot();
        }
    }
}

E no arquivo AndroidManifest.xml, as seguintes entradas são obrigatórias:

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

Se você quiser tirar uma captura de tela, fragment siga este procedimento:

  1. Substituir onCreateView():

             @Override
            public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                     Bundle savedInstanceState) {
                // Inflate the layout for this fragment
                View view = inflater.inflate(R.layout.fragment_one, container, false);
                mView = view;
            }
  2. Lógica para captura de tela:

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

    public void shareScreenShotM(View view, NestedScrollView scrollView){
    
         bm = takeScreenShot(view,scrollView);  //method to take screenshot
        File file = savePic(bm);  // method to save screenshot in phone.
        }
  4. método takeScreenShot ():

             public Bitmap takeScreenShot(View u, NestedScrollView z){
    
                u.setDrawingCacheEnabled(true);
                int totalHeight = z.getChildAt(0).getHeight();
                int totalWidth = z.getChildAt(0).getWidth();
    
                Log.d("yoheight",""+ totalHeight);
                Log.d("yowidth",""+ totalWidth);
                u.layout(0, 0, totalWidth, totalHeight);
                u.buildDrawingCache();
                Bitmap b = Bitmap.createBitmap(u.getDrawingCache());
                u.setDrawingCacheEnabled(false);
                u.destroyDrawingCache();
                 return b;
            }
  5. método savePic ():

     public static File savePic(Bitmap bm){
    
            ByteArrayOutputStream bytes = new ByteArrayOutputStream();
            bm.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
             File sdCardDirectory =  new File(Environment.getExternalStorageDirectory() + "/Foldername");
    
           if (!sdCardDirectory.exists()) {
                sdCardDirectory.mkdirs();
          }
           //  File file = new File(dir, fileName);
          try {
             file = new File(sdCardDirectory, Calendar.getInstance()
                .getTimeInMillis() + ".jpg");
            file.createNewFile();
            new FileOutputStream(file).write(bytes.toByteArray());
            Log.d("Fabsolute", "File Saved::--->" + file.getAbsolutePath());
             Log.d("Sabsolute", "File Saved::--->" + sdCardDirectory.getAbsolutePath());
         } catch (IOException e) {
              e.printStackTrace();
          }
         return file;
       }

Para atividade, você pode simplesmente usar em View v1 = getWindow().getDecorView().getRootView();vez demView

Parsania Hardik
fonte
3

A maioria das respostas para esta pergunta usa o Canvasmétodo de desenho ou o cache de desenho. No entanto, o View.setDrawingCache()método está obsoleto na API 28 . Atualmente, a API recomendada para fazer capturas de tela é a PixelCopyclasse disponível na API 24 (mas os métodos que aceitam Windowparâmetro estão disponíveis na API 26 == Android 8.0 Oreo). Aqui está um exemplo de código Kotlin para recuperar um 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ý
fonte
O problema com o PixelCopy sobre a solução drawingCache é que ele parece capturar apenas o pixel visível. o resto é preto para mim. Portanto, não é possível compartilhar coisas roláveis ​​e parcialmente fora do quadro. Você tem uma solução para isso?
Henning
Você está certo. Da mesma forma, pode causar um problema se outra tela for exibida acima da tela que eu quero capturar (por exemplo, quando a gaveta é aberta). Nestes casos, apenas uso o método antigo do Canvas :(
Miloš Černilovský 7/19/19
1
É possível capturar imagens em qualquer aplicativo em execução usando o PixelCopy?
Amir Rezaei
2

Apenas para aplicativos do sistema!

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

Nota: Os aplicativos do sistema não precisam executar "su" para executar este comando.

GilCol
fonte
2

A visualização de parâmetro é o objeto de layout raiz.

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

Para captura de tela de rolagem de página inteira

Se você deseja capturar uma captura de tela completa do View (que contém uma visualização de rolagem ou mais), verifique esta biblioteca

https://github.com/peter1492/LongScreenshot

Tudo o que você precisa fazer é importar o Gradel e criar um objeto do BigScreenshot

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

Um retorno de chamada será recebido com o bitmap das capturas de tela capturadas enquanto rolando automaticamente pelo grupo de exibição de tela e, no final, reunidos.

@Override public void getScreenshot(Bitmap bitmap) {}

Os quais podem ser salvos na galeria ou qualquer uso que seja necessário, após

Pedro
fonte
1

Tire uma captura de tela de uma visualização no 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
fonte
-1

se você deseja capturar uma visualização ou layout como RelativeLayout ou LinearLayout etc., basta usar o código:

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

agora você pode salvar este bitmap no armazenamento do dispositivo:

FileOutputStream outStream = null;
File f=new File(Environment.getExternalStorageDirectory()+"/Screen Shots/");
f.mkdir();
String extStorageDirectory = f.toString();
File file = new File(extStorageDirectory, "my new screen shot");
pathOfImage = file.getAbsolutePath();
try {
    outStream = new FileOutputStream(file);
    bm.compress(Bitmap.CompressFormat.PNG, 100, outStream);
    Toast.makeText(getApplicationContext(), "Saved at "+f.getAbsolutePath(), Toast.LENGTH_LONG).show();
    addImageGallery(file);
    //mail.setEnabled(true);
    flag=true;
} catch (FileNotFoundException e) {e.printStackTrace();}
try {
    outStream.flush();
    outStream.close();
} catch (IOException e) {e.printStackTrace();}
Akshay Paliwal
fonte