【问题标题】:Xamarin Android take screenshotXamarin Android 截图
【发布时间】:2016-04-03 12:05:53
【问题描述】:

我正在做一个绘图项目。

我不使用 axml,因为我在一个名为 fillpolygon 的类中进行绘图并在 MainActivity 中调用该函数。我只想在我的项目中截屏。是否有任何基本功能,我可以在 onCreate 方法中调用?因此,当程序运行时,它会自动截取屏幕截图。除了 Xamarin 平台,我找到了答案。

【问题讨论】:

标签: c# android xamarin


【解决方案1】:

由于 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();
        }

    }

【讨论】:

    【解决方案2】:

    在您的视图中,您可以运行以下代码来截取屏幕截图。我之前没有尝试在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;
    }
    

    【讨论】:

    • @Aniki:查看编辑,如果有帮助请标记为答案。
    • 我一般来说是 xamarin 和 android 的新手,但如何将 DrawingCacheEnabled 设置为 true? VS 向我报告当前上下文中不存在名称“DrawingCacheEnabled”。
    • @Lexu 您需要从您的 Xamarin Android 项目代码中执行此操作。请参阅下面的 Amalan Dhananjayan 的答案,他设置了view.DrawingCacheEnabled = true;
    • 我意识到了这一点,但我找不到获得当前视图的方法。一切都归结为使用当前活动或当前视图。但我都找不到。
    • @Lexu 需要查看一些代码。我建议提出一个新问题,并在此处的 cmets 区域发布新问题的链接。请务必将您当前的代码放在问题中
    猜你喜欢
    • 2017-10-09
    • 1970-01-01
    • 1970-01-01
    • 2017-06-26
    • 2011-06-11
    • 1970-01-01
    • 1970-01-01
    • 2017-03-01
    • 1970-01-01
    相关资源
    最近更新 更多