如何将scrollview中的所有内容转换为位图?

18
我使用以下代码进行转换,但似乎只能获取显示屏中的内容,无法获取不在显示屏中的内容。
是否有一种方法可以获取所有内容,即使超出了滚动范围?
Bitmap viewBitmap = Bitmap.createBitmap(mScrollView.getWidth(),mScrollView.getHeight(),Bitmap.Config.ARGB_8888);  
Canvas canvas = new Canvas(viewBitmap); 
mScrollView.draw(canvas);
5个回答

37
我们可以使用下面的代码将scrollView的所有内容转换为位图图像。
private void takeScreenShot() 
{
    View u = ((Activity) mContext).findViewById(R.id.scroll);

    HorizontalScrollView z = (HorizontalScrollView) ((Activity) mContext).findViewById(R.id.scroll);
    int totalHeight = z.getChildAt(0).getHeight();
    int totalWidth = z.getChildAt(0).getWidth();

    Bitmap b = getBitmapFromView(u,totalHeight,totalWidth);             

    //Save bitmap
    String extr = Environment.getExternalStorageDirectory()+"/Folder/";
    String fileName = "report.jpg";
    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(mContext.getContentResolver(), b, "Screen", "screen");
    }catch (FileNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

}

public Bitmap getBitmapFromView(View view, int totalHeight, int totalWidth) {

    Bitmap returnedBitmap = Bitmap.createBitmap(totalWidth,totalHeight , Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(returnedBitmap);
    Drawable bgDrawable = view.getBackground();
    if (bgDrawable != null)
        bgDrawable.draw(canvas);
    else
        canvas.drawColor(Color.WHITE);
    view.draw(canvas);
    return returnedBitmap;
}

1
当使用scrollTo方法时,希望内部滚动其内容的视图无法正常工作。http://developer.android.com/reference/android/view/View.html#scrollTo%28int,%20int%29 - LOG_TAG
这在 Android Oreo 或更高版本上无法工作。 - Johann
1
实际的截屏代码在Android 12上仍然完美运行,但是文件保存逻辑现在出现了问题。 - Luke Needham

9

Pops的回答很好,但在某些情况下,您可能需要创建一个非常大的位图,这可能会在创建位图时触发OutOfMemoryException异常。

因此,我进行了一些小优化,以使内存更加友好 :)

public static Bitmap getBitmapFromView(View view, int totalHeight, int totalWidth) {

   int height = Math.min(MAX_HEIGHT, totalHeight);
   float percent = height / (float)totalHeight;

   Bitmap canvasBitmap = Bitmap.createBitmap((int)(totalWidth*percent),(int)(totalHeight*percent), Bitmap.Config.ARGB_8888);
   Canvas canvas = new Canvas(canvasBitmap);

   Drawable bgDrawable = view.getBackground();
   if (bgDrawable != null)
      bgDrawable.draw(canvas);
   else
      canvas.drawColor(Color.WHITE);

   canvas.save();
   canvas.scale(percent, percent);
   view.draw(canvas);
   canvas.restore();

   return canvasBitmap;
}

它创建了一个缩放位图(使其高度<= MAX_HEIGHT)。您应该使用int totalHeight = scrollView.getChildAt(0).getHeight();来获取ScrollView的高度。如果位图变小,稍后可以将其放大。 - CoolMind

5

这个对我有效

在保存位图之前,请先检查运行时权限

 @OnClick(R.id.donload_arrow)
    public void DownloadBitMap()
    {
     if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) 
    {
        downloadData();
                    Log.e("callPhone: ", "permission" );
                } else {
                    ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0);
                    Toast.makeText(this, "need permission", Toast.LENGTH_SHORT).show();
                }

            }

获取位图
 private void downloadData() {

        ScrollView iv = (ScrollView) findViewById(R.id.scrollView);
        Bitmap bitmap = Bitmap.createBitmap(
                iv.getChildAt(0).getWidth()*2,
                iv.getChildAt(0).getHeight()*2,
                Bitmap.Config.ARGB_8888);
        Canvas c = new Canvas(bitmap);
        c.scale(2.0f, 2.0f);
        c.drawColor(getResources().getColor(R.color.colorPrimary));
        iv.getChildAt(0).draw(c);
        // Do whatever you want with your bitmap
        saveBitmap(bitmap);

    }

保存位图
 public void saveBitmap(Bitmap bitmap) {
        File folder = new File(Environment.getExternalStorageDirectory() +
                File.separator + "SidduInvoices");
        boolean success = true;
        if (!folder.exists()) {
            success = folder.mkdirs();
        }
        if (success) {
            // Do something on success
        } else {
            // Do something else on failure
        }

        File imagePath = new File(Environment.getExternalStorageDirectory() + "/SidduInvoices/Siddus.png");

        if(imagePath.exists())
        {
            imagePath=new File(Environment.getExternalStorageDirectory() + "/SidduInvoices/Siddus"+custamername.getText().toString()+".png");

        }
        FileOutputStream fos;
        try {
            fos = new FileOutputStream(imagePath);
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
            fos.flush();
            fos.close();
            progressBar.cancel();


            final File finalImagePath = imagePath;
            new SweetAlertDialog(this, SweetAlertDialog.SUCCESS_TYPE)
                    .setTitleText("Saved")
                    .setContentText("Do you want to share this with whatsapp")
                    .setCancelText("No,cancel !")
                    .setConfirmText("Yes,share it!")
                    .showCancelButton(true)
                    .setConfirmClickListener(new SweetAlertDialog.OnSweetClickListener() {
                        @Override
                        public void onClick(SweetAlertDialog sweetAlertDialog) {
                            sweetAlertDialog.cancel();
                            shareImage(finalImagePath);
                        }
                    })
                    .setCancelClickListener(new SweetAlertDialog.OnSweetClickListener() {
                        @Override
                        public void onClick(SweetAlertDialog sDialog) {
                            sDialog.cancel();

                        }
                    })
                    .show();




        } catch (FileNotFoundException e) {
            Log.e("GREC", e.getMessage(), e);
        } catch (IOException e) {
            Log.e("GREC", e.getMessage(), e);
        }



    }

2
您需要获取ScrollView的总宽度和高度,或者您创建的viewBitmap太小,无法容纳ScrollView的全部内容。
请查看此链接: Android: ScrollView的总高度

谢谢!这是这个主题的关键答案。 - CoolMind

1
问题在于实际存在的唯一像素内容,是那些在显示屏上可见的。Android和其他移动平台非常注意内存使用,滚动视图保持性能的一种方式是不绘制任何超出屏幕的内容。因此没有任何 "完整" 的位图 -- 含有移出屏幕内容的内存会被回收利用。

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