Acceso a la galeria de Imagenes
¡Hola a todos! Bienvenidos a este tutorial donde aprenderemos a acceder a la galeria de imagenes Android mediante dependencyService y visualizar las imagenes seleccionadas. ¡Empecemos!
¿Qué es DependencyService?
DependencyService permite a las aplicaciones llamar a funciones específicas de una plataforma desde el código compartido de tu aplicación. Con esto, permite a Xamarin.Forms hacer todo aquello que hace una aplicación nativa.
Después de esta breve explicación, procedemos a crear nuestro proyecto.
Creación del Proyecto.
Para empezar vamos a crear nuestro proyecto, para eso vamos a File>New>Project y seleccionamos la opción Cross-Platform.
Ahora seleccionamos la opción Blank.
Implementación en Android
Una vez creado el proyecto veremos que se han creado 4 proyectos, el primero de todos es el proyecto de código compartido, el segundo es el de android, el tercero el de iOS y el cuarto es de Universal Windows.
Vamos a crear una carpeta en el proyecto de código compartido, la llamaremos Dependencies. Dentro de la carpeta Dependencies crearemos una interfaz llamada IGaleriaImagenes, para crearlo damos click derecho sobre la carpeta Dependencies, elegimos las opción Add y dentro la opción New Item y seleccionamos la opción Interface.
El código de IGaleriaImagenes debe de ser así:
public interface IGaleriaImagenes
{
Task<Stream> GetFotoAsync();
}
Una vez hecho esto, vamos al proyecto Android y damos doble click sobre MainActivity. Ahora insertamos el siguiente código:
public static readonly int idImagen = 1000;
public TaskCompletionSource<Stream> ImagenTaskCompletionSource { set; get; }
public static object Instance { get; internal set; }
protected override void OnActivityResult(int requestCode, Result resultCode, Intent intent)
{
base.OnActivityResult(requestCode, resultCode, intent);
if (requestCode == idImagen)
{
if ((resultCode == Result.Ok) && (intent != null))
{
Android.Net.Uri uri = intent.Data;
Stream stream = ContentResolver.OpenInputStream(uri);
ImagenTaskCompletionSource.SetResult(stream);
}
else
{
ImagenTaskCompletionSource.SetResult(null);
}
}
}
Explicación: Hemos sobreescrito el método OnActivityResult que se activa cuando el usuario ha elegido una imagen, lo que le hemos escrito es que recoge la Uri de la imagen y poderla convertir en un objeto Stream de .NET llamando al método OpenInputStream.
La implementación de Android se usa un elemento llamado TaskCompletionSource para indicar que se ha completado la tarea. Este objeto se declara como propiedad pública en la clase MainActivity. Esto a su vez, permite hacer referencia a la propiedad en la clase AndroidImplementation que haremos ahora.
Creamos la clase llamada AndroidImplementation, para crear la clase damos click derecho sobre el proyecto, elegimos la opción Add y dentro la opción Class…
Dentro de la clase heredaremos de la interface IGaleriaImagenes y tendrá el siguiente código:
public class AndroidImplementation : IGaleriaImagenes
{
public Task<Stream> GetFotoAsync()
{
Intent intent = new Intent();
intent.SetType("image/*");
intent.SetAction(Intent.ActionGetContent);
MainActivity activity = Forms.Context as MainActivity;
activity.StartActivityForResult(Intent.CreateChooser(intent, "Selecciona una Imagen"), MainActivity.idImagen);
activity.ImagenTaskCompletionSource = new TaskCompletionSource<Stream>();
return activity.ImagenTaskCompletionSource.Task;
}
}
Explicación: este método accede a la clase MainActivity para acceder a las propiedades Instance, idImagen, ImagenTaskCompletionSource y para llamar a StartActivityForResult. GetFotoAsync() crea un objeto Intent en el que obtiene la imagen seleccionada, luego crea el activity de seleccion de imagen y guarda el TaskCompletionSource. Por último devuelve el task object.
Models y ViewModels
Ya tenemos la implementación en Android lista, ahora procederemos a crear unos modelos para poder visualizar las imagenes que seleccionamos.
Primero, vamos al proyecto de código compartido y creamos una carpeta llamada Models, después creamos una clase llamada Foto.
Dentro de la clase Foto tiene el siguiente código:
public class Foto
{
public Foto()
{
Imagen = new Image();
}
public String name { get; set; }
public Image Imagen { get; set; }
}
Ahora crearemos otra carpeta sobre el proyecto de código compartido llamará Base, dentro de esa carpeta tendrá una clase llamada ViewModelBase que tendrá el siguiente código:
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(String propertyname)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyname));
}
}
Explicación: Con la propiedad PropertyChanged nos permitirá actualizar nuestro ViewModel pudiendo ver los cambios que se hacen en la vista.
Lo siguiente que haremos es crear otra carpeta sobre el proyecto de código compartido llamado ViewModel que tendrá una clase llamada FotosViewModel. El código de la clase es el siguiente:
public class FotosViewModel: ViewModelBase
{
public FotosViewModel()
{
this.Fotos = new ObservableCollection<Foto>();
}
private ObservableCollection<Foto> _Fotos;
public ObservableCollection<Foto> Fotos
{
get { return this._Fotos; }
set { this._Fotos = value; OnPropertyChanged("Fotos"); }
}
private int num = 1;
public Command CargarFoto
{
get
{
return new Command(async () =>
{
Stream stream = await
DependencyService.Get<IGaleriaImagenes>().GetFotoAsync();
if (stream != null)
{
Foto foto = new Foto();
foto.Imagen.Source = ImageSource.FromStream(() => stream);
foto.name = "Imagen "+num;
num++;
this.Fotos.Add(foto);
}
});
}
}
}
Explicación: esta clase hereda de ViewModelBase, por lo que le permite a sus propiedades que se actualicen el la vista. Tiene una propiedad prublica llamada ObervableCollection que permite crear colecciones de elementos y mejora la renderización de dichos elementos en la vista. También tiene un Command llamado CargarFoto que obtiene la imagen seleccionada de la galeria de imagenes y lo añade a la lista de fotos.
Vista
Una vez que hayamos terminado, vamos al archivo MainPage.xaml y ponemos el siguiente código dentro de la etiqueta ContentPage junto a los atributos:
xmlns:viewmodel="clr-namespace:PostImagenes.ViewModel"
Con esto mapeamos la carpeta ViewModel para poder hacer el BindingContext que es lo siguiente que insertaremos:
<ContentPage.BindingContext>
<viewmodel:FotosViewModel />
</ContentPage.BindingContext>
Dentro del StackLayout creamos un ListView, debe de quedar de esta manera:
<ListView ItemsSource="{Binding Fotos}" HeightRequest="80" HasUnevenRows="True">
<ListView.ItemTemplate >
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Label Text="{Binding name}" TextColor="Red"/>
<Image Source="{Binding Imagen.Source}" HorizontalOptions="FillAndExpand" HeightRequest="80"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Y por último creamos el botón con el comando CargarFoto:
<Button Text="Selecciona una imagen!" x:Name="botonimagen" Command="{Binding CargarFoto}"/>
El archivo tiene que quedar de esta manera:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:viewmodel="clr-namespace:PostImagenes.ViewModel"
x:Class="PostImagenes.MainPage">
<ContentPage.BindingContext>
<viewmodel:FotosViewModel />
</ContentPage.BindingContext>
<StackLayout Margin="0,30,0,0">
<ListView ItemsSource="{Binding Fotos}" HeightRequest="80" HasUnevenRows="True">
<ListView.ItemTemplate >
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Label Text="{Binding name}" TextColor="Red"/>
<Image Source="{Binding Imagen.Source}" HorizontalOptions="FillAndExpand" HeightRequest="80"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button Text="Selecciona una imagen!" x:Name="botonimagen" Command="{Binding CargarFoto}"/>
</StackLayout>
</ContentPage>
Y con esto ya habríamos terminado, ahora lo ejecutamos y… ¡Ya tendríamos que ver los resultados!
Autor/a: David Valencia Beltrán
Curso: Microsoft MCSA Web Applications + Microsoft MCSD App Builder + Xamarin
Centro: Tajamar
Año académico: 2018-2019
Código / recursos utilizados / Otros datos de interés: https://github.com/Davos95/PostImagenes