Як програмно зробити скріншот на Android?


495

Як я можу зробити знімок екрана вибраної області екрану телефону не будь-якою програмою, а кодом?


4
Не від емулятора Мені потрібно зробити скріншот частини моєї програми і зробити це з нею в тій же програмі.
korovaisdead

1
Інша посилання хороша: stackoverflow.com/a/10296881/439171
Італо Borssatto

Відповіді:


448

Ось код, який дозволив моєму скріншоті зберігатись на SD-картці та використовувати його згодом для будь-яких потреб:

Спочатку потрібно додати належний дозвіл на збереження файлу:

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

А це код (працює в діяльності):

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 на екрані показує чорний екран


23
Привіт, Ви можете описати, що таке mCurrentUrlMask? Я спробував цей код, але він завжди дає мені NullPointerException на Bitmap.createBitmap (v1.getDrawingCache ()), чи можу хтось сказати, що я роблю не так? Будь-яка допомога вдячна. Дякую.
Мітеш Сардхара

4
@MiteshSardhara mCurrentUrlMaskповинен бути Viewунікальним класом в Android API, який має getRootView()метод. Ймовірно, це погляд в інтерфейсі.
gipi

6
Скажіть, будь ласка, що таке, mCurrentUrlMask?
Jayeshkumar Sojitra

37
InstEd з View v1 = mCurrentUrlMask.getRootView();I використовував View v1 = getWindow().getDecorView().getRootView();і це працює для мене.
Енадун

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
Це, здається, чистіший код, ніж прийнята відповідь. Це також добре?
Джофд

2
Я деякий час використовував його в кількох різних додатках і не мав жодних проблем.
JustinMorris

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і використовуйте як своє бажання.


Чи потрібен кореневий доступ?
зум

3
Так, вам потрібен кореневий доступ. Перевірте Примітку в заголовку
Вісванат Лекшман

Привіт, я отримав System.err : java.io.IOException: Error running exec(). Command: [su] Working Directory: null Environment: null , мій пристрій андроїд 5.0
Едді

@Eddy Це залежить від вашого пристрою
Дем'ян

Чи є спосіб зчитувати вихід безпосередньо, не зберігаючи результат у файл, а потім читати його знову? stackoverflow.com/questions/43914035
Yazan W Yusuf

35

РЕДАКТУЙ: помилуйсь з низовими записами. Це було правдою в 2010 році, коли я відповів на питання.

Усі програми, які дозволяють знімати екрани, працюють лише на вкорінених телефонах.


Схоже, що в наші дні це можливо на Андроїдах з чіпсетом на основі Tegra
GDR

4.0.3 - тоді це, мабуть, один із цих нових шкільних планшетів із теграми
GDR

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

2
Власне кажучи, поряд із "оболонкою" облікового запису користувача ADB завжди було дозволено робити це, оскільки це було призначеним випадком використання. Те, що не було в наявності (крім випадкових збірок як помилки), було способом для ідентифікаторів користувача програми .
Кріс Страттон

26

Ніякого кореневого дозволу або великого кодування для цього методу не потрібно.


У оболонці 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

чи потрібен дозвіл кореня ??
Taranmeet Singh

1
це буде працювати на зефір? або це буде працювати у фоновому режимі сервісу @JeegarPatel
karanatwal.github.io

2
не працює програмно, але працює з оболонки. Пробував з нугою.
mehmet6parmak

1
su -c "input keyevent 120"нормально !!
ipcjs

17

Відповідь Муаліга дуже хороша, але у мене була та сама проблема, яку описує Евокс, я не отримую передумови. Тому іноді досить добре, а іноді я отримую чорний текст на чорному тлі (залежно від теми).

Це рішення базується на коді Муаліга та коді, який я знайшов у 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();
}

У мене в списку перегляду андроїд: cacheColorHint = "# 00000000" у своїй діяльності, і я використовую цей код для скріншоту, я все-таки отримав чорний фон, тому що я виявив, що фон, який отримує від теми, є чорним, як я можу з цим боротися listview?
Wangchao0721

Активність діяльності = 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
Ця відповідь займає скріншот лише програми, а не "екрану телефону", про що йдеться у запитанні, - чи я щось роблю не так?
AlikElzin-kilaka

Що про те, якщо мені потрібен знімок екрана списку перегляду?
Аншул Тяги

Я хочу захопити з адаптера будь-яку ідею, як я можу це зробити?
Глибокий Дейв

16

В якості довідки, один із способів захоплення екрана (а не лише активності вашої програми) - це захоплення фреймбуфера (device / dev / graphics / fb0). Для цього у вас повинні бути або root права, або ваш додаток повинен мати додаток з дозволом на підпис ("Дозвіл, який система надає лише у тому випадку, якщо запитуючий додаток підписаний тим самим сертифікатом, що і додаток, який оголосив дозвіл") - який дуже малоймовірно, якщо ви не склали власний ПЗУ.

Кожен знімок кадрів з декількох пристроїв, які я перевірив, містив рівно один знімок екрана. Люди повідомили, що вона містить більше, я думаю, це залежить від розміру кадру / дисплея.

Я намагався читати фреймбуфер постійно, але, схоже, повертається за фіксовану кількість прочитаних байтів. У моєму випадку це (3 410 432) байтів, що достатньо для зберігання кадру відображення розміром 854 * 480 RGBA (3 279 360 байт). Так, кадр у двійковій формі, що виводиться з fb0, є RGBA на моєму пристрої. Це, швидше за все, буде залежати від пристрою до пристрою. Це буде важливо для вас, щоб розшифрувати його =)

У моєму пристрої / dev / graphics / fb0 дозволи дозволяють читати fb0 лише root та користувачі з групової графіки.

графіка є групою з обмеженим доступом, тому ви, ймовірно, можете отримати доступ до fb0 тільки з вкоріненим телефоном за допомогою команди su.

У додатках для Android є ідентифікатор користувача (uid) = app _ ## та ідентифікатор групи (guide) = app _ ## .

adb shell має uid = shell та guide = оболонку , що має набагато більше дозволів, ніж програма. Ви можете перевірити ці дозволи на /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 остаточно блоком. Якщо ви зіткнулися з винятком, зараз потік не закриється.
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, не вимагаючи привілеїв кореневого доступу. Натомість ASL використовує вбудований сервіс, який працює у фоновому режимі, запускається через міст налагодження Android (ADB) один раз на завантаження пристрою.


1
Я спробував this.but, він займає скріншот лише запущеного додатка. Не можу допомогти, якщо я хочу зробити скріншот домашнього екрану. ви як зробити скріншот домашнього екрану з цим кодом?
Жана

1
@ Janardhanan.S: Про це і задається питання. Чи можете ви розробити нову відповідь замість того, щоб задавати окреме запитання.
trgraglia

3
Та сама проблема зі мною .. "Рідна служба не працює !!"
Йогеш Махешварі

1
Те саме зі мною "Рідна служба не працює !!" .... може хтось додати тут довідковий текст?
Панкай Кумар

1
те ж саме! "Рідна служба не працює !!" а в останній версії 1.2 вони використовують API LEVEL 19 класів, наприклад Socket.
користувач347187

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

Тоді ви робите все, що забажаєте, з растровою картою. Або перетворивши його у файл зображення, або надішліть урі растрової карти кудись ще.


1
Це найкращий метод, якщо це ваша програма, яку ви пишете в растровій карті. Крім того, остерігайтеся методів, які мають затримки перед тим, як взяти кеш ... як Notify ... () для переглядів списку.
trgraglia

Не тільки це. Макет потрібно спочатку вивести на екран. Це "кеш", який ви отримуєте після закінчення. Спробував приховати погляд і зробити знімки екрана на задньому плані (теоретично), але це не вийшло.
Кевін Тан

Набагато ефективніші за інші рішення
сіві

6

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

Ви повинні прочитати вміст OpenGL framebuffer після надання кадру. Існує хороший відповідь тут


6

Я створив просту бібліотеку, яка знімає знімок екрана з Viewі дає вам об'єкт Bitmap або зберігає його безпосередньо на будь- який потрібний вам шлях

https://github.com/abdallahalaraby/Blink


Для цього потрібен вкорінений телефон?
Nilesh Agrawal


У використанні u згадане Screenshot.takeScreenshot(view, mPath); imageView.setImageBitmap(Screenshot.getBitmapScreenshot(view, mPath)); Як переглянути перегляд поточної активності. Я не хочу використовувати ідентифікатор xml.
Nilesh Agrawal

використовувати takeScreenshotForScreen()замість цього.
Абдалла Аларабі

6

Короткий шлях є

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

5

Просто продовження відповіді таралоки. Ви повинні додати наступні рядки, щоб це працювало. Я зробив ім'я зображення статичним. Будь ласка, переконайтеся, що ви використовуєте змінну часової позначки таралоки, якщо вам потрібна назва динамічного зображення.

    // 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). Ось зразок котла Котліна для отримання 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 над рішенням drawCache полягає в тому, що він, схоже, захоплює лише видимий піксель. решта для мене чорна. Тому неможливо ділитися речами, які можна прокручувати і частково поза рамкою. Чи є у вас рішення для цього?
Хеннінг

Ти правий. Аналогічно це може спричинити проблеми, якщо інший вигляд буде показаний над екраном Я хочу зробити знімок екрана (наприклад, коли ящик відкритий). У цих випадках я просто використовую старий метод Canvas :(
Miloš Černilovský

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

Знімок екрана прокрутки на повній сторінці

Якщо ви хочете зробити повний знімок екрана View (який містить перегляд прокрутки чи так), тоді перевірте цю бібліотеку

https://github.com/peter1492/LongScreenshot

Все, що вам потрібно зробити, це імпортувати Градель і створити об’єкт BigScreenshot

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

Зворотний виклик буде отриманий із растровою екраном знімків екрана, зробленою під час автоматичної прокрутки групи перегляду екрана та наприкінці зібраної разом.

@Override public void getScreenshot(Bitmap bitmap) {}

Які можна зберегти в галереї або будь-яке використання, необхідне їх після


1

Зробіть знімок екрана в 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;
}

-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.