iOS Monotouch UIImagePickerController 来自相机的多张照片/视频

标签 ios xamarin.ios uiimagepickercontroller

我们在使用 UIImagePickerController 时遇到了一个奇怪的问题。在我们的应用程序中,用户可以填写一系列表格,还可以在这些表格中附加图片和视频。

我们允许用户从相机胶卷添加多张照片/视频,或者在填写表格时拍摄。

我们正在使用 UIImagePickerController 来执行此操作。当用相机拍摄 1 或 2 张图像/视频时会出现问题。

一旦第三次重新进入相​​机屏幕时捕获了 1 或 2 个图像/视频,则图像是静态的并且不会更新。 View 停留在最后捕获的任何内容的最后一帧。

如果按下捕捉按钮,则图像/视频会突然更新并捕捉到相机指向的内容。从那时起,选择器就可以正常运行了。此外,从相机胶卷中选择一张图片/视频似乎会使另一张图片/视频的所有内容再次出现。最后,当屏幕没有响应并且用户选择拍照时, View 将缩小到 View 内的一个小矩形。 Controller 设置如下:

    private void SourceChosen(EventHandler<UIImagePickerMediaPickedEventArgs> captureEvent, int buttonIndex, string[] mediaTypes)
    {
        var picker = ConfigurePicker(mediaTypes, captureEvent);

        if (CameraAvailable && buttonIndex == 0)
        {
            picker.SourceType = UIImagePickerControllerSourceType.Camera;
            picker.CameraDevice = UIImagePickerControllerCameraDevice.Rear;
            this.NavigationController.PresentViewController(picker, true, () => { });
        }

        if ((!CameraAvailable && buttonIndex == 0) || (CameraAvailable && buttonIndex == 1))
        {
            picker.SourceType = UIImagePickerControllerSourceType.PhotoLibrary;
            this.NavigationController.PresentViewController(picker, false, () => { });
        }
    }

    private UIImagePickerController ConfigurePicker(string[] mediaTypes, EventHandler<UIImagePickerMediaPickedEventArgs> captureEvent)
    {
        var mediaPicker = new UIImagePickerController();
        mediaPicker.FinishedPickingMedia += captureEvent;
        mediaPicker.Canceled += (sender, args) => mediaPicker.DismissViewController(true, () => { });
        mediaPicker.SetBarDefaults();
        mediaPicker.MediaTypes = mediaTypes;
        return mediaPicker;
    }

一个captureEvent的例子如下:

    void PhotoChosen(object sender, UIImagePickerMediaPickedEventArgs e)
    {
        UIImage item = e.OriginalImage;
        string fileName = string.Format("{0}.{1}", Guid.NewGuid(), "png");
        string path = Path.Combine(IosConstants.UserPersonalFolder, fileName);
        NSData imageData = item.AsPNG();
        CopyData(imageData, path, fileName, ViewModel.Images, ((UIImagePickerController)sender));
    }

    private void CopyData(NSData imageData, string path, string fileName, List<AssociatedItem> collectionToAddTo, UIImagePickerController picker)
    {
        byte[] imageBytes = new byte[imageData.Length];
        System.Runtime.InteropServices.Marshal.Copy(imageData.Bytes, imageBytes, 0, Convert.ToInt32(imageData.Length));
        File.WriteAllBytes(path, imageBytes);

        AssociatedItem item = new AssociatedItem
        {
            StorageKey = fileName
        };

        collectionToAddTo.Add(item);
        picker.DismissViewController(true, ReloadTables);
    }

目前如您所见,我们没有保存对选取器的引用,但我们已经尝试了此代码的变体,我们在其中存储对选取器的引用并在 CopyData 方法之后处理它,我们添加了选取器。发布();在 copydata 之后和 dispose 之前(导致随后的选择器在显示时崩溃应用程序)以及主题的几乎所有其他变体。

有谁知道为什么会发生这种情况以及如何解决?我的假设是我们可能内存不足,但每次都没有处理它/只创建一个实例并将其模式从图片更改为视频有任何影响,我们总是看到相同的行为。

编辑

多亏了 Kento 和下面的回答,我们需要做的是让一切按预期工作:

public class PickerDelegate : UIImagePickerControllerDelegate
{
    private readonly Action<UIImagePickerController, NSDictionary> _captureEvent;

    public PickerDelegate(Action<UIImagePickerController, NSDictionary> captureEvent)
    {
        _captureEvent = captureEvent;
    }

    public override void FinishedPickingMedia(UIImagePickerController picker, NSDictionary info)
    {
        _captureEvent(picker, info);
    }
}

然后获取图像

    void PhotoChosen(UIImagePickerController picker, NSDictionary info)
    {
        UIImage item = (UIImage)info.ObjectForKey(UIImagePickerController.OriginalImage);
        string fileName = string.Format("{0}.{1}", Guid.NewGuid(), "png");
        string path = Path.Combine(IosConstants.UserPersonalFolder, fileName);
        NSData imageData = item.AsPNG();
        CopyData(imageData, path, fileName, ViewModel.Images, picker);
    }

或者获取视频

    void VideoChosen(UIImagePickerController picker, NSDictionary info)
    {
        var videoURL = (NSUrl)info.ObjectForKey(UIImagePickerController.MediaURL);
        NSData videoData = NSData.FromUrl(videoURL);
        string fileName = string.Format("{0}.{1}", Guid.NewGuid(), "mov");
        string path = Path.Combine(IosConstants.UserPersonalFolder, fileName);
        CopyData(videoData, path, fileName, ViewModel.Videos, picker);
    }

最佳答案

我遇到了同样的问题。

这里的帖子没有被标记为答案,但它确实为我解决了这个问题:https://stackoverflow.com/a/20035698/2514318

我猜这是使用 FinishedPickingMedia 事件时带有 MonoTouch 的错误。我已经读到使用 UIImagePickerController 存在泄漏(无论使用 obj c 还是 Mono),所以我更愿意保留实例并重新使用它。如果您每次都重新创建它,我建议您处理掉之前的实例。

Xamarin 的任何人都可以权衡一下这是不是错误吗?

关于iOS Monotouch UIImagePickerController 来自相机的多张照片/视频,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20502099/

相关文章:

ios - Uiimageview 自动布局问题

ios - SpriteKit 移动到 X :duration from Current Stat

c# - 如何在 Xamarin.iOS 中实现 +(Class) layerClass?

c# - 如何使用 Xamarin.iOS (C#) 以编程方式截取 iPhone/iPad 的屏幕截图?

xamarin - 如何使用 Xamarin Forms 从图像属性读取地理坐标?

iphone - UIImagePickerController内部的imagePickerController:didFinishPickingMediaWithInfo方法中的应用程序崩溃

iphone - 比 AVAudioPlayer 更快的替代品?

ios - 使 map 缩放到用户位置和注释(swift 2)

ios - 前置摄像头图片的奇怪问题

ios - 将图像上传到服务器需要很长时间