【发布时间】:2016-04-03 12:05:53
【问题描述】:
我正在做一个绘图项目。
我不使用 axml,因为我在一个名为 fillpolygon 的类中进行绘图并在 MainActivity 中调用该函数。我只想在我的项目中截屏。是否有任何基本功能,我可以在 onCreate 方法中调用?因此,当程序运行时,它会自动截取屏幕截图。除了 Xamarin 平台,我找到了答案。
【问题讨论】:
我正在做一个绘图项目。
我不使用 axml,因为我在一个名为 fillpolygon 的类中进行绘图并在 MainActivity 中调用该函数。我只想在我的项目中截屏。是否有任何基本功能,我可以在 onCreate 方法中调用?因此,当程序运行时,它会自动截取屏幕截图。除了 Xamarin 平台,我找到了答案。
【问题讨论】:
由于 Android 28 DrawingCacheEnabled 已弃用,如果没有它,我们会强制视图在自定义画布上重绘,这可能会导致带有自定义控件和渲染器的伪影,并且屏幕截图版本可能与我们在屏幕上看到的不同。
仍在处理简单案例的遗留代码是:
public byte[] CaptureScreenshot()
{
var view=
Xamarin.Essentials.Platform.CurrentActivity.Window.DecorView.RootView;
if (view.Height < 1 || view.Width < 1)
return null;
byte[] buffer = null;
view.DrawingCacheEnabled = true;
using (var screenshot = Bitmap.CreateBitmap(
view.Width,
view.Height,
Bitmap.Config.Argb8888))
{
var canvas = new Canvas(screenshot);
view.Draw(canvas);
using (var stream = new MemoryStream())
{
screenshot.Compress(Bitmap.CompressFormat.Png, 90, stream);
buffer = stream.ToArray();
}
}
view.DrawingCacheEnabled = false;
return buffer;
}
使用上述遗留方法如下
if ((int)Android.OS.Build.VERSION.SdkInt < 28)
{
//legacy
}
DrawingCacheEnabled 过时警告将我们重定向到使用 PixelCopy。此方法与回调一起使用,因此要同步使用它需要一些帮助:
用法:
public byte[] CaptureScreenshot()
{
using var helper = new ScreenshotHelper(
Xamarin.Essentials.Platform.CurrentActivity.Window.DecorView.RootView,
Xamarin.Essentials.Platform.CurrentActivity);
byte[] buffer = null;
bool wait = true;
Task.Run(async () =>
{
helper.Capture((Bitmap bitmap) =>
{
try
{
if (!helper.Error)
{
using (var stream = new MemoryStream())
{
bitmap.Compress(Bitmap.CompressFormat.Png, 90, stream);
buffer = stream.ToArray();
}
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
finally
{
wait = false;
}
});
}).ConfigureAwait(false);
while (wait)
{
Task.Delay(10).Wait();
}
return buffer;
}
帮手:
public class ScreenshotHelper : Java.Lang.Object, PixelCopy.IOnPixelCopyFinishedListener
{
public void OnPixelCopyFinished(int copyResult)
{
var stop = true;
if (copyResult == (int) PixelCopyResult.Success)
{
Error = false;
//todo CallbackGotScreenshot();
_callback(_bitmap);
}
else
{
Error = true;
}
_callback(_bitmap);
}
public bool Error { get; protected set; }
public ScreenshotHelper(Android.Views.View view, Activity activity)
{
_view = view;
_activity = activity;
_bitmap = Bitmap.CreateBitmap(
_view.Width,
_view.Height,
Bitmap.Config.Argb8888);
}
// Starts a background thread and its {@link Handler}.
private void StartBackgroundThread()
{
_BackgroundThread = new HandlerThread("ScreeshotMakerBackground");
_BackgroundThread.Start();
_BackgroundHandler = new Handler(_BackgroundThread.Looper);
}
// Stops the background thread and its {@link Handler}.
private void StopBackgroundThread()
{
try
{
_BackgroundThread.QuitSafely();
_BackgroundThread.Join();
_BackgroundThread = null;
_BackgroundHandler = null;
}
catch (Exception e)
{
//e.PrintStackTrace();
}
}
public void Capture(Action<Bitmap> callback)
{
//var locationOfViewInWindow = new int[2];
//_view.GetLocationInWindow(locationOfViewInWindow);
_callback = callback;
try
{
StartBackgroundThread();
//todo could create-use background handler
PixelCopy.Request(_activity.Window, _bitmap, this,
_BackgroundHandler);
}
catch (Exception e)
{
Console.WriteLine(e);
}
finally
{
Task.Run(StopBackgroundThread);
}
}
private Android.Views.View _view;
private Activity _activity;
private Bitmap _bitmap;
private HandlerThread _BackgroundThread;
private Handler _BackgroundHandler;
private Action<Bitmap> _callback;
public new void Dispose()
{
_bitmap?.Dispose();
_bitmap= null;
_activity = null;
_view = null;
_callback = null;
base.Dispose();
}
}
【讨论】:
在您的视图中,您可以运行以下代码来截取屏幕截图。我之前没有尝试在OnCreate() 中运行它,因此您可能需要对其进行测试以确保视图已完全呈现。
*编辑:根据this post,您可能无法在OnCreate() 中运行此代码,因此您需要找到一个更好的地方。我无法弄清楚用户在他发布的链接中指的是什么帖子。
*编辑#2:刚刚发现Compress() 没有考虑质量参数(下面列为0),因为PNG 是无损的,但是如果您将格式更改为JPEG 等,那么您可能需要调高质量参数,因为您的图像看起来像垃圾。
public byte[] SaveImage() {
DrawingCacheEnabled = true; //Enable cache for the next method below
Bitmap bitmap = GetDrawingCache(true); //Gets the image from the cache
byte[] bitmapData;
using(MemoryStream stream = new MemoryStream()) {
bitmap.Compress(Bitmap.CompressFormat.Png, 0, stream);
bitmapData = stream.ToArray();
}
return bitmapData;
}
【讨论】:
view.DrawingCacheEnabled = true;