iOS Monotouch UIImagePickerController 来自相机的多张照片/视频 [英] iOS Monotouch UIImagePickerController multiple photos / videos from camera

查看:23
本文介绍了iOS Monotouch UIImagePickerController 来自相机的多张照片/视频的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

We're experiencing a strange problem with a UIImagePickerController. In our application users are able to fill out a series of forms and also attach images and videos within these forms.

我们允许用户添加来自相机胶卷或在填写表格时拍摄的多张照片/视频.

We allow users to add multiple photos / videos either from the camera roll or to be captured at the time of filling the form out.

我们使用 UIImagePickerController 来做到这一点.使用相机拍摄 1 或 2 个图像/视频时会出现问题.

We're using the UIImagePickerController to do this. The problem occurs when 1 or 2 images / videos are taken with the camera.

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

Once 1 or 2 images / videos are captured when the camera screen is re-entered for a third time the image is static and doesn't update. The view is stuck at the last frame of whatever was captured last.

如果按下捕获按钮,则图像/视频会突然更新并捕获相机指向的内容.从那时起,picker 有利于另一个正常运行的 go.此外,从相机胶卷中选择图片/视频似乎会使另一张图片/视频的所有内容再次运行.最后,当屏幕没有响应并且用户选择拍照时,视图将缩小为视图内的一个小矩形.控制器设置如下:

If the capture button is pressed then the image / video suddenly updates and has captured what the camera was pointing at. From then on the picker is good for another go behaving normally. Additionally selecting a picture / video from the camera roll appears to make everything behave again for another picture / video. Finally when the screen isn't responding and the user has selected to take a picture the view will shrink to a small rectangle within the view. The controller is being setup as follows:

    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 的例子如下:

An example of a captureEvent is as follows:

    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 之前(导致后续选择器在显示时使应用程序崩溃)以及主题的几乎所有其他变化.

At the moment as you can see we're not holding a reference to the picker but we have tried variations of this code where we store a reference to the picker and dispose it after the CopyData method, we've added picker.Release(); after copydata and before the dispose (results in subsequent pickers crashing the application when displayed) and pretty much every other variation on the theme.

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

Does anyone have any idea why this might be occurring and how to fix it? It was my assumption that we might be running low on memory but neither disposing of it each time / only ever creating one instance and changing its mode from pictures to videos has any affect and we always see the same behaviour.

编辑

感谢 Kento 和下面的回答,我们需要让一切按预期运行:

Thanks to Kento and the below answer what we needed to get it all working as intended was something along the lines of:

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

The post here is not marked as the answer but it did solve it for me: https://stackoverflow.com/a/20035698/2514318

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

I'm guessing this is a bug w/ MonoTouch when using the FinishedPickingMedia event. I have read that there are leaks with using UIImagePickerController (regardless of using obj c or Mono) so I prefer to keep the instance around and re-use it. If you do re-create it each time, I would recommend disposing the previous instance.

Xamarin 的任何人都可以权衡这是否是错误?

Can anyone from Xamarin weigh in on if this is a bug or not?

这篇关于iOS Monotouch UIImagePickerController 来自相机的多张照片/视频的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆