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

495

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

korovaisdead
источник
4
Не из эмулятора. Мне нужно сделать скриншот части моей программы и сделать что-то с ней в той же программе.
korovaisdead
1
Еще одна
полезная
Вот как hackerseve.com/android-save-view-as-image-and-share-externally
жесткий кодер

Ответы:

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 показывает черный экран

taraloca
источник
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;
}
JustinMorris
источник
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();
}
xamar
источник
У меня есть список с 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();
    }
}

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

validcat
источник
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) один раз за загрузку устройства.

Kuba
источник
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 после рендеринга кадра. Существует хороший ответ здесь

Rockeye
источник
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" />
TechBee
источник
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» для выполнения этой команды.

GilCol
источник
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();}
Акшай Паливал
источник