簡體   English   中英

如何實現Xamarin.Forms中的經典媒體選擇器?

[英]How to implement the classic media picker in Xamarin.Forms?

我正在開發這個 xamarin.forms 應用程序,該應用程序要求用戶從其設備中 select 一定數量的照片(從最少 1 張照片到指定的最大數量甚至無限)。 我一直在努力了解如何實現它。 我使用了 Microsoft 文檔中建議的FilePicker ,但這樣我就無法限制可選擇的圖像數量。 我也嘗試使用依賴服務在兩個項目中實現圖庫,但我認為我走錯了路:在 android 上,我在某些文件夾中搜索設備圖像,但是這樣,如果用戶將其照片存儲在外部應用程序(例如谷歌照片或亞馬遜照片)他看不到(並選擇)它們,還沒有在 iOS 上嘗試過。

以前我曾嘗試使用Media.Plugin但自 20 年 11 月以來,該庫已被取消。

我不明白如何正確實現此代碼,以及考慮到它在應用程序中如此常見的事實,為什么沒有它的視圖。

如何才能做到這一點?

如 Media.Plugin 所述:

Xamarin.Essentials 1.6 引入了對使用新媒體選擇器 API 選擇/拍攝照片和視頻的官方支持。

根據您的描述,如果您想限制選擇的照片數量,我建議您可以查看 OnActivityResult 中的數字。 我做了一個樣本,你可以看看:

首先,在.net標准項目中創建依賴服務打開圖庫的接口。

public interface IMediaService
{
    Task OpenGallery();
}

其次,在 Android 項目中,我創建了一個服務來處理照片庫的打開,我也在使用 Permission 插件來檢查和請求 Android 6 及更高版本中的權限。

[assembly: Xamarin.Forms.Dependency(typeof(MediaService))]
namespace pickerimage.Droid
{
public class MediaService : Java.Lang.Object, IMediaService
{
    public async Task OpenGallery()
    {
        try
        {
            var status = await CrossPermissions.Current.CheckPermissionStatusAsync(Plugin.Permissions.Abstractions.Permission.Storage);
            if (status != PermissionStatus.Granted)
            {
                if (await CrossPermissions.Current.ShouldShowRequestPermissionRationaleAsync(Plugin.Permissions.Abstractions.Permission.Storage))
                {
                    Toast.MakeText(Xamarin.Forms.Forms.Context, "Need Storage permission to access to your photos.", ToastLength.Long).Show();
                }

                var results = await CrossPermissions.Current.RequestPermissionsAsync(new[] { Plugin.Permissions.Abstractions.Permission.Storage });
                status = results[Plugin.Permissions.Abstractions.Permission.Storage];
            }

            if (status == PermissionStatus.Granted)
            {
                Toast.MakeText(Xamarin.Forms.Forms.Context, "Select max 20 images", ToastLength.Long).Show();
                var imageIntent = new Intent(
                    Intent.ActionPick);
                imageIntent.SetType("image/*");
                imageIntent.PutExtra(Intent.ExtraAllowMultiple, true);
                imageIntent.SetAction(Intent.ActionGetContent);
                ((Activity)Forms.Context).StartActivityForResult(
                    Intent.CreateChooser(imageIntent, "Select photo"), 1);

            }
            else if (status != PermissionStatus.Unknown)
            {
                Toast.MakeText(Xamarin.Forms.Forms.Context, "Permission Denied. Can not continue, try again.", ToastLength.Long).Show();
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
            Toast.MakeText(Xamarin.Forms.Forms.Context, "Error. Can not continue, try again.", ToastLength.Long).Show();
        }
    }
   
}
}

public static class ImageHelpers
{
    public static string SaveFile(string collectionName, byte[] imageByte, string fileName)
    {
        var fileDir = new Java.IO.File(Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryPictures), collectionName);
        if (!fileDir.Exists())
        {
            fileDir.Mkdirs();
        }

        var file = new Java.IO.File(fileDir, fileName);
        System.IO.File.WriteAllBytes(file.Path, imageByte);

        return file.Path;

    }

    public static byte[] RotateImage(string path)
    {
        byte[] imageBytes;

        var originalImage = BitmapFactory.DecodeFile(path);
        var rotation = GetRotation(path);
        var width = (originalImage.Width * 0.25);
        var height = (originalImage.Height * 0.25);
        var scaledImage = Bitmap.CreateScaledBitmap(originalImage, (int)width, (int)height, true);

        Bitmap rotatedImage = scaledImage;
        if (rotation != 0)
        {
            var matrix = new Matrix();
            matrix.PostRotate(rotation);
            rotatedImage = Bitmap.CreateBitmap(scaledImage, 0, 0, scaledImage.Width, scaledImage.Height, matrix, true);
            scaledImage.Recycle();
            scaledImage.Dispose();
        }

        using (var ms = new MemoryStream())
        {
            rotatedImage.Compress(Bitmap.CompressFormat.Jpeg, 90, ms);
            imageBytes = ms.ToArray();
        }

        originalImage.Recycle();
        rotatedImage.Recycle();
        originalImage.Dispose();
        rotatedImage.Dispose();
        GC.Collect();

        return imageBytes;
    }

    private static int GetRotation(string filePath)
    {
        using (var ei = new ExifInterface(filePath))
        {
            var orientation = (Android.Media.Orientation)ei.GetAttributeInt(ExifInterface.TagOrientation, (int)Android.Media.Orientation.Normal);

            switch (orientation)
            {
                case Android.Media.Orientation.Rotate90:
                    return 90;
                case Android.Media.Orientation.Rotate180:
                    return 180;
                case Android.Media.Orientation.Rotate270:
                    return 270;
                default:
                    return 0;
            }
        }
    }
}
 }

最后,在 MainActivity.cs 中,檢查clipData.ItemCount計數,如果計數大於 20,則返回。

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

        if (requestCode == 1 && resultCode == Result.Ok)
        {
            List<string> images = new List<string>();

            if (data != null)
            {
                ClipData clipData = data.ClipData;
                if (clipData != null)
                {
                    if(clipData.ItemCount>20)
                    {
                        Toast.MakeText(Xamarin.Forms.Forms.Context, "please select max 20 images", ToastLength.Long).Show();
                        return;
                    }
                    for (int i = 0; i < clipData.ItemCount; i++)
                    {
                        ClipData.Item item = clipData.GetItemAt(i);
                        Android.Net.Uri uri = item.Uri;
                        var path = GetRealPathFromURI(uri);

                        if (path != null)
                        {
                            //Rotate Image
                            var imageRotated = ImageHelpers.RotateImage(path);
                            var newPath = ImageHelpers.SaveFile("TmpPictures", imageRotated, System.DateTime.Now.ToString("yyyyMMddHHmmssfff"));
                            images.Add(newPath);
                        }
                    }
                }
                else
                {
                    Android.Net.Uri uri = data.Data;
                    var path = GetRealPathFromURI(uri);

                    if (path != null)
                    {
                        //Rotate Image
                        var imageRotated = ImageHelpers.RotateImage(path);
                        var newPath = ImageHelpers.SaveFile("TmpPictures", imageRotated, System.DateTime.Now.ToString("yyyyMMddHHmmssfff"));
                        images.Add(newPath);
                    }
                }

                MessagingCenter.Send<App, List<string>>((App)Xamarin.Forms.Application.Current, "ImagesSelected", images);
            }
        }
    }



    public String GetRealPathFromURI(Android.Net.Uri contentURI)
    {
        try
        {
            ICursor imageCursor = null;
            string fullPathToImage = "";

            imageCursor = ContentResolver.Query(contentURI, null, null, null, null);
            imageCursor.MoveToFirst();
            int idx = imageCursor.GetColumnIndex(MediaStore.Images.ImageColumns.Data);

            if (idx != -1)
            {
                fullPathToImage = imageCursor.GetString(idx);
            }
            else
            {
                ICursor cursor = null;
                var docID = DocumentsContract.GetDocumentId(contentURI);
                var id = docID.Split(':')[1];
                var whereSelect = MediaStore.Images.ImageColumns.Id + "=?";
                var projections = new string[] { MediaStore.Images.ImageColumns.Data };

                cursor = ContentResolver.Query(MediaStore.Images.Media.InternalContentUri, projections, whereSelect, new string[] { id }, null);
                if (cursor.Count == 0)
                {
                    cursor = ContentResolver.Query(MediaStore.Images.Media.ExternalContentUri, projections, whereSelect, new string[] { id }, null);
                }
                var colData = cursor.GetColumnIndexOrThrow(MediaStore.Images.ImageColumns.Data);
                cursor.MoveToFirst();
                fullPathToImage = cursor.GetString(colData);
            }
            return fullPathToImage;
        }
        catch (Exception ex)
        {
            Toast.MakeText(Xamarin.Forms.Forms.Context, "Unable to get path", ToastLength.Long).Show();

        }

        return null;

    }
}

在 MainPage 中顯示圖像。

 <StackLayout>
    <Button
        BackgroundColor="Blue"
        Clicked="Handle_Clicked"
        Text="Select From Gallery"
        TextColor="White" />

    <ListView x:Name="listItems">
        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell>
                    <StackLayout Orientation="Horizontal">
                        <Image HeightRequest="100" Source="{Binding .}" />
                    </StackLayout>
                </ViewCell>

            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

</StackLayout>

public partial class MainPage : ContentPage
{
    List<string> _images = new List<string>();
    public MainPage()
    {
        InitializeComponent();
    }
    protected override void OnAppearing()
    {
        base.OnAppearing();

        MessagingCenter.Subscribe<App, List<string>>((App)Xamarin.Forms.Application.Current, "ImagesSelected", (s, images) =>
        {
            listItems.ItemsSource = images;
            _images = images;
        });
    }
    protected override void OnDisappearing()
    {
        base.OnDisappearing();
        MessagingCenter.Unsubscribe<App, List<string>>(this, "ImagesSelected");
    }

    async void Handle_Clicked(object sender, System.EventArgs e)
    {
        await DependencyService.Get<IMediaService>().OpenGallery();
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM