Как программно сделать скриншот на Android?


495

Как сделать скриншот выбранной области экрана телефона не какой-либо программой, а кодом?


4
Не из эмулятора. Мне нужно сделать скриншот части моей программы и сделать что-то с ней в той же программе.
— korovaisdead

1
Еще одна
— полезная

Ответы:


448

Вот код, который позволил сохранить мой скриншот на SD-карте и использовать позже для любых ваших потребностей:

Во-первых, вам нужно добавить правильное разрешение для сохранения файла:

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

И это код (работает в Activity):

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

И вот как вы можете открыть недавно сгенерированное изображение:

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

Если вы хотите использовать это при просмотре фрагмента, используйте:

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

вместо

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

на takeScreenshot () функция

Примечание :

Это решение не работает, если ваш диалог содержит вид поверхности. Для получения подробной информации, пожалуйста, проверьте ответ на следующий вопрос:

Скриншот Android Take из Surface View показывает черный экран


23
Привет, Можете ли вы описать, что такое mCurrentUrlMask? Я пробовал этот код, но он всегда дает мне NullPointerException в Bitmap.createBitmap (v1.getDrawingCache ()), кто-нибудь может сказать, что я делаю неправильно? Любая помощь приветствуется. Спасибо.
— Митеш Сардхара

4
@MiteshSardhara mCurrentUrlMaskдолжно быть, Viewпоскольку это уникальный класс в API Android, который имеет getRootView()метод. Вероятно, это вид в пользовательском интерфейсе.
— Гипи

6
Подскажите, пожалуйста, что такое mCurrentUrlMask?
— Джаешкумар Соджитра

37
Insted of View v1 = mCurrentUrlMask.getRootView();я использовал, View v1 = getWindow().getDecorView().getRootView();и это работает для меня.
— enadun

9
Этот ответ занимает снимок экрана только с приложением, а не с "экрана телефона", как было задано в вопросе, или я делаю что-то не так.
— Алик Эльзин-килака

126

Вызовите этот метод, передав внешнюю группу ViewGroup, для которой требуется снимок экрана:

public Bitmap screenShot(View view) {
    Bitmap bitmap = Bitmap.createBitmap(view.getWidth(),
            view.getHeight(), Config.ARGB_8888);
    Canvas canvas = new Canvas(bitmap);
    view.draw(canvas);
    return bitmap;
}

9
Кажется, это более чистый код, чем принятый ответ. Это работает так же хорошо?
— Jophde

2
Я использовал его некоторое время в нескольких разных приложениях, и у меня не было проблем.
— Джастин Моррис

3
Если вы хотите получить скриншот телефона, где ваше приложение находится в фоновом режиме, что вы view
— называете

2
Передача в getWindow().getDecorView().getRootView()виде представления приводит к созданию снимка экрана только с приложением, а не с экрана.
— Алик Эльзин-килака

Этот ответ занимает снимок экрана только с приложением, а не с "экрана телефона", как было задано в вопросе, или я делаю что-то не так.
— Алик Эльзин-килака

42

Примечание: работает только для рутованного телефона

Программно, вы можете запустить, adb shell /system/bin/screencap -p /sdcard/img.pngкак показано ниже

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

тогда читайте img.pngкак Bitmapи используйте как хотите.


Нужен ли root-доступ?
— увеличить

3
Да, вам нужен root-доступ. Пожалуйста, проверьте примечание в заголовке
— Вишванат Лекшманан

Привет, я получил System.err : java.io.IOException: Error running exec(). Command: [su] Working Directory: null Environment: null , мое устройство Android 5.0
— Eddy

@ Eddy Это зависит от вашего устройства
— Демиан

Есть ли способ прочитать вывод напрямую, не сохраняя результат в файл, а затем снова прочитав его? stackoverflow.com/questions/43914035
— Язан W Юсуф

35

РЕДАКТИРОВАТЬ: помиловать с downvotes. Это было верно в 2010 году, когда я ответил на вопрос.

Все программы, позволяющие делать скриншоты, работают только на рутованных телефонах.


Похоже, что в наши дни это возможно на Android с чипсетом на базе Tegra
— GDR

4.0.3 - тогда это, вероятно, один из этих планшетов новой школы
— ГДР

AFAIK, когда устройства имеют стандартное приложение для захвата скриншотов, это приложение со специальными привилегиями подписи, которые позволяют ему захватывать кадровый буфер (буфер с содержит пиксели экрана). Так что это правда, если в вашем ПЗУ есть такое приложение, вам не нужно будет рутироваться, но только это приложение может делать снимки, а не ваше.
— Руи Маркес

2
Строго говоря, наряду с учетной записью пользователя «shell» корневого ADB всегда было разрешено делать это, как и предполагалось. То, что не было исторически доступным (за исключением случайных сборок как ошибки), было способом для идентификаторов пользователей приложения сделать это.
— Крис Страттон

26

Для этого метода не требуется разрешение root или большое кодирование .


В оболочке adb с помощью приведенной ниже команды вы можете сделать снимок экрана.

input keyevent 120

Эта команда не требует каких-либо прав root, так что вы также можете выполнить из Java-кода приложения Android.

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

Подробнее о KeyEvent кода в Android см http://developer.android.com/reference/android/view/KeyEvent.html

Здесь мы использовали. KEYCODE_SYSRQ его значение равно 120 и используется для системного запроса / ключа экрана печати.


Как сказал CJBS, выходное изображение будет сохранено в / sdcard / Pictures / Screenshots


Выходное изображение будет сохранено здесь:/sdcard/Pictures/Screenshots
— CJBS

это требует разрешения root?
— Таранмит Сингх

1
это будет работать на зефир? или это будет работать в фоновом режиме обслуживания @JeegarPatel
— karanatwal.github.io

2
не работает программно, но работает из оболочки. Пробовал с нугой.
— mehmet6parmak

1
su -c "input keyevent 120"в порядке !!
— ipcjs

17

Ответ Муалига очень хороший, но у меня была та же проблема, что описывает Эвокс, я не понимаю, как это происходит. Так что иногда это достаточно хорошо, а иногда я получаю черный текст на черном фоне (в зависимости от темы).

Это решение основано на коде Mualig и коде, который я нашел в Robotium. Я отказываюсь от использования кэша рисования, вызывая непосредственно метод рисования. Перед этим я попытаюсь получить фон для рисования из текущей деятельности, чтобы нарисовать его первым.

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

У меня есть список с android: cacheColorHint = "# 00000000" в моей деятельности, и я использую этот код для скриншота, у меня все еще есть черный фон, потому что я обнаружил, что фон, полученный из темы, черный, как я могу справиться с этим Посмотреть список?
— Wangchao0721

Activity activity = getCurrentActivity, дающая Eroor неопределенный метод.
— Шаббир Дхангот

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

Добавьте разрешение в манифест

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

Для поддержки Marshmallow или более поздних версий, пожалуйста, добавьте приведенный ниже код в метод активности onCreate

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

Требуется: <использование-разрешения android: name = "android.permission.WRITE_EXTERNAL_STORAGE" />
— AndroidGuy

4
Этот ответ занимает скриншот только приложения, а не «экрана телефона», как было задано в вопросе, или я что-то не так делаю?
— Алик Эльзин-килака

А что если мне нужен скриншот элемента списка?
— Аншул Тяги

я хочу захватить с адаптера любую идею, как я могу это сделать?
— Глубокий Дейв

16

Для справки: один из способов захвата экрана (а не только активности вашего приложения) - захват кадрового буфера (device / dev / graphics / fb0). Для этого у вас должны быть права суперпользователя или ваше приложение должно быть приложением с разрешениями на подпись («разрешение, которое система предоставляет, только если запрашивающее приложение подписано тем же сертификатом, что и приложение, которое объявило разрешение»), что очень маловероятно, если вы не скомпилировали свой собственный ROM.

Каждый кадр кадрового буфера с пары протестированных мной устройств содержал ровно один скриншот. Люди сообщили, что он содержит больше, я думаю, это зависит от размера кадра / дисплея.

Я пытался читать кадровый буфер непрерывно, но, похоже, он возвращает фиксированное количество прочитанных байтов. В моем случае это (3 410 432) байта, что достаточно для хранения кадра дисплея 854 * 480 RGBA (3 279 360 байтов). Да, кадр в двоичном формате, выведенный из fb0, является RGBA на моем устройстве. Скорее всего, это будет зависеть от устройства к устройству. Это будет важно для вас, чтобы расшифровать его =)

В моем устройстве права доступа / dev / graphics / fb0 такие, что только root и пользователи из групповой графики могут читать fb0.

Графика является ограниченной группой, поэтому вы, вероятно, получите доступ к fb0 только с рутированным телефоном с помощью команды su.

Приложения Android имеют идентификатор пользователя (uid) = app _ ## и идентификатор группы (guid) = app _ ## .

В оболочке adb есть uid = shell и guid = shell , которые имеют гораздо больше прав, чем приложение. Вы можете проверить эти разрешения в /system/permissions/platform.xml

Это означает, что вы сможете читать fb0 в оболочке adb без рута, но вы не будете читать его в приложении без рута.

Кроме того, предоставление разрешений READ_FRAME_BUFFER и / или ACCESS_SURFACE_FLINGER для AndroidManifest.xml ничего не даст для обычного приложения, поскольку они будут работать только для приложений с « подписью ».

Также проверьте эту закрытую тему для более подробной информации.


2
Это работает (работает?) На некоторых телефонах, но обратите внимание, что телефоны на базе графического процессора не обязательно обеспечивают линейный кадровый буфер для процессора приложений.
— Крис Страттон,

15

Мое решение:

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

а также

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

Изображения сохраняются в папке внешнего хранилища.


1
Вы должны закрыть FileOutputStream в блоке finally. Если вы встретите исключение, поток не будет закрыт.
— Wotuu

На что viewвы переходите ImageUtils.loadBitmapFromView(this, view)?
— Алик Эльзин-килака

1
почему вы используете v.layout (0, 0, v.getMeasuredWidth (), v.getMeasuredHeight ()); ? Разве это не меняет представление (v)?
— Serj

11

Вы можете попробовать следующую библиотеку: http://code.google.com/p/android-screenshot-library/ Библиотека скриншотов Android (ASL) позволяет программно захватывать скриншоты с устройств Android без необходимости иметь права root-доступа. Вместо этого ASL использует собственный сервис, работающий в фоновом режиме, запускаемый через Android Debug Bridge (ADB) один раз за загрузку устройства.


1
Я попробовал это. Но он делает снимок экрана запущенного приложения в одиночку. Это не может помочь, если я хочу сделать скриншот домашнего экрана. ты как сделать скриншот домашнего экрана с этим кодом?
— Яна

1
@ Janardhanan.S: Это то, о чем просит вопрос. Можете ли вы уточнить новый ответ вместо того, чтобы задавать отдельный вопрос?
— Trgraglia

3
Та же проблема со мной .. "Родной сервис не работает !!"
— Йогеш Махешвари

1
То же самое со мной "Native Service Not Running !!" .... кто-нибудь может добавить сюда текст справки?
— Панкадж Кумар

1
тоже самое! "Родной сервис не работает !!" и в их последней версии 1.2 они используют классы API LEVEL 19, как, например, Socket.
— user347187

10

Основываясь на ответе @JustinMorris выше и @NiravDangi здесь https://stackoverflow.com/a/8504958/2232148, мы должны взять фон и передний план представления и собрать их следующим образом:

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

Параметр качества принимает константу Bitmap.Config, обычно либо либо, Bitmap.Config.RGB_565либо Bitmap.Config.ARGB_8888.


рисование холста с белым цветом в случае, если фон является нулевым, помогло мне. Спасибо Оливер
— 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();
}

}

ДОБАВИТЬ РАЗРЕШЕНИЕ

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

Этот ответ занимает скриншот только приложения, а не «экрана телефона», как было задано в вопросе, или я что-то не так делаю?
— Алик Эльзин-килака

7

Вы можете попробовать сделать что-то вроде этого,

Получение кеша растрового изображения из макета или представления, выполнив что-то вроде: Сначала вы должны setDrawingCacheEnabledперейти к макету (линейное или относительное расположение, или представление)

тогда

Bitmap bm = layout.getDrawingCache()

Затем вы делаете все, что хотите с растровым изображением. Либо превратив его в файл изображения, либо отправьте URI растрового изображения в другое место.


1
Это лучший метод, если вы пишете в растровое изображение ваше приложение. Кроме того, остерегайтесь методов, которые имеют задержки перед получением кэша ... как Notify ... () для представлений списка.
— trgraglia

Не только это. Макет должен отображаться на экране первым. Это «кеш», который вы получаете в конце концов. Пробовал скрывать вид и делать скриншоты в фоновом режиме (теоретически), но это не сработало.
— Кевин Тан


6

Для тех, кто хочет захватить GLSurfaceView, метод getDrawingCache или рисование на холст не будет работать.

Вы должны прочитать содержимое кадрового буфера OpenGL после рендеринга кадра. Существует хороший ответ здесь


6

Я создал простую библиотеку, которая делает снимок экрана с Viewи дает вам растровый объект или сохраняет его по любому желаемому пути

https://github.com/abdallahalaraby/Blink


Требуется ли рутированный телефон?
— Нилеш Агравал

1
Нет необходимости
— рутирования

При использовании вы упомянули, Screenshot.takeScreenshot(view, mPath); imageView.setImageBitmap(Screenshot.getBitmapScreenshot(view, mPath)); как получить представление о текущей деятельности. Я не хочу использовать идентификатор XML.
— Нилеш Агравал

используйте takeScreenshotForScreen()вместо.
— Абдалла Алараби

6

Короткий путь

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

5

Просто расширяю ответ Таралки. Вы должны добавить следующие строки, чтобы это работало. Я сделал имя изображения статичным. Пожалуйста, убедитесь, что вы используете переменную timestamp taraloca, если вам нужно динамическое имя изображения.

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

А в файле AndroidManifest.xml должны быть следующие записи:

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

4

Если вы хотите сделать снимок экрана, fragment чем следовать:

  1. Переопределить 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. Логика для снятия скриншота:

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

Для активности вы можете просто использовать View v1 = getWindow().getDecorView().getRootView();вместоmView


3

В большинстве ответов на этот вопрос используется Canvasметод рисования или метод кэширования рисунка. Однако View.setDrawingCache()метод не рекомендуется в API 28 . В настоящее время рекомендуемым API для создания снимков экрана является PixelCopyкласс, доступный из API 24 (но методы, которые принимают Windowпараметр, доступны из API 26 == Android 8.0 Oreo). Вот пример кода Kotlin для получения 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
        }
    }
}

Проблема с PixelCopy над решением DrawingCache заключается в том, что кажется, что он захватывает только видимый пиксель. остальное для меня черное. Таким образом, невозможно делиться вещами, которые можно прокручивать и которые частично находятся вне кадра. У вас есть решение для этого?
— Хеннинг

Вы правы. Точно так же это может вызвать проблему, если над видом, который я хочу сделать снимок экрана, отображается другой вид (например, когда ящик открыт). В этих случаях я просто использую старый метод Canvas :(
— Милош Черниловский

1
Можно ли сделать снимок экрана в любом запущенном приложении, используя PixelCopy?
— Амир Резаи

2

Только для системных приложений!

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

Примечание. Системным приложениям не нужно запускать «su» для выполнения этой команды.


2

Представление параметра является корневым объектом макета.

public static Bitmap screenShot(View view) {
                    Bitmap bitmap = null;
                    if (view.getWidth() > 0 && view.getHeight() > 0) {
                        bitmap = Bitmap.createBitmap(view.getWidth(),
                                view.getHeight(), Bitmap.Config.ARGB_8888);
                        Canvas canvas = new Canvas(bitmap);
                        view.draw(canvas);
                    }
                    return bitmap;
                }

2

Скриншот для полной прокрутки страницы

Если вы хотите сделать полный снимок экрана (который содержит скроллвью или около того), проверьте эту библиотеку

https://github.com/peter1492/LongScreenshot

Все, что вам нужно сделать, это импортировать Gradel и создать объект BigScreenshot

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

Будет получен обратный вызов с растровым изображением снимков экрана, сделанным при автоматической прокрутке группы представлений экрана и в конце, собранных вместе.

@Override public void getScreenshot(Bitmap bitmap) {}

Которые могут быть сохранены в галерее или их использование необходимо после их


1

Сделай скриншот вида в андроид.

public static Bitmap getViewBitmap(View v) {
    v.clearFocus();
    v.setPressed(false);

    boolean willNotCache = v.willNotCacheDrawing();
    v.setWillNotCacheDrawing(false);

    int color = v.getDrawingCacheBackgroundColor();
    v.setDrawingCacheBackgroundColor(0);

    if (color != 0) {
        v.destroyDrawingCache();
    }
    v.buildDrawingCache();
    Bitmap cacheBitmap = v.getDrawingCache();
    if (cacheBitmap == null) {
        return null;
    }

    Bitmap bitmap = Bitmap.createBitmap(cacheBitmap);

    v.destroyDrawingCache();
    v.setWillNotCacheDrawing(willNotCache);
    v.setDrawingCacheBackgroundColor(color);

    return bitmap;
}

-1

если вы хотите захватить представление или макет, такой как RelativeLayout или LinearLayout и т. д., просто используйте код:

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

Теперь вы можете сохранить это растровое изображение на устройстве:

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();}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.