这篇文章主要介绍如何在Xamarin.Form实现跨平台的调用系统图片库。 由于系统图片库是一个平台相关性比较大的系统工具,在Xamarin.Form上没有现成的统一API可用,所以我们只能利用DependencyService 来自己实现一个对系统图片库的调用。

下面,我们就一步一步来实现这个DependencyService调用。

声明接口

namespace DependencyServiceSample
{
    public interface IPicturePicker
    {
        Task<Stream> GetImageStreamAsync();
    }
}

这里我们将方法声明为异步的,因为只有等到用户选择完图片之后这个方法才会返回,声明成异步方法才不至于阻塞主线程。

iOS平台下的实现

在iOS平台下,我们要利用UIImagePickerController 来打开图片库。

[assembly: Dependency (typeof (PicturePickerImplementation))]

namespace DependencyServiceSample.iOS
{
    public class PicturePickerImplementation : IPicturePicker
    {
        TaskCompletionSource<Stream> taskCompletionSource;
        UIImagePickerController imagePicker;

        public Task<Stream> GetImageStreamAsync()
        {
            // 创建UIImagePickerController
            imagePicker = new UIImagePickerController
            {
                SourceType = UIImagePickerControllerSourceType.PhotoLibrary,
                MediaTypes = UIImagePickerController.AvailableMediaTypes(UIImagePickerControllerSourceType.PhotoLibrary)
            };

            // 添加事件处理
            imagePicker.FinishedPickingMedia += OnImagePickerFinishedPickingMedia;
            imagePicker.Canceled += OnImagePickerCancelled;

            // 显示UIImagePickerController;
            UIWindow window = UIApplication.SharedApplication.KeyWindow;
            var viewController = window.RootViewController;
            viewController.PresentModalViewController(imagePicker, true);

            // 返回Task对象
            taskCompletionSource = new TaskCompletionSource<Stream>();
            return taskCompletionSource.Task;
        }
        void OnImagePickerFinishedPickingMedia(object sender, UIImagePickerMediaPickedEventArgs args)
        {
            UIImage image = args.EditedImage ?? args.OriginalImage;

            if (image != null)
            {
                //将 UIImage转换成 .NET Stream对象
                NSData data = image.AsJPEG(1);
                Stream stream = data.AsStream();

                // 将Stream设置为Task的结果
                taskCompletionSource.SetResult(stream);
            }
            else
            {
                taskCompletionSource.SetResult(null);
            }
            imagePicker.DismissModalViewController(true);
        }

        void OnImagePickerCancelled(object sender, EventArgs args)
        {
            taskCompletionSource.SetResult(null);
            imagePicker.DismissModalViewController(true);
        }
    }
}

为了使程序可以正常运行,我们还需要在plist文件中的dict段里添加如下声明:

<key>NSPhotoLibraryUsageDescription</key>
<string>Picture Picker uses photo library</string>

Android平台下的实现

在Android平台下,我们要声明一个Activity。

public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsApplicationActivity
{
    ...
    // 以下是为图片选择器而声明的字段、属性和方法
    public static readonly int PickImageId = 1000;

    public TaskCompletionSource<Stream> PickImageTaskCompletionSource { set; get; }

    protected override void OnActivityResult(int requestCode, Result resultCode, Intent intent)
    {
        base.OnActivityResult(requestCode, resultCode, intent);

        if (requestCode == PickImageId)
        {
            if ((resultCode == Result.Ok) && (intent != null))
            {
                Android.Net.Uri uri = intent.Data;
                Stream stream = ContentResolver.OpenInputStream(uri);

                // 将Stream设置为Task的结果
                PickImageTaskCompletionSource.SetResult(stream);
            }
            else
            {
                PickImageTaskCompletionSource.SetResult(null);
            }
        }
    }
}

还有图片选择器的实现:

[assembly: Dependency(typeof(PicturePickerImplementation))]

namespace DependencyServiceSample.Droid
{
    public class PicturePickerImplementation : IPicturePicker
    {
        public Task<Stream> GetImageStreamAsync()
        {
            // 定义一个用于获取图片的Intent
            Intent intent = new Intent();
            intent.SetType("image/*");
            intent.SetAction(Intent.ActionGetContent);

            // 获取MainActivity的实例
            MainActivity activity = Forms.Context as MainActivity;

            //启动图片选择的 activity (选择结果在MainActivity.cs中处理)
            activity.StartActivityForResult(
                Intent.CreateChooser(intent, "Select Picture"),
                MainActivity.PickImageId);

            // 保存一个TaskCompletionSource 对象作为 MainActivity的属性
            activity.PickImageTaskCompletionSource = new TaskCompletionSource<Stream>();

            // 返回 Task 对象
            return activity.PickImageTaskCompletionSource.Task;
        }
    }
}

在Xamarin.Form中调用图片选择器

 Stream stream = await DependencyService.Get<IPicturePicker>().GetImageStreamAsync();

 if (stream != null)
    {
        Image image = new Image
        {
            Source = ImageSource.FromStream(() => stream)
        };
    }

参考文献

Picking a Photo from the Picture Library