Orientacja urządzenia

Pobierz przykład. Pobieranie przykładu

Ważne jest, aby zastanowić się nad tym, jak będzie używana aplikacja i jak można włączyć orientację poziomą, aby poprawić środowisko użytkownika. Poszczególne układy można zaprojektować tak, aby pomieścić wiele orientacji i jak najlepiej wykorzystać dostępne miejsce. Na poziomie aplikacji można wyłączyć lub włączyć rotację.

Kontrolowanie orientacji

W przypadku korzystania z programu obsługiwaną metodą kontrolowania orientacji urządzenia jest użycie Xamarin.Forms ustawień dla każdego projektu.

iOS

W systemie iOS orientacja urządzenia jest konfigurowana dla aplikacji przy użyciu pliku Info.plist. Użyj opcji środowiska IDE w górnej części tego dokumentu, aby wybrać instrukcje, które chcesz wyświetlić:

W Visual Studio otwórz projekt systemu iOS i otwórz program Info.plist. Plik zostanie otwarty w panelu konfiguracji, począwszy od karty iPhone informacje o wdrożeniu:

iPhone Informacje o wdrożeniu w Visual Studio.

Android

Aby kontrolować orientację w systemie Android, otwórz mainActivity.cs i ustaw orientację przy użyciu atrybutu decorating MainActivity klasy:

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 obsługuje kilka opcji określania orientacji:

  • Krajobraz – wymusza orientację aplikacji na poziomą, niezależnie od danych z czujników.
  • Pionowa – wymusza orientację aplikacji na pionową, niezależnie od danych z czujników.
  • Użytkownik – powoduje, że aplikacja jest przedstawiana przy użyciu preferowanej orientacji użytkownika.
  • Za kulisami – Powoduje, że orientacja aplikacji jest taka sama jak orientacja działania, za nią.
  • Czujnik – Powoduje, że orientacja aplikacji jest określana przez czujnik, nawet jeśli użytkownik wyłączył automatyczną rotację.
  • SensorLandscape – powoduje, że aplikacja używa orientacji poziomej podczas korzystania z danych czujnika w celu zmiany kierunku działania ekranu (tak aby ekran nie był widoczny do góry w dół).
  • SensorPortrait – Powoduje, że aplikacja używa orientacji pionowej podczas używania danych czujnika do zmiany kierunku, w jakim znajduje się ekran (tak aby ekran nie był widoczny do góry do góry).
  • ReverseLandscape – Powoduje, że aplikacja korzysta z orientacji poziomej, skierowana w kierunku odwrotnym do zwykłego, tak aby pojawiła się "do góry do góry do dołu".
  • ReversePortrait – Powoduje, że aplikacja korzysta z orientacji pionowej, skierowana w kierunku odwrotnym do zwykłego, tak aby pojawiła się "do góry do dołu".
  • FullSensor – Powoduje, że aplikacja korzysta z danych czujników w celu wybrania poprawnej orientacji (z 4).
  • FullUser – Powoduje, że aplikacja korzysta z preferencji orientacji użytkownika. Jeśli automatyczna rotacja jest włączona, można użyć wszystkich 4 orientacji.
  • UserLandscape[ Ustawienie ] Nie obsługiwane powoduje, że aplikacja używa orientacji poziomej, chyba że użytkownik ma włączoną automatyczną rotację. W takim przypadku użyje czujnika do określenia orientacji. Ta opcja spowoduje przerwania kompilacji.
  • UserPortrait[ Ustawienie ] Nie obsługiwane powoduje, że aplikacja używa orientacji pionowej, chyba że użytkownik ma włączoną automatyczną rotację. W takim przypadku użyje czujnika do określenia orientacji. Ta opcja spowoduje przerwania kompilacji.
  • Zablokowane[ Ustawienie ] Nie obsługiwane powoduje, że aplikacja używa orientacji ekranu, niezależnie od tego, czy jest uruchamiana, bez reagowania na zmiany orientacji fizycznej urządzenia. Ta opcja spowoduje przerwania kompilacji.

Należy pamiętać, że natywne interfejsy API systemu Android zapewniają dużą kontrolę nad zarządzaniem orientacją, w tym opcjami, które jawnie sprzeczne z preferencjami wyrażonych przez użytkownika.

Platforma Windows uniwersalna

Na platformie universal Windows Platform (UWP) obsługiwane orientacje są ustawiane w pliku Package.appxmanifest. Otwarcie manifestu spowoduje ujawnienie panelu konfiguracji, w którym można wybrać obsługiwane orientacje.

Reagowanie na zmiany w orientacji

Xamarin.Forms Nie oferuje żadnych zdarzeń natywnych w celu powiadamiania aplikacji o zmianach orientacji w udostępnionym kodzie. Zawiera Xamarin.Essentials jednak klasę DeviceDisplay [], która zapewnia powiadomienia o zmianach orientacji.

Aby wykryć orientacje bez , monitoruj zdarzenie , które jest wyzjęty, gdy zmienia się Xamarin.Essentials SizeChanged szerokość lub Page Page wysokość. Gdy szerokość urządzenia jest Page większa niż wysokość, urządzenie jest w trybie poziomym. Aby uzyskać więcej informacji, zobacz Wyświetlanie obrazu na podstawie orientacji ekranu.

Alternatywnie można przesłonić metodę w metodzie , wstawiając w nim OnSizeAllocated Page dowolną logikę zmiany układu. Metoda OnSizeAllocated jest wywoływana za każdym Page razem, gdy a jest przydzielany nowy rozmiar, co dzieje się za każdym razem, gdy urządzenie jest obracane. Należy pamiętać, że podstawowa implementacja funkcji wykonuje ważne funkcje układu, dlatego ważne jest wywołanie implementacji OnSizeAllocated podstawowej w przesłonięciach:

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

Niewykonanie tego kroku spowoduje, że strona nie będzie działać.

Należy OnSizeAllocated pamiętać, że metoda może być wywoływana wiele razy podczas rotacji urządzenia. Zmiana układu za każdym razem powoduje marnowanie zasobów i może prowadzić do migotania. Rozważ użycie zmiennej wystąpienia na stronie, aby śledzić, czy orientacja znajduje się w orientacji poziomej, czy pionowej, i ponownie narysować tylko w przypadku zmiany:

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
    }
}

Po wykryciu zmiany orientacji urządzenia możesz dodać lub usunąć dodatkowe widoki do/z interfejsu użytkownika, aby reagować na zmianę dostępnego miejsca. Rozważmy na przykład wbudowany kalkulator na każdej platformie w orientacji pionowej:

Aplikacja Calculator w orientacji pionowej.

i krajobraz:

Aplikacja Calculator w orientacji poziomej.

Zwróć uwagę, że aplikacje mogą korzystać z dostępnego miejsca, dodając więcej funkcji w krajobrazie.

Układ dynamiczny

Interfejsy można projektować przy użyciu wbudowanych układów, tak aby bezpiecznie przechodziły one w czasie rotacji urządzenia. Podczas projektowania interfejsów, które będą nadal atrakcyjne podczas reagowania na zmiany orientacji, należy wziąć pod uwagę następujące reguły ogólne:

  • Zwróć uwagę na współczynniki – Zmiany orientacji mogą powodować problemy, gdy zostaną przyjęte pewne założenia dotyczące współczynników. Na przykład widok, który będzie miał dużą ilość miejsca w 1/3 pionowej przestrzeni ekranu w pionie, może nie mieścić się w 1/3 pionowej przestrzeni poziomej.
  • Należy zachować ostrożność w przypadku wartości bezwzględnych – wartości bezwzględne (piksele), które mają sens w orientacji pionowej, mogą nie mieć sensu w krajobrazie. Gdy wartości bezwzględne są niezbędne, użyj zagnieżdżonych układów, aby odizolować ich wpływ. Na przykład uzasadnione byłoby użycie wartości bezwzględnych w pliku , gdy szablon TableView ItemTemplate elementu ma gwarantowaną stałą wysokość.

Powyższe reguły mają również zastosowanie podczas implementowania interfejsów dla wielu rozmiarów ekranu i są ogólnie uznawane za najlepsze rozwiązanie. W pozostałej części tego przewodnika objaśnimy konkretne przykłady układów dynamicznych przy użyciu każdego z układów podstawowych w programie Xamarin.Forms .

Uwaga

Dla przejrzystości w poniższych sekcjach pokazano, jak implementować układy dynamiczne przy użyciu tylko jednego Layout typu jednocześnie. W praktyce często łatwiej jest pomieszać elementy w celu uzyskania żądanego układu przy użyciu prostszego lub najbardziej intuicyjnego Layout Layout rozwiązania dla każdego składnika.

StackLayout

Rozważmy następującą aplikację wyświetlaną w pionie:

Zrzut ekranu przedstawia ekran StackLayout aplikacji do zdjęć w orientacji pionowej.

i krajobraz:

Zrzut ekranu przedstawia ekran StackLayout aplikacji do zdjęć w orientacji poziomej.

Jest to realizowane przy użyciu następującego kodu XAML:

<?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>

Niektóre ustawienia języka C# służą do zmieniania orientacji na podstawie outerStack orientacji urządzenia:

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

. Weź pod uwagę następujące kwestie:

  • outerStack Jest dostosowywany w celu przedstawienia obrazu i kontrolek jako poziomego lub pionowego stosu w zależności od orientacji, aby jak najlepiej wykorzystać dostępne miejsce.

AbsoluteLayout

Rozważmy następującą aplikację wyświetlaną w pionie:

Zrzut ekranu przedstawia aplikację do zdjęć AbsoluteLayout w orientacji pionowej.

i krajobraz:

Zrzut ekranu przedstawia aplikację do zdjęć AbsoluteLayout w orientacji poziomej.

Jest to realizowane przy użyciu następującego kodu XAML:

<?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>

. Weź pod uwagę następujące kwestie:

  • Ze względu na sposób układu strony nie ma potrzeby, aby kod proceduralny wprowadzał czas odpowiedzi.
  • Wartość jest używana, aby umożliwić widoczność etykiety nawet wtedy, gdy wysokość ekranu jest mniejsza niż suma stałej wysokości przycisków ScrollView i obrazu.

RelativeLayout

Rozważmy następującą aplikację wyświetlaną w pionie:

Zrzut ekranu przedstawia aplikację do zdjęć RelativeLayout w orientacji pionowej.

i krajobraz:

Zrzut ekranu przedstawia położenie aplikacji do zdjęć RelativeLayout w orientacji poziomej.

Jest to realizowane przy użyciu następującego kodu XAML:

<?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>

. Weź pod uwagę następujące kwestie:

  • Ze względu na układ strony nie ma potrzeby, aby kod proceduralny wprowadzał czas odpowiedzi.
  • Wartość jest używana, aby umożliwić widoczność etykiety nawet wtedy, gdy wysokość ekranu jest mniejsza niż suma stałej wysokości przycisków ScrollView i obrazu.

Siatka

Rozważmy następującą aplikację wyświetlaną w pionie:

Zrzut ekranu przedstawia siatkę aplikacji do zdjęć w orientacji pionowej.

i pozioma:

Zrzut ekranu przedstawia siatkę aplikacji do zdjęć w orientacji poziomej.

Jest to realizowane przy użyciu następującego kodu XAML:

<?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>

Wraz z następującym kodem procedur do obsługi zmian rotacji:

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

. Weź pod uwagę następujące kwestie:

  • Ze względu na układ strony istnieje metoda zmiany położenia siatki kontrolek.