According to your description, if you want to limit selected photos numbers, I suggest you can check the numbers in OnActivityResult. I do one sample that you can take a look:
Firstly, create interface for the dependency service to open the gallery in .net standard project.
public interface IMediaService { Task OpenGallery(); }
Secondly, in the Android project, I created a service to handle the photo gallery opening, also I’m using the Permission plugin for check and request permissions in Android 6 and higher.
[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; } } } } }
Finally, in MainActivity.cs, check clipData.ItemCount count, if count is greather than 20, return.
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; } }
Display image in 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(); } }