如何在Xamarin中实现经典的媒体选择器.表格



我正在开发这个xamarin.forms应用程序,它要求用户从设备中选择一定数量的照片(从最小1张照片到指定的最大数量,甚至无限(。我一直在努力了解如何实现它。我使用了微软文档中建议的FilePicker,但这样我就不能限制可选择的图像数量。我也尝试过在这两个项目中使用依赖服务来实现图库,但我认为我走错了路:在android上,我在某些文件夹中搜索设备图像,但这样,如果用户的照片存储在外部应用程序中(如谷歌照片或亚马逊照片(,他就看不到(并选择(它们,还没有在iOS上尝试过。

以前我试过使用媒体。插件,但自20年11月以来,该库被驳回。

我不明白这个代码是如何正确实现的,也不明白既然它在应用程序中如此常见,为什么没有它的视图。

如何做到这一点?

如媒体上所述。插件:

Xamarin。Essentials 1.6引入了对拾取/提取的官方支持新的媒体选取器API的照片和视频。

根据您的描述,如果您想限制所选照片的数量,我建议您可以在OnActivityResult中检查数字。我做了一个你可以看看的样品:

首先,为依赖服务创建接口,以便在.net标准项目中打开库。

public interface IMediaService
{
Task OpenGallery();
}

其次,在安卓项目中,我创建了一个服务来处理照片库的打开,我还在安卓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;
}
}

在主页中显示图像。

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

最新更新