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

Posted

技术标签:

【中文标题】iOS Monotouch UIImagePickerController 来自相机的多张照片/视频【英文标题】:iOS Monotouch UIImagePickerController multiple photos / videos from camera 【发布时间】:2013-12-10 18:11:11 【问题描述】:

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

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

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

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

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

    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);
    

【问题讨论】:

您好,我也有同样的问题。我使用 MvvmCross 图片选择器插件。并查看他们使用委托的源代码,但我的应用程序仍然存在问题吗?你能指导我吗? @Sudhir3 我建议发布一个问题,其中包含一些示例代码以及您到目前为止所尝试的内容。 谢谢我在这里发布了我的问题***.com/questions/21642912/… 【参考方案1】:

我遇到了同样的问题。

此处的帖子未标记为答案,但确实为我解决了问题:https://***.com/a/20035698/2514318

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

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

【讨论】:

非常感谢您的回答,这正是我必须做的。我将使用我想出的代码编辑我的问题,以使其按预期工作。 第二。我们有同样的问题。从 Event 切换到 Delegate 使问题消失了。谢谢 您好,我也有同样的问题。我使用了 MvvmCross 图片选择器插件。并查看他们使用委托的源代码,但是我的应用程序仍然存在问题吗?你能指导我吗?【参考方案2】:

这篇文章对我帮助很大,所以我决定制作一个非常简单的示例并在 github 上发布给任何可能需要它的人:https://github.com/GiusepeCasagrande/XamarinSimpleCameraSample

【讨论】:

以上是关于iOS Monotouch UIImagePickerController 来自相机的多张照片/视频的主要内容,如果未能解决你的问题,请参考以下文章

如何在 MonoTouch 中使用 System.IO.Packaging

使用 Monotouch 播放默认 iOS 系统声音

iOS 5.1 Monotouch 查看问题

MonoTouch:从命令行创建 iOS AppStore-Version

C# Monotouch/Xamarin.iOS - 不支持推送导航控制器

MonoTouch 5.0:获取 MonoDevelop 以使用 iOS 5 SDK/模拟器