Xamarin.Forms 用户界面——控件——布局——Device Orientation

设备方向

了解如何布置在纵向和横向方向看起来很棒的应用程序。

PDF用于离线使用
示例代码:
相关食谱:

让我们知道你对此的感受

最后更新:2015年12月

重要的是考虑如何使用您的应用程序,以及如何整合景观导向以改善用户体验。可以设计单独的布局以适应多个方向,并最佳地利用可用空间。在应用程序级别,可以禁用或启用旋转。

本文将指导您创建利用设备导向功能的应用程序,并具有以下部分:

  • 控制方向 - 了解如何在每个平台的应用程序级别控制方向。
  • 对方向的变化作出反应 - 学习如何获得通知,并对方向的变化作出反应。
  • 响应布局 - 学习如何创建自动在横向和纵向方向工作的布局。

控制方向

使用Xamarin.Forms时,支持的控制设备方向的方法是使用每个项目的设置。

注意:从Xamarin.Forms 1.5.0开始,有一个错误可以防止基于渲染器的尝试来控制方向失败。有关更多信息,请参阅Xamarin论坛中的 此讨论

iOS版

在iOS上,为使用Info.plist文件的应用程序配置了设备方向。该文件将包括iPhone和iPod的方向设置,以及iPad的设置,如果应用程序将其作为目标。以下是IDE特有的说明。使用本文档顶部的IDE选项可以选择您要查看的说明:

在Visual Studio中,打开iOS项目并打开Info.plist。该文件将打开到配置面板,从iPhone部署信息选项卡开始:

要配置iPad方向,请选择面板左上角的“ iPad部署信息”选项卡,然后从可用的方向中选择:

Android的

要控制Android上的方向,请打开MainActivity.cs并使用装饰MainActivity类的属性设置方向:

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

Xamarin.Android支持几种指定方向的选项:

  • 景观 - 强制应用方向为横向,无论传感器数据如何。
  • 纵向 - 将应用程序方向强制为纵向,无论传感器数据如何。
  • 用户 - 使应用程序使用用户的首选方向显示。
  • 背后 - 使应用程序的方向与其后面的活动的方向相同。
  • 传感器 - 导致应用程序的方向由传感器确定,即使用户已禁用自动旋转。
  • SensorLandscape - 导致应用程序使用横向,同时使用传感器数据来更改屏幕所面向的方向(以便屏幕不被看作是颠倒的)。
  • SensorPortrait - 使用传感器数据来改变屏幕所面向的方向,使应用程序使用纵向定向(因此屏幕不会被看作是颠倒的)。
  • ReverseLandscape - 使应用程序使用横向,面向与往常相反的方向,以便显示“颠倒”。
  • ReversePortrait - 使应用程序使用纵向方向,面向与往常相反的方向,以便显示“颠倒”。
  • FullSensor - 使应用程序依靠传感器数据来选择正确的方向(从可能的4)。
  • FullUser - 使应用程序使用用户的方向偏好。如果启用自动旋转,则可以使用所有4个方向。
  • UserLandscape - [不支持]导致应用程序使用横向,除非用户已启用自动旋转,在这种情况下,它将使用传感器来确定方向。此选项将中断编译。
  • UserPortrait - [不支持]导致应用程序使用纵向方向,除非用户已启用自动旋转,在这种情况下,它将使用传感器来确定方向。此选项将中断编译。
  • 锁定 - [不支持] 导致应用程序使用屏幕方向,无论它在启动时,而不响应设备的物理方向的更改。此选项将中断编译。

请注意,本机Android API可以很好地控制如何管理方向,其中包括与用户表达的偏好相抵触的选项。

Windows Phone

在Windows Phone RT上,支持的方向在Package.appxmanifest文件中设置。打开清单将显示一个配置面板,可以选择支持的方向:

在Windows Phone 8(Silverlight)上,支持的方向在MainPage.xaml.cs文件的代码中设置。在默认项目模板中,该值已经使用以下代码行进行设置:

SupportedOrientations = SupportedPageOrientation.PortraitOrLandscape;

要在Windows Phone上指定方向选项,请使用代码替换以启用所需的方向:

SupportedOrientations = SupportedPageOrientation.PortraitOrLandscape;
SupportedOrientations = SupportedPageOrientation.Portrait; // portrait only
SupportedOrientations = SupportedPageOrientation.Landscape; // landscape only

请注意,Windows Phone支持横向视图(从纵向看)从左到右和从右到左的方向。不可能指定使用哪个。

反应方向的变化

Xamarin.Forms不提供任何本地事件来通知您的应用程序在共享代码中的方向更改。然而,SizeChanged所述的事件Page触发时的宽度或高度Page的变化。当宽度Page大于高度时,设备处于横向模式。有关详细信息,请参阅基于屏幕方向显示图像

注意:有一个现有的,免费的NuGet软件包,用于接收共享代码中方向更改的通知。有关更多信息,请参阅 GitHub回购

或者,可以覆盖一个OnSizeAllocated方法,在Page那里插入任何布局更改逻辑。OnSizeAllocated每当a Page被分配一个新的大小时,调用该方法,这在设备旋转时发生。请注意,OnSizeAllocated执行重要的布局功能的基础实现,所以在覆盖中调用base实现很重要:

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

不采取该步骤将导致无效页面。

请注意,OnSizeAllocated当设备旋转时,可能会多次调用该方法。每次更改布局都浪费资源,并可能导致闪烁。考虑在页面中使用一个实例变量来跟踪方向是横向还是纵向,只有当有变化时才重新绘制:

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

检测到设备方向更改后,您可能需要向用户界面添加或删除其他视图,以对可用空间的更改做出反应。例如,考虑每个平台上的内置计算器:

景观:

请注意,应用程序可以通过在景观中添加更多功能来利用可用空间。

响应布局

可以使用内置的布局来设计界面,以便在旋转设备时正常地转换。当设计在响应方向变化时继续吸引人的界面时,请考虑以下一般规则:

  • 注意比率 - 在比较方面做出某些假设时,方向的变化可能会导致问题。例如,在纵向的屏幕的垂直空间的1/3中将具有足够的空间的视图可能不适合于景观中的垂直空间的1/3。
  • 要注意绝对值 - 在肖像中有意义的绝对(像素)值在景观上可能没有意义。当需要绝对值时,使用嵌套布局来隔离其影响。例如,TableView ItemTemplate当项目模板具有有保证的均匀高度时,使用绝对值是合理的。

当实现多个屏幕尺寸的接口时,上述规则也适用,并且通常被认为是最佳实践。本指南的其余部分将解释使用Xamarin.Forms中每个主要布局的响应布局的具体示例。

注意:为了清楚起见,以下部分将演示如何使用一次只能使用一种类型的响应式布局 Layout。在实践中, Layout通过使用更简单或最直观 Layout的每个组件来混合s来实现所需的布局通常更简单。

StackLayout

考虑以下应用程序,以纵向显示:

景观:

这是通过以下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>

一些C#用于outerStack根据设备的方向改变方向:

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

请注意以下事项:

  • outerStack 被调整为根据取向呈现图像并作为水平或垂直堆叠进行控制,以最好地利用可用空间。

AbsoluteLayout

考虑以下应用程序,以纵向显示:

景观:

这是通过以下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" BackgroundImage="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>

请注意以下事项:

  • 由于页面的布局方式,不需要程序代码来引入响应。
  • ScrollView即使当屏幕的高度小于按钮和图像的固定高度的总和时,它也被用于允许标签可见。

的RelativeLayout

考虑以下应用程序,以纵向显示:

景观:

这是通过以下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"
BackgroundImage="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>

请注意以下事项:

  • 由于页面的布局方式,不需要程序代码来引入响应。
  • ScrollView即使当屏幕的高度小于按钮和图像的固定高度的总和时,它也被用于允许标签可见。

考虑以下应用程序,以纵向显示:

景观:

这是通过以下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>

随着以下程序代码来处理轮换更改:

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

请注意以下事项:

  • 由于页面的布局方式,有一种方法来更改控件的网格位置。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值