Esta es la traducción de un post de Kent Boogaart en donde recopiló una serie de tips sobre cómo mejorar el desempeño de apps hechas con Xamarin Forms.



Jason Smith, ingeniero a cargo de Xamarin Forms, hizo una fantástica presentación en la conferencia Evolve de este año. En ella, él repasó una larga lista de tips de desempeño, así como una sesión de preguntas y respuestas. No he podido encontrar estos tips por escrito (en diapositivas, transcripción o post en blog). Con el interés de hacer esta información más fácilmente accesible para mi y otros, decidí resumirlos aquí.

Me tomé la libertad de reacomodar y agrupar tips relacionados, pero quiero dejar en claro que este es el contenido de Jason, no el mío.

General

HABILITA la compilación de XAML si estás usándolo para tus vistas:

[assembly: XamlCompilation(XamlCompilationOptions.Compile)]

NO USES bindings cuando asignaciones estáticas sean suficientes.

NO asignes valores por default. Hacerlo conlleva un costo, aunque nunca modifiques el valor.

EVITA usar transparencias. Busca lograr efectos similares con la opacidad al 100%.

USA async / await para evitar bloquear el hilo principal.

CONSIDERA crear los controles en un hilo distinto al principal, pero asegurate de agregarlos al árbol visual en el hilo principal. De no hacerlo no hará que tu app falle inmediatamente, pero corromperá su estado. Se especialmente cuidadoso si estás usando MessagingCenter en el constructor de tu control.

Layout

NO USES un ContentView con Padding solo para aplicarle un margen al hijo. Usa, en su lugar, la propiedad Margin en el hijo (disponible desde Xamarin.Forms 2.2).

NO USES un StackLayout para contener un solo hijo.

NO USES un Grid cuando con StackLayout basta.

NO USES múltiples StackLayouts cuando con un Grid es suficiente.

TOMA EN CUENTA las propiedades Spacing (ColumnSpacing / RowSpacing en Grid) y Padding. En lugar de esto:

<StackLayout>
    <ContentView Padding="10,10,10,5">
        <Label Text="1"/>
    </ContentView>
    <ContentView Padding="10,0,10,5">
        <Label Text="2"/>
    </ContentView>
    <ContentView Padding="10,0,10,0">
        <Label Text="3"/>
    </ContentView>
</StackLayout>

Haz esto:

<StackLayout Padding="10" Spacing="5">
    <Label Text="1"/>
    <Label Text="2"/>
    <Label Text="3"/>
</StackLayout>

PREFIERE usar LayoutOptions.Fill (o LayoutOptions.FillAndExpand). Estos son los valores por default y la mayoría de las veces no deben ser modificados.

PREFIERE filas/columnas de Grid con tamaño definido con * en lugar de Auto.

NO USES múltiples StackLayouts para simular un Grid.

NO USES RelativeLayout si es posible.

AÑADE agrega los controles hijos a su contenedor padre antes de agregar el padre a la pantalla.

En lugar de esto:

var page = new ContentPage();
var stackLayout = new StackLayout();
var image = new Image { Source = "person.png" };
var label = new Label { Text = "Name" };

page.Content = stackLayout;

navigationPage.Push(page);
stackLayout.Children.Add(image);
stackLayout.Children.Add(label);

Haz esto:

var page = new ContentPage();
var stackLayout = new StackLayout();
var image = new Image { Source = "person.png" };
var label = new Label { Text = "Name" };

stackLayout.Children.Add(image);
stackLayout.Children.Add(label);
page.Content = stackLayout;

navigationPage.Push(page);

XAML ya agrega los controles en el orden correcto.

AÑADE los controles a la página en el constructor en lugar de en el método OnAppearing.

PREFIERE animar los controles usando las propiedades TranslationX y TranslatonY.

NO llames al método Layout() (y especialmente ForceLayout()).

CONSIDERA crear un custom layout. Es la mejor opción si es fácil describir el orden de tus controles con palabras pero difícil de implementarlo con los layouts que vienen en forms, si AbsoluteLayout hace casi lo que te gusta, o si simplemente necesitas velocidad pura.

NO USES un StackLayout dentro de un ScrollView para simular un ListView.

USA un Grids para hacer ordenamiento por capas.

Labels

NO USES múltiples Labels cuando con una (usando spans con FormattedText cuando es necesario) basta.

DESACTIVA Label wrapping si es posible (LineBreakMode="NoWrap").

NO cambies el valor de VerticalTextAlignment a menos que sea necesario. El valor por default elimina un ciclo de medición completo.

PREFIERE las propiedades VerticalTextAlignment y HorizontalTextAlignment sobre VerticalOptions y HorizontalOptions.

EVITA actualizaciones esporádicas a Labels. Si las actualizaciones son a múltiples Labels, agrupa las actualizaciones de ser posible.

ListViews

NO pongas un ListView dentro de un ScrollView. Usa las propiedades Header y Footer en su lugar.

NO USES TableView donde puedas usar ListView. Hoy en día, la única razón real para usar un TableView es por interfaces del estilo de un panel de configuración en el que cada celda tiene un contenido único.

USA ListViewCachingStrategy.RecycleElement cuando puedas. Si no te funciona, revisa por qué no lo hace, realmente vale la pena. Debes activar esta propiedad manualmente.

USA los selectores de data template para facilitar el uso de distintos controles dentro de un solo ListView. No sobreescribas OnBindingContextChanged para obtener el mismo efecto.

EVITA usar IEnumerable<T> como origen de datos para un ListView, en su lugar, intenta usar IList<T>.

NO anides ListViews, en su lugar utiliza grupos dentro de uno. No hay soporte para anidamiento de ListViews y hará que tu aplicación falle.

USA la propiedad HasUnevenRows cuando tu ListView tenga filas de distintos tamaños. Si el contenido de una celda es modificado dinámicamente (tal vez despuésde cargar información de la base de datos), asegúrate de llamar ForceUpdateSize() en la celda.

USA await cuando ejecutes PushAsync y PopAsync. El no hacerlo reduce el desempeño y la correctitud de tu aplicación.

EVITA ocultar / mostrar la barra de navegación.

USA el soporte para AppCompat para Android. Esto mejorará el desempeño y apariencia de la aplicación.

Imágenes

TOMA EN CUENTA que Android no se optimiza el tamaño de la imagen.

ASIGNA true a Image.IsOpaque si es posible.

CARGA imagenes desde Content en lugar de Recursos.

BindableProperty

NO USES la versión genérica de BindableProperty.Create (usa la versión basada en string en conjunto con el operador nameof).

CarouselPage

NO USES la CarouselPage

USA un ContentView dentro de una `ContentPage

MessagingCenter

PREFIERE usar otro framework (como Prism).

USA un método estático o de instancia en lugar de una expresión lambda para el MessagingCenter.