Ошибка «Попытка представить Xamarin_Forms_Platform_iOS_ModalWrapper, чье представление не находится в иерархии окон» с помощью UIImagePickerController - PullRequest
3 голосов
/ 17 мая 2019

У меня есть приложение на основе Xamarin.Forms, которое работает на Android и iOS. Прямо сейчас я реализую функцию выбора изображений с камеры и загрузки их на наш сервер. Поэтому я пишу специфичный для платформы код для iOS, где и происходит ошибка.

Я вызываю UIImagePickerController из специфичного для платформы средства визуализации для iOS. Открывается нормально. Но при нажатии на изображение в UIImagePickerController ничего не происходит, кроме Visual Studio, показывающего сообщение в консоли отладки:

"Предупреждение. Попытка представить Xamarin_Forms_Platform_iOS_ModalWrapper: 0x155a7ed00 в Xamarin_Forms_Platform_iOS_PlatformRenderer: 0x153ead6a0, представление которого отсутствует в иерархии окон!" * 1007

Я гуглил и обнаружил, что кто-то пишет функцию GetVisibleViewController, которую я адаптировал к своему проекту (вы можете увидеть это ниже). На ViewController, который возвращает эта функция, я вызываю метод PresentModalViewController (). К сожалению, это тоже не работает. Невозможно выбрать фотографию.

private void ChoosePhoto()
{
    _imagePicker = new UIImagePickerController()
    {
        SourceType = UIImagePickerControllerSourceType.PhotoLibrary,
        MediaTypes = new string[] { UTType.Image }
    };

    _imagePicker.FinishedPickingMedia += delegate (object sender, UIImagePickerMediaPickedEventArgs e)
    {
        var fileName = eopAppLibrary.Tools.GetTimestampJpegFileName("ScanToEop_iOS");
        var jpegImageData = e.OriginalImage.AsJPEG();
        var jpegBytes = jpegImageData.ToArray();

        Events.RaiseFilePreviewNeeded(this, jpegBytes, fileName);
    };

    _imagePicker.Canceled += delegate (object sender, EventArgs e)
    {
        _imagePicker.DismissModalViewController(true);
    };

    var viewController = GetVisibleViewController();
    viewController.PresentModalViewController(_imagePicker, true);
}
UIViewController GetVisibleViewController(UIViewController controller = null)
{
    controller = controller ?? UIApplication.SharedApplication.KeyWindow.RootViewController;

    if (controller.PresentedViewController == null)
    {
        return controller;
    }

    if (controller.PresentedViewController is UINavigationController)
    {
        return ((UINavigationController)controller.PresentedViewController).VisibleViewController;
    }

    if (controller.PresentedViewController is UITabBarController)
    {
        return ((UITabBarController)controller.PresentedViewController).SelectedViewController;
    }

    return GetVisibleViewController(controller.PresentedViewController);
}

Ответы [ 2 ]

1 голос
/ 17 мая 2019

У нас была похожая проблема, и вот что мы придумали:

    var topViewController = UIApplication.SharedApplication.KeyWindow.RootViewController;
    var controllerToPresentWith = topViewController.VisibleViewController();
    controllerToPresentWith.PresentModalViewController(_imagePicker, true);

, а затем

    ...
    public static UIViewController VisibleViewController(this UIViewController controller)
    {
        if (controller == null)
            return null;

        if (controller is UINavigationController navController)
        {
            return navController.VisibleViewController();
        }
        else if (controller is UITabBarController tabController)
        {
            tabController.SelectedViewController?.VisibleViewController();
        }
        else
        {
            var vc =  controller.PresentedViewController?.VisibleViewController();
            if (vc != null)
                return vc;
        }
        return controller;
    }
0 голосов
/ 23 мая 2019

В конце концов, я реализовал это с помощью библиотеки Media Plugin Джеймса Монтамано (доступно через NuGet: https://www.nuget.org/packages/Xam.Plugin.Media) и плагин Permissions (https://www.nuget.org/packages/Plugin.Permissions).

). Я написал для этого следующий код:

private async Task ChoosePhoto()
{
    var permission = await CheckCameraRollPermission();

    if (permission == PermissionStatus.Granted)
    {
        await CrossMedia.Current.Initialize();

        // Show image picker dialog
        var file = await CrossMedia.Current.PickPhotoAsync(new Plugin.Media.Abstractions.PickMediaOptions()
        {
            ModalPresentationStyle = Plugin.Media.Abstractions.MediaPickerModalPresentationStyle.OverFullScreen
        });

        if (file != null)
        {
            // Image has been selected
            using (var stream = file.GetStream())
            {
                using (var memoryStream = new System.IO.MemoryStream())
                {
                    stream.CopyTo(memoryStream);

                    var fileBytes = memoryStream.ToArray();

                    // DO WHATEVER YOU WANT TO DO WITH THE SELECTED IMAGE AT THIS POINT
                }
            }
        }
    }
}

private async Task<PermissionStatus> CheckCameraRollPermission()
{
    // Check permission for image library access
    var permission = await PermissionsImplementation.Current.CheckPermissionStatusAsync(Permission.Photos);

    if (permission != PermissionStatus.Granted)
    {
        // Permission has not been granted -> if permission has been requested before and the user did not grant it, show message and return the permission
        var message = "";

        switch (permission)
        {
            case PermissionStatus.Denied:
            case PermissionStatus.Restricted:
                message = "Unfortunately, you did not grant permission to access the camera roll. If you want to change this, you can do so in the system settings of your device.";
                break;
            default:
                break;
        }

        if (!string.IsNullOrEmpty(message))
        {
            // Message available -> Display alert and return the permission
            var alert = UIAlertController.Create("Permission not granted", message, UIAlertControllerStyle.Alert);
            alert.AddAction(UIAlertAction.Create("OK", UIAlertActionStyle.Default, null));

            PresentViewController(alert, true, null);
            return permission;
        }

        // In all other cases, request the permission
        await PermissionsImplementation.Current.RequestPermissionsAsync(Permission.Photos);

        // Check for permission one more time and return it
        permission = await PermissionsImplementation.Current.CheckPermissionStatusAsync(Permission.Photos);
    }

    return permission;
}
...