【问题标题】:android taking screenshot of offscreen pageandroid截取屏幕外页面
【发布时间】:2011-08-02 00:37:25
【问题描述】:

我正在开发一个安卓应用程序。我有一个活动,比如 A,它用视图填充整个屏幕。在 A 中单击按钮时,我想启动另一个活动,比如 B,它也有一些视图和控件。我希望活动 B 不在屏幕上,并想从 A 截取 B 的屏幕截图。可能吗?

注意:我通过将绘图缓存保存到位图中成功地截取了页面 A 的屏幕截图,但很难截取屏幕外页面的屏幕截图。

【问题讨论】:

    标签: android android-activity screenshot off-screen


    【解决方案1】:

    我认为这样做会非常困难,因为我不知道如何控制这些视图的绘制方法,而且除非可见,否则 android 操作系统也不会绘制它们。

    但是,也可以只在很短的时间内将其他 View 置于前景以填充其绘图缓存。也许它甚至可以在它变得可见之前再次放置背景,因为为了流畅的体验,操作系统似乎在它们实际合成到前景之前将视图绘制在屏幕外。

    另一个技巧可能是将您的前景视图作为子视图附加到背景上,并赋予它非常轻微的 alpha 透明度。例如 WebView 可以通过这种方式很好地叠加,实际上是强制同时绘制 WebView 及其背景。也许这也适用于其他视图。

    【讨论】:

    • "android 操作系统也不会绘制它们,除非可见"你确定吗?如果是,那就杀了它..
    • “可见”并不是一个确切的术语。例如,如果一个 View 的一个像素由于一个小容器 View 包围它而可见,则需要调用它的 onDraw(Canvas) 方法,因为操作系统无法知道画布上的 onDraw 将实际绘制的位置。因此,使用一些 onDraw 方法的用户定义的 Wievs 将绘制。但是,内部包含 UI 元素的布局视图不得:每个 UI 元素都是独立的视图,如果系统认为不可见,则可能会被忽略。
    • 也许您可以使用自己的 Canvas 在invalidate() 之后调用draw(Canvas) 自己绘制视图。
    • “可见”并不是一个确切的术语。例如,如果一个 View 的一个像素由于一个小容器 View 包围它而可见,则需要调用它的 onDraw(Canvas) 方法“->你就在那里..让我试试那个..
    【解决方案2】:

    是的,有可能...您应该在活动“A”中扩展 ActivityGroup。 然后在您的按钮单击事件中执行此操作...

     View view =getLocalActivityManager().startActivity("B",new Intent(this,B.class).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)).getDecorView();
    

    然后将该视图转换为位图...

    我认为这对你有帮助...

    【讨论】:

    • 谢谢John..我的A类已经在扩展Activity了,而java不允许多重继承..那么如何让A扩展ActivityGroup..
    • 哎呀,我的继承部分是正确的...只是扩展activityGroup而不是activity..现在尝试截屏..
    • 好吧,我无法截取我得到的这个 DecorView 的屏幕截图。如何在这个 decorView 中获取主布局。对于我的 onScreen 活动,我截取了 mainLayout 的屏幕截图。如何从此 decorView 获取我的 offScreen 的 mainLayout
    • 如何获取这个decorView()的位图。decorView的getDrawingCache()总是返回null。
    • 最后我没有使用你描述的方法。我仍然从你的回答开始,最后得到了我想要的。但我认为有更好的方法(更直接)。如果你读到这个,请举例说明你将如何做到这一点。
    【解决方案3】:

    我使用这种方式效果很好,但是有一个问题,我只是在第一次拍摄快照时拍摄一个布局的快照,它给了我正确的照片,但经过一些更改后,我再次拍摄它,它给了我之前的快照。

    p>
    RelativeLayout layout = (RelativeLayout)findViewById(R.id.mainview);
        layout.setDrawingCacheEnabled(true);
        layout.setDrawingCacheQuality(LinearLayout.DRAWING_CACHE_QUALITY_HIGH);
        layout.buildDrawingCache();
        Bitmap bitmap = layout.getDrawingCache();
    
              File file =  new File(Environment.getExternalStorageDirectory().toString() + "/sPenimg.png");
              FileOutputStream ostream;
              try {
                  ostream = new FileOutputStream(file);
                  bitmap.compress(CompressFormat.PNG, 100, ostream);
                  ostream.flush();
                  ostream.close();      
              } catch (FileNotFoundException e) {
                  // TODO Auto-generated catch block
                  e.printStackTrace();
              } catch (IOException e) {
                  // TODO Auto-generated catch block
                  e.printStackTrace();
              }
    

    这个问题解决了添加 ((RelativeLayout)findViewById(R.id.mainview)).destroyDrawingCache();

    【讨论】:

      【解决方案4】:

      嗯,我已经实现了我想要的。这些是我使用的步骤。

      1. 使用 startActivityForResult() 而不是启动活动 B 开始活动()。

        Intent bIntent = new Intent(A.this,B.class);
        startActivityForResult(bIntent,B_REQUEST_CODE);
        
      2. 在活动 B 的 onCreate 中,获取 B 的 mainLayout 并启用其 绘图缓存

        final LinearLayout layout = (LinearLayout)
                             findViewById(R.id.app_parent_layout);
        layout.setDrawingCacheEnabled(true);
        layout.setDrawingCacheQuality(LinearLayout.DRAWING_CACHE_QUALITY_HIGH);
        
      3. 在活动 B 中等到它的布局完全绘制(这是非常 重要的)。在活动 B 的 onCreate() 中,获取 mainLayout 的 B、使用ViewTreeObserver获取其布局绘制时的回调 完全。

        ViewTreeObserver vto = layout.getViewTreeObserver();
        vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
         @Override
         public void onGlobalLayout() {
          layout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
          getDrawingBitmap();
         }
        });
        
      4. 现在在完全绘制布局时调用 getDrawingBitmap()。 截图吧。

        public void getDrawingBitmap(){
            LinearLayout mainLayout = (LinearLayout)
                                findViewById(R.id.app_parent_layout);
            Bitmap b = mainLayout.getDrawingCache();
        
            File file = saveBitmapAsFile(b);
        
            Intent resultIntent = new Intent();
            resultIntent.putExtra("FullFileName",file.getAbsolutePath());
            setResult(Activity.RESULT_OK,resultIntent);
            finish();
        }
        

        我在这里获取位图并将其保存为文件并返回 文件名作为结果代码。我相信有更好的方法发送 位图到父活动而不是保存为文件并发送 文件名。但无论如何我都需要保存位图 有时。所以对我来说这是更简单的方法。设置结果后 完成活动。

      5. 现在在 Activity A onActivityResult() 上检索文件名。

        public void onActivityResult(int requestCode, int resultCode, Intent data) {
          super.onActivityResult(requestCode, resultCode, data);
          if(requestCode == B_REQUEST_CODE){
            if (resultCode == Activity.RESULT_OK) { 
              String newText = data.getStringExtra("FullFileName");
             File dir = new File (newText);
            } 
          }
        }
        

      【讨论】:

      • 这里的问题是,这个活动 B 怎么还会出现在屏幕外?你这里没有处理这个的代码吗?
      • @Peterdk 这里的问题是,这个活动 B 怎么还会出现在屏幕外? 活动 B 根本不会出现。它在出现在屏幕上之前就完成了(参见 getDrawingBitmap 方法中的 finish() 调用)。
      • 好的,我现在明白了。但是,当我自己尝试时,我看到新活动的短暂闪烁,因此它不是真正的解决方案。
      • @Peterdk 不,我知道。这不是最好的解决方案。但是当我使用它时,没有闪光灯。您能否检查您的 getDrawingBitmap() 方法是否在 onResume() 调用之前被调用?我认为没有其他方法可以在 android 中调用屏幕外的活动(如果有人纠正我很高兴)。
      • 也许将屏幕截图传递回活动的更好方法是将其序列化为字节数组(将其序列化为压缩,例如转换为值为 90 的 png),然后将其设置为捆绑额外内容。在其他活动中,从字节数组中读取此位图。
      猜你喜欢
      • 1970-01-01
      • 2010-10-12
      • 2021-07-12
      • 2011-08-02
      • 2019-03-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-21
      相关资源
      最近更新 更多