CaptureSession/Viewcontroller with capture session not being dismissed xamarin ios

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

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

  1. public override Task<ImageData> ScanId(PictureQuality quality)
  2. {
  3. _quality = quality;
  4. _scanIdViewController = new ScanIdViewController();
  5. _scanIdViewController.ModalPresentationStyle = UIModalPresentationStyle.FullScreen;
  6. _scanIdViewController.ImagePicked += CustomCam_ImagePicked;
  7. UIWindow window = UIApplication.SharedApplication.KeyWindow;
  8. var rootController = window.RootViewController;
  9. while (rootController.PresentedViewController != null)
  10. rootController = rootController.PresentedViewController;
  11. rootController.PresentViewController(_scanIdViewController, true, null);
  12. _imageDataPickedCompletionSource = new TaskCompletionSource<ImageData> { };
  13. return _imageDataPickedCompletionSource.Task;
  14. }
  15. private void CustomCam_ImagePicked(object sender, EventArgs e)
  16. {
  17. if (sender is ScanIdViewController scanIdController && scanIdController.Image is { })
  18. {
  19. using (NSData imageData = scanIdController.Image.AsPNG())
  20. {
  21. byte[] data = new byte[imageData.Length];
  22. Marshal.Copy(imageData.Bytes, data, 0, Convert.ToInt32(imageData.Length));
  23. var scaledBytes = GetScaledImage(data);
  24. _imageDataPickedCompletionSource.SetResult(new ImageData(scaledBytes, null, RotationNeeded(GetPicInfo(data)), true));
  25. };
  26. }
  27. }

字符串
则ScanIdViewController:

  1. public class ScanIdViewController: UIViewController
  2. {
  3. public event EventHandler ImagePicked;
  4. public UIImage Image { get; private set; }
  5. private PhotoCaptureDelegate _delegate;
  6. private AVCaptureSession _captureSession;
  7. private CGRect _outlineRect;
  8. IExceptionHandler _exceptionHandler = DependencyContainer.Current.Resolve<IExceptionHandler>();
  9. public override void ViewDidLoad()
  10. {
  11. base.ViewDidLoad();
  12. // Create a new AVCaptureSession
  13. _captureSession = new AVCaptureSession() { SessionPreset = AVCaptureSession.PresetPhoto };
  14. // Set the capture session's preset to high quality
  15. _captureSession.SessionPreset = AVCaptureSession.PresetHigh;
  16. // Get the back camera device
  17. var backCamera = AVCaptureDevice.GetDefaultDevice(AVCaptureDeviceType.BuiltInWideAngleCamera, AVMediaTypes.Video, AVCaptureDevicePosition.Back);
  18. // Create a new AVCaptureDeviceInput using the back camera
  19. var input = AVCaptureDeviceInput.FromDevice(backCamera);
  20. // Add the input to the capture session
  21. _captureSession.AddInput(input);
  22. // Create a new AVCaptureVideoPreviewLayer
  23. var previewLayer = new AVCaptureVideoPreviewLayer(_captureSession);
  24. SetupPreviewLayer(previewLayer);
  25. var capturePhotoOutput = new AVCapturePhotoOutput();
  26. _delegate = new PhotoCaptureDelegate();
  27. _delegate.ImagePicked += PhotoCaptureDelegate_ImagePicked;
  28. _captureSession.AddOutput(capturePhotoOutput);
  29. var captureButton = new UIButton(UIButtonType.System);
  30. captureButton.Frame = new CGRect(0, 0, 50, 50);
  31. captureButton.Center = new CGPoint(View.Bounds.GetMidX(), View.Bounds.GetMaxY() - 50);
  32. captureButton.BackgroundColor = UIColor.White;
  33. captureButton.Layer.CornerRadius = 25;
  34. captureButton.TouchUpInside += (sender, e) =>
  35. {
  36. var photoSettings = AVCapturePhotoSettings.Create();
  37. capturePhotoOutput.CapturePhoto(photoSettings, _delegate);
  38. };
  39. View.AddSubview(captureButton);
  40. _captureSession.StartRunning();
  41. }
  42. private void PhotoCaptureDelegate_ImagePicked(object sender, EventArgs e)
  43. {
  44. if (sender is PhotoCaptureDelegate del && del.Image is { })
  45. {
  46. var bounds = UIScreen.MainScreen.Bounds;
  47. var aspectX = del.Image.Size.Width / bounds.Width;
  48. var aspectY = del.Image.Size.Height / bounds.Height;
  49. var cutImage = del.Image.CropImage((int)(_outlineRect.X * aspectX), (int)(_outlineRect.Y * aspectY), (int)(_outlineRect.Width * aspectX), (int)(_outlineRect.Height * aspectY));
  50. var previewImageView = new UIImageView(new CGRect(0, 0, UIScreen.MainScreen.Bounds.Width, UIScreen.MainScreen.Bounds.Height - 100)) { Image = cutImage };
  51. var previewController = new PreviewImageViewController(previewImageView);
  52. previewController.ModalPresentationStyle = UIModalPresentationStyle.FullScreen;
  53. previewController.ImageAccepted += PreviewController_ImageAccepted;
  54. UIWindow window = UIApplication.SharedApplication.KeyWindow;
  55. var rootController = window.RootViewController;
  56. while (rootController.PresentedViewController != null)
  57. rootController = rootController.PresentedViewController;
  58. rootController.PresentViewController(previewController, true, null);
  59. }
  60. }
  61. private void PreviewController_ImageAccepted(object sender, EventArgs e)
  62. {
  63. Image = _delegate.Image;
  64. ImagePicked?.Invoke(this, EventArgs.Empty);
  65. if (_captureSession.Running)
  66. {
  67. Device.BeginInvokeOnMainThread(() => _captureSession.StopRunning());
  68. Device.BeginInvokeOnMainThread(() => DismissModalViewController(true));
  69. }
  70. }
  71. private void SetupPreviewLayer(AVCaptureVideoPreviewLayer avCapturePreviewLayer)
  72. {
  73. avCapturePreviewLayer.VideoGravity = AVLayerVideoGravity.ResizeAspectFill;
  74. avCapturePreviewLayer.Connection.VideoOrientation = AVCaptureVideoOrientation.Portrait;
  75. avCapturePreviewLayer.Frame = UIScreen.MainScreen.Bounds;
  76. View.Layer.InsertSublayer(avCapturePreviewLayer, 0);
  77. var overlay = CreateImageOverlay();
  78. View.AddSubview(overlay);
  79. }


然后是PreviewImageViewController:

  1. public class PreviewImageViewController : UIViewController
  2. {
  3. private UIImageView _previewImageView;
  4. public event EventHandler ImageAccepted;
  5. public PreviewImageViewController(UIImageView previewImageView)
  6. {
  7. _previewImageView = previewImageView;
  8. }
  9. public override void ViewDidLoad()
  10. {
  11. base.ViewDidLoad();
  12. SetUpPreviewImageView();
  13. }
  14. private void SetUpPreviewImageView()
  15. {
  16. _previewImageView.ContentMode = UIViewContentMode.ScaleAspectFit;
  17. UIButton acceptButton = new UIButton();
  18. acceptButton.SetTitle("Foto verwenden", UIControlState.Normal);
  19. acceptButton.SetTitleColor(UIColor.White, UIControlState.Normal);
  20. acceptButton.BackgroundColor = UIColor.Black;
  21. acceptButton.Frame = new CGRect(0, View.Frame.Height - 100, View.Frame.Width / 2, 100);
  22. acceptButton.SetTitleColor(UIColor.White, UIControlState.Normal);
  23. acceptButton.TouchUpInside += (sender, e) =>
  24. {
  25. _previewImageView.Image = _previewImageView.Image;
  26. ImageAccepted?.Invoke(this, EventArgs.Empty);
  27. DismissModalViewController(true);
  28. };
  29. UIButton retakeButton = new UIButton();
  30. retakeButton.Frame = new CGRect(View.Frame.Width / 2, View.Frame.Height - 100, View.Frame.Width / 2, 100);
  31. retakeButton.SetTitle("Wiederholen", UIControlState.Normal);
  32. retakeButton.SetTitleColor(UIColor.White, UIControlState.Normal);
  33. retakeButton.BackgroundColor = UIColor.Black;
  34. retakeButton.TouchUpInside += (sender, e) =>
  35. {
  36. DismissModalViewController(true);
  37. };
  38. View.AddSubview(_previewImageView);
  39. View.Add(acceptButton);
  40. View.Add(retakeButton);
  41. }
  42. }


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

u5rb5r59

u5rb5r591#

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

  1. public class PreviewImageViewController : UIViewController
  2. {
  3. private UIImageView _previewImageView;
  4. public event EventHandler ImageAccepted;
  5. private bool _imagePicked;
  6. ...
  7. private void SetUpPreviewImageView()
  8. {
  9. ...
  10. acceptButton.TouchUpInside += (sender, e) =>
  11. {
  12. _imagePicked = true;
  13. DismissModalViewController(true);
  14. };
  15. ...
  16. }
  17. public override void ViewDidDisappear(bool animated)
  18. {
  19. base.ViewDidDisappear(animated);
  20. if (_imagePicked)
  21. {
  22. ImageAccepted?.Invoke(this, EventArgs.Empty);
  23. }
  24. }
  25. ...
  26. }

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

  1. private void PreviewController_ImageAccepted(object sender, EventArgs e)
  2. {
  3. Image = _delegate.Image;
  4. ImagePicked?.Invoke(this, EventArgs.Empty);
  5. _shouldClose = true;
  6. Device.BeginInvokeOnMainThread(() => DismissModalViewController(true));
  7. }
  8. public override void ViewWillDisappear(bool animated)
  9. {
  10. base.ViewWillDisappear(animated);
  11. if (_shouldClose)
  12. Device.BeginInvokeOnMainThread(() =>
  13. {
  14. _captureSession.StopRunning();
  15. foreach (var input in _captureSession.Inputs)
  16. _captureSession.RemoveInput(input);
  17. foreach (var output in _captureSession.Outputs)
  18. _captureSession.RemoveOutput(output);
  19. _captureSession.Dispose();
  20. });
  21. }

展开查看全部

相关问题