Orientación del dispositivo

Ejemplo de descarga Descarga del ejemplo

Es importante tener en cuenta cómo se usará la aplicación y cómo se puede incorporar la orientación horizontal para mejorar la experiencia del usuario. Los diseños individuales se pueden diseñar para dar cabida a varias orientaciones y usar mejor el espacio disponible. En el nivel de aplicación, la rotación se puede deshabilitar o habilitar.

Controlar la orientación

Cuando se Xamarin.Forms usa , el método admitido para controlar la orientación del dispositivo es usar la configuración de cada proyecto individual.

iOS

En iOS, la orientación del dispositivo se configura para las aplicaciones que usan el archivo Info.plist. Use las opciones del IDE de la parte superior de este documento para seleccionar qué instrucciones desea ver:

En Visual Studio, abra el proyecto de iOS y abra Info.plist. El archivo se abrirá en un panel de configuración, empezando por la iPhone información de implementación:

iPhone información de implementación en Visual Studio

Android

Para controlar la orientación en Android, abra MainActivity.cs y establezca la orientación mediante el atributo que decora la clase:

namespace MyRotatingApp.Droid
{
    [Activity (Label = "MyRotatingApp.Droid", Icon = "@drawable/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation, ScreenOrientation = ScreenOrientation.Landscape)] //This is what controls orientation
    public class MainActivity : FormsAppCompatActivity
    {
        protected override void OnCreate (Bundle bundle)
...

Xamarin.Android admite varias opciones para especificar la orientación:

  • Horizontal: obliga a que la orientación de la aplicación sea horizontal, independientemente de los datos del sensor.
  • Vertical: obliga a que la orientación de la aplicación sea vertical, independientemente de los datos del sensor.
  • Usuario: hace que la aplicación se presente con la orientación preferida del usuario.
  • Behind: hace que la orientación de la aplicación sea la misma que la orientación de la actividad subyacente.
  • Sensor: hace que el sensor determine la orientación de la aplicación, incluso si el usuario ha deshabilitado la rotación automática.
  • SensorLandscape: hace que la aplicación use la orientación horizontal mientras usa los datos del sensor para cambiar la dirección a la que se enfrenta la pantalla (de modo que la pantalla no se ve como al revés).
  • SensorPortrait: hace que la aplicación use la orientación vertical mientras usa los datos del sensor para cambiar la dirección a la que se enfrenta la pantalla (de modo que la pantalla no se ve al revés).
  • ReverseLandscape: hace que la aplicación use la orientación horizontal, orientada a la dirección opuesta a la habitual, para que aparezca "al revés".
  • ReversePortrait: hace que la aplicación use la orientación vertical, orientada a la dirección opuesta a la habitual, para que aparezca "al revés".
  • FullSensor: hace que la aplicación se base en los datos del sensor para seleccionar la orientación correcta (de las 4 posibles).
  • FullUser: hace que la aplicación use las preferencias de orientación del usuario. Si la rotación automática está habilitada, se pueden usar las 4 orientaciones.
  • UserLandscape:[No compatible] hace que la aplicación use la orientación horizontal, a menos que el usuario tenga habilitada la rotación automática, en cuyo caso usará el sensor para determinar la orientación. Esta opción interrumpirá la compilación.
  • UserPortrait:[No compatible] hace que la aplicación use orientación vertical, a menos que el usuario tenga habilitada la rotación automática, en cuyo caso usará el sensor para determinar la orientación. Esta opción interrumpirá la compilación.
  • Bloqueado:[No compatible] hace que la aplicación use la orientación de la pantalla, independientemente de lo que esté en el inicio, sin responder a los cambios en la orientación física del dispositivo. Esta opción interrumpirá la compilación.

Tenga en cuenta que las API nativas de Android proporcionan un gran control sobre cómo se administra la orientación, incluidas las opciones que contradicen explícitamente las preferencias expresadas por el usuario.

Plataforma Windows universal

En la Plataforma Windows universal (UWP), las orientaciones admitidas se establecen en el archivo Package.appxmanifest. Al abrir el manifiesto se mostrará un panel de configuración donde se pueden seleccionar las orientaciones admitidas.

Reacción a los cambios de orientación

Xamarin.Forms no ofrece ningún evento nativo para notificar a la aplicación los cambios de orientación en el código compartido. Sin embargo, Xamarin.Essentials contiene una clase [ ] que proporciona notificaciones de cambios de DeviceDisplay orientación.

Para detectar orientaciones sin , supervise el evento de , que se produce cuando cambia el ancho Xamarin.Essentials o el alto de SizeChangedPagePage . Cuando el ancho de es Page mayor que el alto, el dispositivo está en modo horizontal. Para obtener más información, vea Mostrar una imagen basada en la orientación de la pantalla.

Como alternativa, es posible invalidar el método en un , insertando ahí cualquier lógica de cambio OnSizeAllocated de Page diseño. Se llama al método cada vez que se asigna un nuevo tamaño, lo que sucede OnSizeAllocated cada vez que se gira el Page dispositivo. Tenga en cuenta que la implementación base de realiza funciones de diseño importantes, por lo que es importante llamar a OnSizeAllocated la implementación base en la invalidación:

protected override void OnSizeAllocated(double width, double height)
{
    base.OnSizeAllocated(width, height); //must be called
}

Si no se hace ese paso, se produce una página que no funciona.

Tenga en cuenta OnSizeAllocated que se puede llamar al método muchas veces cuando se gira un dispositivo. Cambiar el diseño cada vez es un desperdicio de recursos y puede provocar un parpadeo. Considere la posibilidad de usar una variable de instancia dentro de la página para realizar un seguimiento de si la orientación está en horizontal o vertical, y volver a dibujar solo cuando se haya cambiado:

private double width = 0;
private double height = 0;

protected override void OnSizeAllocated(double width, double height)
{
    base.OnSizeAllocated(width, height); //must be called
    if (this.width != width || this.height != height)
    {
        this.width = width;
        this.height = height;
        //reconfigure layout
    }
}

Una vez detectado un cambio en la orientación del dispositivo, es posible que desee agregar o quitar vistas adicionales hacia o desde la interfaz de usuario para reaccionar ante el cambio en el espacio disponible. Por ejemplo, considere la calculadora integrada en cada plataforma en vertical:

Aplicación calculadora en vertical

y horizontal:

Aplicación calculadora en horizontal

Tenga en cuenta que las aplicaciones aprovechan el espacio disponible agregando más funcionalidad en horizontal.

Diseño dinámico

Es posible diseñar interfaces con los diseños integrados para que se puedan realizar correctamente cuando se gira el dispositivo. Al diseñar interfaces que seguirán siendo atractivas al responder a los cambios de orientación, tenga en cuenta las siguientes reglas generales:

  • Preste atención a las relaciones: los cambios de orientación pueden causar problemas cuando se realizan determinadas suposiciones con respecto a las relaciones. Por ejemplo, una vista que tendría mucho espacio en 1/3 del espacio vertical de una pantalla en vertical puede no caber en 1/3 del espacio vertical en horizontal.
  • Tenga cuidado con los valores absolutos: es posible que los valores absolutos (píxeles) que tengan sentido en vertical no tengan sentido en horizontal. Cuando sean necesarios valores absolutos, use diseños anidados para aislar su impacto. Por ejemplo, sería razonable usar valores absolutos en cuando TableViewItemTemplate la plantilla de elemento tenga un alto uniforme garantizado.

Las reglas anteriores también se aplican al implementar interfaces para varios tamaños de pantalla y, por lo general, se consideran procedimientos recomendados. En el resto de esta guía se explican ejemplos específicos de diseños con capacidad de respuesta mediante cada uno de los diseños principales de Xamarin.Forms .

Nota:

Para mayor claridad, en las secciones siguientes se muestra cómo implementar diseños con capacidad de respuesta con un solo tipo Layout de a la vez. En la práctica, a menudo es más fácil mezclar para lograr un diseño deseado mediante el más sencillo o Layout más intuitivo para cada Layout componente.

StackLayout

Considere la siguiente aplicación, que se muestra en vertical:

Captura de pantalla que muestra Photo Application StackLayout en vertical.

y horizontal:

Captura de pantalla que muestra Photo Application StackLayout en Horizontal.

Esto se logra con el código XAML siguiente:

<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ResponsiveLayout.StackLayoutPageXaml"
Title="Stack Photo Editor - XAML">
    <ContentPage.Content>
        <StackLayout Spacing="10" Padding="5" Orientation="Vertical"
        x:Name="outerStack"> <!-- can change orientation to make responsive -->
            <ScrollView>
                <StackLayout Spacing="5" HorizontalOptions="FillAndExpand"
                    WidthRequest="1000">
                    <StackLayout Orientation="Horizontal">
                        <Label Text="Name: " WidthRequest="75"
                            HorizontalOptions="Start" />
                        <Entry Text="deer.jpg"
                            HorizontalOptions="FillAndExpand" />
                    </StackLayout>
                    <StackLayout Orientation="Horizontal">
                        <Label Text="Date: " WidthRequest="75"
                            HorizontalOptions="Start" />
                        <Entry Text="07/05/2015"
                            HorizontalOptions="FillAndExpand" />
                    </StackLayout>
                    <StackLayout Orientation="Horizontal">
                        <Label Text="Tags:" WidthRequest="75"
                            HorizontalOptions="Start" />
                        <Entry Text="deer, tiger"
                            HorizontalOptions="FillAndExpand" />
                    </StackLayout>
                    <StackLayout Orientation="Horizontal">
                        <Button Text="Save" HorizontalOptions="FillAndExpand" />
                    </StackLayout>
                </StackLayout>
            </ScrollView>
            <Image  Source="deer.jpg" />
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

Algunos C# se usan para cambiar la orientación de outerStack en función de la orientación del dispositivo:

protected override void OnSizeAllocated (double width, double height){
    base.OnSizeAllocated (width, height);
    if (width != this.width || height != this.height) {
        this.width = width;
        this.height = height;
        if (width > height) {
            outerStack.Orientation = StackOrientation.Horizontal;
        } else {
            outerStack.Orientation = StackOrientation.Vertical;
        }
    }
}

Tenga en cuenta lo siguiente:

  • outerStack se ajusta para presentar la imagen y los controles como una pila horizontal o vertical en función de la orientación, para aprovechar mejor el espacio disponible.

AbsoluteLayout

Considere la siguiente aplicación, que se muestra en vertical:

Captura de pantalla que muestra Photo Application AbsoluteLayout en vertical.

y horizontal:

Captura de pantalla que muestra Photo Application AbsoluteLayout en Horizontal.

Esto se logra con el código XAML siguiente:

<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ResponsiveLayout.AbsoluteLayoutPageXaml"
Title="AbsoluteLayout - XAML" BackgroundImageSource="deer.jpg">
    <ContentPage.Content>
        <AbsoluteLayout>
            <ScrollView AbsoluteLayout.LayoutBounds="0,0,1,1"
                AbsoluteLayout.LayoutFlags="PositionProportional,SizeProportional">
                <AbsoluteLayout>
                    <Image Source="deer.jpg"
                        AbsoluteLayout.LayoutBounds=".5,0,300,300"
                        AbsoluteLayout.LayoutFlags="PositionProportional" />
                    <BoxView Color="#CC1A7019" AbsoluteLayout.LayoutBounds=".5
                        300,.7,50" AbsoluteLayout.LayoutFlags="XProportional
                        WidthProportional" />
                    <Label Text="deer.jpg" AbsoluteLayout.LayoutBounds = ".5
                        310,1, 50" AbsoluteLayout.LayoutFlags="XProportional
                        WidthProportional" HorizontalTextAlignment="Center" TextColor="White" />
                </AbsoluteLayout>
            </ScrollView>
            <Button Text="Previous" AbsoluteLayout.LayoutBounds="0,1,.5,60"
                AbsoluteLayout.LayoutFlags="PositionProportional
                    WidthProportional"
                BackgroundColor="White" TextColor="Green" BorderRadius="0" />
            <Button Text="Next" AbsoluteLayout.LayoutBounds="1,1,.5,60"
                AbsoluteLayout.LayoutFlags="PositionProportional
                    WidthProportional" BackgroundColor="White"
                    TextColor="Green" BorderRadius="0" />
        </AbsoluteLayout>
    </ContentPage.Content>
</ContentPage>

Tenga en cuenta lo siguiente:

  • Debido a la forma en que se ha diseñado la página, no es necesario que el código de procedimientos presente capacidad de respuesta.
  • se usa para permitir que la etiqueta sea visible incluso cuando el alto de la pantalla es menor que la suma de la altura fija de los botones y ScrollView la imagen.

RelativeLayout

Considere la siguiente aplicación, que se muestra en vertical:

Captura de pantalla que muestra Photo Application RelativeLayout en vertical.

y horizontal:

Captura de pantalla que muestra Photo Application RelativeLayout en Horizontal.

Esto se logra con el código XAML siguiente:

<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ResponsiveLayout.RelativeLayoutPageXaml"
Title="RelativeLayout - XAML"
BackgroundImageSource="deer.jpg">
    <ContentPage.Content>
        <RelativeLayout x:Name="outerLayout">
            <BoxView BackgroundColor="#AA1A7019"
                RelativeLayout.WidthConstraint="{ConstraintExpression
                    Type=RelativeToParent,Property=Width,Factor=1}"
                RelativeLayout.HeightConstraint="{ConstraintExpression
                    Type=RelativeToParent,Property=Height,Factor=1}"
                RelativeLayout.XConstraint="{ConstraintExpression
                    Type=RelativeToParent,Property=Width,Factor=0,Constant=0}"
                RelativeLayout.YConstraint="{ConstraintExpression
                    Type=RelativeToParent,Property=Height,Factor=0,Constant=0}" />
            <ScrollView
                RelativeLayout.WidthConstraint="{ConstraintExpression
                    Type=RelativeToParent,Property=Width,Factor=1}"
                RelativeLayout.HeightConstraint="{ConstraintExpression
                    Type=RelativeToParent,Property=Height,Factor=1,Constant=-60}"
                RelativeLayout.XConstraint="{ConstraintExpression
                    Type=RelativeToParent,Property=Width,Factor=0,Constant=0}"
                RelativeLayout.YConstraint="{ConstraintExpression
                    Type=RelativeToParent,Property=Height,Factor=0,Constant=0}">
                <RelativeLayout>
                    <Image Source="deer.jpg" x:Name="imageDeer"
                        RelativeLayout.WidthConstraint="{ConstraintExpression
                            Type=RelativeToParent,Property=Width,Factor=.8}"
                        RelativeLayout.XConstraint="{ConstraintExpression
                            Type=RelativeToParent,Property=Width,Factor=.1}"
                        RelativeLayout.YConstraint="{ConstraintExpression
                            Type=RelativeToParent,Property=Height,Factor=0,Constant=10}" />
                    <Label Text="deer.jpg" HorizontalTextAlignment="Center"
                        RelativeLayout.WidthConstraint="{ConstraintExpression
                            Type=RelativeToParent,Property=Width,Factor=1}"
                        RelativeLayout.HeightConstraint="{ConstraintExpression
                            Type=RelativeToParent,Property=Height,Factor=0,Constant=75}"
                        RelativeLayout.XConstraint="{ConstraintExpression
                            Type=RelativeToParent,Property=Width,Factor=0,Constant=0}"
                        RelativeLayout.YConstraint="{ConstraintExpression
                            Type=RelativeToView,ElementName=imageDeer,Property=Height,Factor=1,Constant=20}" />
                </RelativeLayout>

            </ScrollView>

            <Button Text="Previous" BackgroundColor="White" TextColor="Green" BorderRadius="0"
                RelativeLayout.YConstraint="{ConstraintExpression
                    Type=RelativeToParent,Property=Height,Factor=1,Constant=-60}"
                RelativeLayout.XConstraint="{ConstraintExpression
                    Type=RelativeToParent,Property=Width,Factor=0,Constant=0}"
                RelativeLayout.HeightConstraint="{ConstraintExpression
                    Type=RelativeToParent,Property=Width,Factor=0,Constant=60}"
                RelativeLayout.WidthConstraint="{ConstraintExpression
                    Type=RelativeToParent,Property=Width,Factor=.5}"
                 />
            <Button Text="Next" BackgroundColor="White" TextColor="Green" BorderRadius="0"
                RelativeLayout.XConstraint="{ConstraintExpression
                    Type=RelativeToParent,Property=Width,Factor=.5}"
                RelativeLayout.YConstraint="{ConstraintExpression
                    Type=RelativeToParent,Property=Height,Factor=1,Constant=-60}"
                RelativeLayout.HeightConstraint="{ConstraintExpression
                    Type=RelativeToParent,Property=Width,Factor=0,Constant=60}"
                RelativeLayout.WidthConstraint="{ConstraintExpression
                    Type=RelativeToParent,Property=Width,Factor=.5}"
                />
        </RelativeLayout>
    </ContentPage.Content>
</ContentPage>

Tenga en cuenta lo siguiente:

  • Debido a la forma en que se ha diseñado la página, no es necesario que el código de procedimientos presente capacidad de respuesta.
  • se usa para permitir que la etiqueta sea visible incluso cuando el alto de la pantalla es menor que la suma de la altura fija de los botones y ScrollView la imagen.

Cuadrícula

Considere la siguiente aplicación, que se muestra en vertical:

Captura de pantalla que muestra Photo Application Grid en vertical.

y horizontal:

Captura de pantalla que muestra Photo Application Grid en Horizontal.

Esto se logra con el código XAML siguiente:

<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ResponsiveLayout.GridPageXaml"
Title="Grid - XAML">
    <ContentPage.Content>
        <Grid x:Name="outerGrid">
            <Grid.RowDefinitions>
                <RowDefinition Height="*" />
                <RowDefinition Height="60" />
            </Grid.RowDefinitions>
            <Grid x:Name="innerGrid" Grid.Row="0" Padding="10">
                <Grid.RowDefinitions>
                    <RowDefinition Height="*" />
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>
                <Image Source="deer.jpg" Grid.Row="0" Grid.Column="0" HeightRequest="300" WidthRequest="300" />
                <Grid x:Name="controlsGrid" Grid.Row="0" Grid.Column="1" >
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition Width="*" />
                    </Grid.ColumnDefinitions>
                    <Label Text="Name:" Grid.Row="0" Grid.Column="0" />
                    <Label Text="Date:" Grid.Row="1" Grid.Column="0" />
                    <Label Text="Tags:" Grid.Row="2" Grid.Column="0" />
                    <Entry Grid.Row="0" Grid.Column="1" />
                    <Entry Grid.Row="1" Grid.Column="1" />
                    <Entry Grid.Row="2" Grid.Column="1" />
                </Grid>
            </Grid>
            <Grid x:Name="buttonsGrid" Grid.Row="1">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>
                <Button Text="Previous" Grid.Column="0" />
                <Button Text="Save" Grid.Column="1" />
                <Button Text="Next" Grid.Column="2" />
            </Grid>
        </Grid>
    </ContentPage.Content>
</ContentPage>

Junto con el código de procedimiento siguiente para controlar los cambios de rotación:

private double width;
private double height;

protected override void OnSizeAllocated (double width, double height){
    base.OnSizeAllocated (width, height);
    if (width != this.width || height != this.height) {
        this.width = width;
        this.height = height;
        if (width > height) {
            innerGrid.RowDefinitions.Clear();
            innerGrid.ColumnDefinitions.Clear ();
            innerGrid.RowDefinitions.Add (new RowDefinition{ Height = new GridLength (1, GridUnitType.Star) });
            innerGrid.ColumnDefinitions.Add (new ColumnDefinition { Width = new GridLength (1, GridUnitType.Star) });
            innerGrid.ColumnDefinitions.Add (new ColumnDefinition { Width = new GridLength (1, GridUnitType.Star) });
            innerGrid.Children.Remove (controlsGrid);
            innerGrid.Children.Add (controlsGrid, 1, 0);
        } else {
            innerGrid.RowDefinitions.Clear();
            innerGrid.ColumnDefinitions.Clear ();
            innerGrid.ColumnDefinitions.Add (new ColumnDefinition{ Width = new GridLength (1, GridUnitType.Star) });
            innerGrid.RowDefinitions.Add (new RowDefinition { Height = new GridLength (1, GridUnitType.Auto) });
            innerGrid.RowDefinitions.Add (new RowDefinition { Height = new GridLength (1, GridUnitType.Star) });
            innerGrid.Children.Remove (controlsGrid);
            innerGrid.Children.Add (controlsGrid, 0, 1);
        }
    }
}

Tenga en cuenta lo siguiente:

  • Debido a la forma en que se ha diseñado la página, hay un método para cambiar la posición de cuadrícula de los controles.