关于将屏幕外视图保存到位图有很多问题,而我却一无所获,这就是为什么我不认为这两者都是重复的。
背景
我的应用提供了相同数据的两种不同视图。这两个视图都是使用按设计方式工作的自定义视图来呈现的(一个视图使用的是SurfaceView,这在这种情况下很难做到)。要求以包含两个视图的图像的形式共享此数据(一次只有一个视图对用户可见,他们可以在视图之间切换)。为了改善用户体验,并且无论使用什么设备,都为相同的数据生成相同的图像,该数据每次都应包含在固定大小的位图(PNG)中。
方法
为了完成上述任务,我已经
fragment_screenshot_generator.xml
布局:(水平LinearLayout
的宽度和高度设置为match_parent
,其中包含2个FrameLayouts
,每个高度为match_parent
, layout_weight
(共1个)占整个屏幕的一半。出于测试目的,它们具有半透明的背景(分别为红色和绿色)DialogFragment
(进度对话框),该对话框应在后台完成此工作,并在屏幕截图保存到文件后自动关闭(将文件返回到父片段)fragment_screenshot_generator.xml
充气并在每个FrameLayout
中设置了两种视图类型。此处使用的代码与生成原始用户可见视图的代码完全相同。问题
除了视图背景外,什么都不会渲染到位图上。我怀疑我在某个地方错过了一个电话来告诉fragment_screenshot_generator.xml
的根“一切都很好” ,以便其中的视图可以呈现。我尝试过将其发布到布局根目录,但这是非常不可预测的,有时会花费很长时间,并且除了透明性外,什么也没有画。我必须将此布局附加到窗口吗?我可以将其附加到当前窗口而不显示它吗?您是否在我的代码中看到任何遗漏?
注释
我尝试过
NullPointerException
,因为getDrawingCache
方法返回null
。无论如何仍然不推荐使用。SurfaceView
部分为空。这是可以预期的,因为SurfaceView
本质上是一个'hole'。我怀疑PixelCopy
API不会因此受到影响。代码
fragment_screenshot_generator.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:baselineAligned="false"
android:orientation="horizontal">
<FrameLayout
android:id="@+id/view_1"
android:background="#4f00"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<FrameLayout
android:id="@+id/view_2"
android:background="#40f0"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
</LinearLayout>
ScreenshotGeneratorDialogFragment#onCreateDialog
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
viewModel = ViewModelProviders.of(activity!!).get(DetailViewModel::class.java)
val parameter1 = viewModel.dataTypeOne.value!!.parameter1
val parameter2 = viewModel.dataTypeOne.value!!.parameter2
screenshotView = View.inflate(context, R.layout.fragment_screenshot_generator, null).apply {
measure(View.MeasureSpec.makeMeasureSpec(SCREENSHOT_WIDTH, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(SCREENSHOT_HEIGHT, View.MeasureSpec.EXACTLY))
layout(0, 0, measuredWidth, measuredHeight)
setupViewTypeOne(findViewById(R.id.view_1)!!, parameter1, parameter2)
setupViewTypeTwo(findViewById(R.id.view_2)!!, parameter1, parameter2, viewModel.plotData.value)
layout(0, 0, measuredWidth, measuredHeight)
}
dialogView = View.inflate(context, R.layout.dialog_screenshot_generator, null).apply {
findViewById<TextView>(R.id.progress_label)!!.setText(R.string.preparing_screenshots)
}
val dialog = AlertDialog.Builder(context!!)
.setView(dialogView)
.create()
dialog.setOnShowListener { capture() }
return dialog
}
ScreenshotGeneratorDialogFragment#capture
private fun capture():File {
var bitmap = Bitmap.createBitmap(screenshotView.measuredWidth, screenshotView.measuredHeight, Bitmap.Config.ARGB_8888)
var canvas = Canvas(bitmap)
canvas.drawColor(0xffffffff.toInt())
screenshotView.draw(canvas)
// Saving to SDcard for testing. This will move to cache dir.
val file = File.createTempFile("share-", ".png", Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES))
file.outputStream().use {
bitmap.compress(Bitmap.CompressFormat.PNG, 0, it)
}
return file
}