在安卓系统中截取特定布局的“屏幕截图”

14

我有两个主要问题,它们密切相关。我从程序的角度来看待这些问题。

(1) - 我希望截取一个特定布局的屏幕截图,即一个嵌套在 LinearLayout 中的 ScrollView

(2) - 由于 ScrollView 中的内容超出了屏幕范围(因此可以滚动),如何确保截图包含在屏幕上不可见的元素?

这是我使用的当前代码段。它可以完成截图任务,但只能截取整个屏幕。

View view = findViewById(R.id.boss);
View v = view.getRootView();// this does not seem to make a difference
v.setDrawingCacheEnabled(true);                                                
v.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());    
v.buildDrawingCache(true);
Bitmap b = Bitmap.createBitmap(u.getDrawingCache());             
v.setDrawingCacheEnabled(false);

提前感谢。

编辑:

我犯了一些错误。我使用了错误的资源R.id.boss。现在我能够对滚动视图进行截图,而不包括屏幕外的部分。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/boss"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="top"
android:orientation="vertical" >

    <TextView
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="F"
    android:textAppearance="?android:attr/textAppearanceMedium" />

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Analyze via image URL"
        android:textAppearance="?android:attr/textAppearanceSmall" />

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
             >

                        <EditText
                            android:id="@+id/mUrl"
                            android:layout_width="fill_parent"
                            android:layout_height="wrap_content"
                            android:layout_weight="0.7"
                            android:text="http://" >

                            <requestFocus />
                        </EditText>

                        <ImageView
                            android:id="@+id/call"
                            android:layout_width="75dp"
                            android:layout_height="50dp"
                            android:layout_weight="0.3"
                            android:text="ABC"
                            android:src="@drawable/run" />

        </LinearLayout>

     <TextView
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
         android:text="ABC"
         android:textAppearance="?android:attr/textAppearanceSmall" />

     <LinearLayout
         android:layout_width="fill_parent"
         android:layout_height="wrap_content" >

         <EditText
             android:id="@+id/filepath"
             android:layout_width="fill_parent"
             android:layout_height="wrap_content"
             android:layout_weight="0.55" />

         <ImageView
             android:id="@+id/cam"
             android:layout_width="75dp"
             android:layout_height="50dp"
             android:layout_weight="0.15"
             android:src="@drawable/cam" />

         <ImageView
             android:id="@+id/browse"
             android:layout_width="75dp"
             android:layout_height="50dp"
             android:layout_weight="0.15"
             android:src="@drawable/folder"
             android:text="B" />

         <ImageView
             android:id="@+id/upload"
             android:layout_width="75dp"
             android:layout_height="50dp"
             android:layout_weight="0.15"
             android:src="@drawable/run"
             android:text="A" />
     </LinearLayout>


     <LinearLayout
         android:id="@+id/baba"
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
         android:orientation="vertical" >


         <ScrollView
             android:id="@+id/scroll"
             android:layout_width="fill_parent"
             android:layout_height="150dp"
             android:layout_weight="0.7" >

             <LinearLayout
                 android:layout_width="fill_parent"
                 android:layout_height="186dp"
                 android:orientation="vertical" >

                 <ImageView
                     android:id="@+id/pic"
                     android:layout_width="fill_parent"
                     android:layout_height="fill_parent"
                     android:layout_weight="1" />

                 <TextView
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:layout_weight="1"
                     android:text="Facial recognition"
                     android:textAppearance="?android:attr/textAppearanceMedium" />

                 <TextView
                     android:id="@+id/text3"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:layout_weight="1"
                     android:text="Small Text"
                     android:textAppearance="?android:attr/textAppearanceSmall" />

                 <TextView
                     android:id="@+id/avmarwe"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:layout_weight="1"
                     android:text="Gender and age"
                     android:textAppearance="?android:attr/textAppearanceMedium" />

                 <TextView
                     android:id="@+id/text1"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:layout_weight="1"
                     android:text="Small Text"
                     android:textAppearance="?android:attr/textAppearanceSmall" />

                 <TextView
                     android:id="@+id/skahasd"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:layout_weight="1"
                     android:text="Expression and mood"
                     android:textAppearance="?android:attr/textAppearanceMedium" />

                 <TextView
                     android:id="@+id/text2"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:layout_weight="1"
                     android:text="Small Text"
                     android:textAppearance="?android:attr/textAppearanceSmall" />

                 <TextView
                     android:id="@+id/dsfsfs"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:layout_weight="1"
                     android:text="Celebrity Facial Match"
                     android:textAppearance="?android:attr/textAppearanceMedium" />

                 <TextView
                     android:id="@+id/text4"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:layout_weight="1"
                     android:text="Small Text"
                     android:textAppearance="?android:attr/textAppearanceSmall" />
             </LinearLayout>
         </ScrollView>

     </LinearLayout>


    <LinearLayout
        android:id="@+id/linearLayout1"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom" >

        <Button
            android:id="@+id/c"
            android:layout_width="fill_parent"
            android:layout_height="50dp"
            android:layout_weight="0.7"
            android:text="" />

        <Button
            android:id="@+id/share"
            android:layout_width="70dp"
            android:layout_height="50dp"
            android:layout_weight="0.3"
            android:text="" />

    </LinearLayout>

</LinearLayout>

请检查以下内容:
  • https://dev59.com/TVLTa4cB1Zd3GeqPevDA
  • https://dev59.com/gG035IYBdhLWcg3wJcYv
  • https://dev59.com/amHVa4cB1Zd3GeqPpryd
- silwar
请查看我的问题(https://dev59.com/gG035IYBdhLWcg3wJcYv)下的“编辑:最终结果”部分。它是关于如何截取屏幕外页面的。但是相同的逻辑在任何地方都适用。 - Krishnabhadra
嗨Silwar,谢谢,我已经看过它们了。2个活动的链接似乎是我需要的最接近的,但我不想创建第二个活动。 - Reuben L.
1
我发现你的代码中有一些错误,涉及到u和v。 - user370305
1
实际上,我尝试了这段代码,它会截取父视图中所有视图的屏幕截图,无论它们是否在屏幕上可见...你不需要滚动。 - user370305
显示剩余10条评论
6个回答

20

感谢大家,我终于找到了问题所在。

View v = view.getRootView(); 不应该被使用,因为它会调用根视图,而我并不想要这个。我错误地认为这没有影响,因为我输入了错误的资源ID。

MeasureSpec 有些原因不能很好地说明宽度和高度。因此,我最终使用了另一种方法:

...
ScrollView z = (ScrollView) findViewById(R.id.scroll);
int totalHeight = z.getChildAt(0).getHeight();
int totalWidth = z.getChildAt(0).getWidth();
u.layout(0, 0, totalWidth, totalHeight);
...

ScrollView的总高度可以由其单个子元素确定。

在进行这些更改后,我现在可以对嵌套的ScrollView及其所有内容(可见或不可见)进行截屏。对于任何感兴趣的人,以下是包括位图保存的代码块:

            View u = findViewById(R.id.scroll);
            u.setDrawingCacheEnabled(true);                                                
            ScrollView z = (ScrollView) findViewById(R.id.scroll);
            int totalHeight = z.getChildAt(0).getHeight();
            int totalWidth = z.getChildAt(0).getWidth();
            u.layout(0, 0, totalWidth, totalHeight);    
            u.buildDrawingCache(true);
            Bitmap b = Bitmap.createBitmap(u.getDrawingCache());             
            u.setDrawingCacheEnabled(false);

            //Save bitmap
            String extr = Environment.getExternalStorageDirectory().toString() +   File.separator + "Folder";
            String fileName = new SimpleDateFormat("yyyyMMddhhmm'_report.jpg'").format(new Date());
            File myPath = new File(extr, fileName);
            FileOutputStream fos = null;
            try {
                fos = new FileOutputStream(myPath);
                b.compress(Bitmap.CompressFormat.JPEG, 100, fos);
                fos.flush();
                fos.close();
                MediaStore.Images.Media.insertImage(getContentResolver(), b, "Screen", "screen");
            }catch (FileNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

对不起,我可以问一下,这些代码真的有帮助吗?我遇到了与你的问题相同的情况,但是当我尝试你的代码时,它并没有显示出我想要的视图,只有黑屏。 - Menma
是的,代码运行良好,应用程序已经发布了2年。你是否相应地调整了变量? - Reuben L.
哎呀,我没看到这行代码 View u = findViewById(R.id.scroll); ,非常感谢你。 - Menma
可以获取GridView的屏幕截图,我尝试了您的代码,它获取了整个GridView的高度和宽度,但没有内容(即图像),它显示黑色方框。 - Hiren Dabhi
那个可以,但是在截图后我需要重置ScrollView的宽度和高度。u.layout(0, 0, totalWidth, totalHeight); 这段代码会改变尺寸。 - Eren Yilmaz
我遇到了错误:“视图太大,无法适应绘图缓存,需要5258880字节,但只有3686400可用”。。我还没有找到解决方案,请帮帮我。 - Girish Patel

3

试一下这个,它对我来说很好用

TableLayout tabLayout = (TableLayout) findViewById(R.id.allview);
if (tabLayout != null) {
    Bitmap image = Bitmap.createBitmap(tabLayout.getWidth(),
            tabLayout.getHeight(), Config.ARGB_8888);
    Canvas b = new Canvas(image);
    tabLayout.draw(b);
}

2

编辑:看到楼主的评论后

您根本不需要考虑新的活动。假设您现在正在一个活动中。布局A是该活动的主要布局,布局B和C是布局A内的两个子布局。就像这样:

 Layout A -> Parent
 |
  -------Layout B
 |
  -------Layout C

现在,如果你只想要截取C的屏幕截图,
1)在activity的onCreate()中。
 LinearLayout myCLayout = (LinearLayout)this.findViewbyId(R.id.my_c_layout);
 ViewTreeObserver vto   =  myCLayout.getViewTreeObserver();
 vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
   @Override
   public void onGlobalLayout() {
      //fully drawn, no need of listener anymore
      myCLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
      getDrawingBitmap();
   }
 });

getDrawingBitmap() 是一个函数,用于获取您的屏幕截图。

public void getDrawingBitmap(){
    LinearLayout myCLayout = (LinearLayout)this.findViewbyId(R.id.my_c_layout);
    Bitmap b = myCLayout.getDrawingCache();

    File file = saveBitmapAsFile(b);
}

编辑:对于ScrollView

我从未尝试过,但我认为你可以这样做。

1)首先重写ScrollView,然后重写onMeasure函数。

public class MyScrollView extends ScrollView{
    public MyScrollView(Context context, AttributeSet attrs) {
         super(context, attrs);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
        super.onMeasure(widthMeasureSpec, yourFullScrollViewHeight));
    }
}

在您的布局中使用MyScrollView。这里的yourFullScrollViewHeight是您需要截屏的所有scrollView内容的高度。我从未尝试过这个方法,但它可能有效。


我仍然无法使用这种方法完整地捕获整个滚动视图的图像。我猜这与正常的屏幕外问题略有不同,因为滚动视图中未显示的内容被视为位于屏幕外。 - Reuben L.
请查看我的编辑。我不能保证它是否有效,但如果我是你,我会尝试一下。 - Krishnabhadra
1
抱歉,我回答后你才发布了你的XML。你可能需要覆盖scrollView内部的LinearLayout,就像我在我的答案中覆盖scrollView一样。覆盖onMeasure并返回完整的内容高度。然后当你截屏时,截取线性布局(scrollView内部的那个)的截图,而不是scrollView。我认为这样会起作用。 - Krishnabhadra
1
虽然我最终用另一种方法解决了这个问题,但我认为你可能是正确的。感谢你的帮助! - Reuben L.
@ReubenL。我想捕获RelativeLayout的屏幕,其中包含2个子视图ImageView和TextView,TextView是可移动的,我已经尝试了一些代码,但是没有得到位图,因为在调用另一个ImageView后它并没有显示出来。 - Abdul Wahab

2

这里是您想要的确切解决方案,它将显示整个屏幕,包括在您的ScrollView中隐藏的内容。

LayoutInflater inflater = (LayoutInflater) this.getSystemService(LAYOUT_INFLATER_SERVICE);
FrameLayout root = (FrameLayout) inflater.inflate(R.layout.activity_main, null); // activity_main is UI(xml) file we used in our Activity class. FrameLayout is root view of my UI(xml) file.
root.setDrawingCacheEnabled(true);
Bitmap bitmap = getBitmapFromView(this.getWindow().findViewById(R.id.frameLayout)); // here give id of our root layout (here its my FrameLayout's id)

在您的 ImageView 中显示位图或按您的意愿使用它。
享受.....


0

我也遇到了这个问题,然后自己编写了代码。

我使用了这段代码来截取整个布局的屏幕截图。

我修改了列表大小和一些数学项。

请查看以下网站


-1
尝试这段代码
公共位图 screenShot(View view) {
    Bitmap bitmap = Bitmap.createBitmap(view.getWidth(),
    view.getHeight(), Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(bitmap);
    view.draw(canvas);
    return bitmap;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接