CaptureSession/Viewcontroller with capture session not being dismissed xamarin ios

bxgwgixi  于 2023-08-01  发布在  iOS
关注(0)|答案(1)|浏览(81)

我有一个CameraHelper类,专门为每个平台实现。在iOS中,我希望在CameraHelper中有一个所谓的ScanId函数,如下所示:

public override Task<ImageData> ScanId(PictureQuality quality)
        {
            _quality = quality;                  
            _scanIdViewController = new ScanIdViewController();
            _scanIdViewController.ModalPresentationStyle = UIModalPresentationStyle.FullScreen;
            _scanIdViewController.ImagePicked += CustomCam_ImagePicked;
            UIWindow window = UIApplication.SharedApplication.KeyWindow;
            var rootController = window.RootViewController;
            

            while (rootController.PresentedViewController != null)
                rootController = rootController.PresentedViewController;
            rootController.PresentViewController(_scanIdViewController, true, null);

            _imageDataPickedCompletionSource = new TaskCompletionSource<ImageData> { };
            return _imageDataPickedCompletionSource.Task;

        }

private void CustomCam_ImagePicked(object sender, EventArgs e)
        {
            if (sender is ScanIdViewController scanIdController && scanIdController.Image is { })
            {
                using (NSData imageData = scanIdController.Image.AsPNG())
                {
                    byte[] data = new byte[imageData.Length];
                    Marshal.Copy(imageData.Bytes, data, 0, Convert.ToInt32(imageData.Length));
                    var scaledBytes = GetScaledImage(data);
                    _imageDataPickedCompletionSource.SetResult(new ImageData(scaledBytes, null, RotationNeeded(GetPicInfo(data)), true));
                };
            }
        }

字符串
则ScanIdViewController:

public class ScanIdViewController: UIViewController
    {
        public event EventHandler ImagePicked;
        public UIImage Image { get; private set; }
        private PhotoCaptureDelegate _delegate;
        private AVCaptureSession _captureSession;
        private CGRect _outlineRect;
        IExceptionHandler _exceptionHandler = DependencyContainer.Current.Resolve<IExceptionHandler>();
        public override void ViewDidLoad()
        {
            base.ViewDidLoad();

            // Create a new AVCaptureSession
            _captureSession = new AVCaptureSession() { SessionPreset = AVCaptureSession.PresetPhoto };

            // Set the capture session's preset to high quality
            _captureSession.SessionPreset = AVCaptureSession.PresetHigh;

            // Get the back camera device
            var backCamera = AVCaptureDevice.GetDefaultDevice(AVCaptureDeviceType.BuiltInWideAngleCamera, AVMediaTypes.Video, AVCaptureDevicePosition.Back);

            // Create a new AVCaptureDeviceInput using the back camera
            var input = AVCaptureDeviceInput.FromDevice(backCamera);

            // Add the input to the capture session
            _captureSession.AddInput(input);

            // Create a new AVCaptureVideoPreviewLayer
            var previewLayer = new AVCaptureVideoPreviewLayer(_captureSession);
            SetupPreviewLayer(previewLayer);
            var capturePhotoOutput = new AVCapturePhotoOutput();

            _delegate = new PhotoCaptureDelegate();
            _delegate.ImagePicked += PhotoCaptureDelegate_ImagePicked;
            _captureSession.AddOutput(capturePhotoOutput);

            var captureButton = new UIButton(UIButtonType.System);
            captureButton.Frame = new CGRect(0, 0, 50, 50);
            captureButton.Center = new CGPoint(View.Bounds.GetMidX(), View.Bounds.GetMaxY() - 50);
            captureButton.BackgroundColor = UIColor.White;
            captureButton.Layer.CornerRadius = 25;
            captureButton.TouchUpInside += (sender, e) =>
            {
                var photoSettings = AVCapturePhotoSettings.Create();
                capturePhotoOutput.CapturePhoto(photoSettings, _delegate);
            };
            View.AddSubview(captureButton);

            _captureSession.StartRunning();
        }

        private void PhotoCaptureDelegate_ImagePicked(object sender, EventArgs e)
        {
            if (sender is PhotoCaptureDelegate del && del.Image is { })
            {
                var bounds = UIScreen.MainScreen.Bounds;
                var aspectX = del.Image.Size.Width / bounds.Width;
                var aspectY = del.Image.Size.Height / bounds.Height;
                var cutImage = del.Image.CropImage((int)(_outlineRect.X * aspectX), (int)(_outlineRect.Y * aspectY), (int)(_outlineRect.Width * aspectX), (int)(_outlineRect.Height * aspectY));

                var previewImageView = new UIImageView(new CGRect(0, 0, UIScreen.MainScreen.Bounds.Width, UIScreen.MainScreen.Bounds.Height - 100)) { Image = cutImage };
                var previewController = new PreviewImageViewController(previewImageView);
                previewController.ModalPresentationStyle = UIModalPresentationStyle.FullScreen;
                previewController.ImageAccepted += PreviewController_ImageAccepted;

                UIWindow window = UIApplication.SharedApplication.KeyWindow;
                var rootController = window.RootViewController;

                while (rootController.PresentedViewController != null)
                    rootController = rootController.PresentedViewController;
                rootController.PresentViewController(previewController, true, null);
            }
        }

        private void PreviewController_ImageAccepted(object sender, EventArgs e)
        {
            Image = _delegate.Image;
            ImagePicked?.Invoke(this, EventArgs.Empty);
            if (_captureSession.Running)
            {
                Device.BeginInvokeOnMainThread(() => _captureSession.StopRunning());
                Device.BeginInvokeOnMainThread(() => DismissModalViewController(true));
            }
        }

        private void SetupPreviewLayer(AVCaptureVideoPreviewLayer avCapturePreviewLayer)
        {
            avCapturePreviewLayer.VideoGravity = AVLayerVideoGravity.ResizeAspectFill;
            avCapturePreviewLayer.Connection.VideoOrientation = AVCaptureVideoOrientation.Portrait;
            avCapturePreviewLayer.Frame = UIScreen.MainScreen.Bounds;
            View.Layer.InsertSublayer(avCapturePreviewLayer, 0);
            var overlay = CreateImageOverlay();
            View.AddSubview(overlay);
        }


然后是PreviewImageViewController:

public class PreviewImageViewController : UIViewController
    {
        private UIImageView _previewImageView;
        public event EventHandler ImageAccepted;

        public PreviewImageViewController(UIImageView previewImageView)
        {
            _previewImageView = previewImageView;
        }

        public override void ViewDidLoad()
        {
            base.ViewDidLoad();
            SetUpPreviewImageView();

        }

        private void SetUpPreviewImageView()
        {
            _previewImageView.ContentMode = UIViewContentMode.ScaleAspectFit;

            UIButton acceptButton = new UIButton();
            acceptButton.SetTitle("Foto verwenden", UIControlState.Normal);
            acceptButton.SetTitleColor(UIColor.White, UIControlState.Normal);
            acceptButton.BackgroundColor = UIColor.Black;
            acceptButton.Frame = new CGRect(0, View.Frame.Height - 100, View.Frame.Width / 2, 100);
            acceptButton.SetTitleColor(UIColor.White, UIControlState.Normal);
            acceptButton.TouchUpInside += (sender, e) =>
            {
                _previewImageView.Image = _previewImageView.Image;
                ImageAccepted?.Invoke(this, EventArgs.Empty);
                DismissModalViewController(true);
            };

            UIButton retakeButton = new UIButton();
            retakeButton.Frame = new CGRect(View.Frame.Width / 2, View.Frame.Height - 100, View.Frame.Width / 2, 100);
            retakeButton.SetTitle("Wiederholen", UIControlState.Normal);
            retakeButton.SetTitleColor(UIColor.White, UIControlState.Normal);
            retakeButton.BackgroundColor = UIColor.Black;

            retakeButton.TouchUpInside += (sender, e) =>
            {
                DismissModalViewController(true);
            };
            View.AddSubview(_previewImageView);
            View.Add(acceptButton);
            View.Add(retakeButton);
        }
    }


问题是PreviewImageViewController被正确地解除了,但是即使Device.BeginInvokeOnMainThread(()=> DismissModalViewController(true));在ScanIdViewController.PreviewController_ImageAccepted中调用,视图在相机视图上保持冻结,覆盖,在这种情况下按钮不起作用。
我真的希望关闭查看/捕获会话并返回到下面的视图(在CameraHelper中调用ScanId之前)

u5rb5r59

u5rb5r591#

好了,通过更改在PreviewImageViewController上调用ImageAccepted的时间来解决这个问题-在ViewDidDisappear中:

public class PreviewImageViewController : UIViewController
    {
        private UIImageView _previewImageView;
        public event EventHandler ImageAccepted;
        private bool _imagePicked;
        ...
        private void SetUpPreviewImageView()
        {
         ...
            acceptButton.TouchUpInside += (sender, e) =>
            {
                _imagePicked = true;
                DismissModalViewController(true);
            };
            ...
        }
        public override void ViewDidDisappear(bool animated)
        {
           base.ViewDidDisappear(animated);
           if (_imagePicked)
           {
             ImageAccepted?.Invoke(this, EventArgs.Empty);
           }
         }
         ...
     }

字符串
然后将以下内容添加到ScanIdViewController:

private void PreviewController_ImageAccepted(object sender, EventArgs e)
        {
            Image = _delegate.Image;
            ImagePicked?.Invoke(this, EventArgs.Empty);
            _shouldClose = true;
            Device.BeginInvokeOnMainThread(() => DismissModalViewController(true));
        }

        public override void ViewWillDisappear(bool animated)
        {
            base.ViewWillDisappear(animated);
            if (_shouldClose) 
                Device.BeginInvokeOnMainThread(() =>
                {
                    _captureSession.StopRunning();
                    foreach (var input in _captureSession.Inputs)
                        _captureSession.RemoveInput(input);

                    foreach (var output in _captureSession.Outputs)
                        _captureSession.RemoveOutput(output);

                    _captureSession.Dispose();
                });
        }

相关问题