设备方向
了解如何布置在纵向和横向方向看起来很棒的应用程序。
重要的是考虑如何使用您的应用程序,以及如何整合景观导向以改善用户体验。可以设计单独的布局以适应多个方向,并最佳地利用可用空间。在应用程序级别,可以禁用或启用旋转。
本文将指导您创建利用设备导向功能的应用程序,并具有以下部分:
控制方向
使用Xamarin.Forms时,支持的控制设备方向的方法是使用每个项目的设置。
iOS版
在iOS上,为使用Info.plist文件的应用程序配置了设备方向。该文件将包括iPhone和iPod的方向设置,以及iPad的设置,如果应用程序将其作为目标。以下是IDE特有的说明。使用本文档顶部的IDE选项可以选择您要查看的说明:
在Visual Studio中,打开iOS项目并打开Info.plist。该文件将打开到配置面板,从iPhone部署信息选项卡开始:
![iPhone部署信息在Visual Studio](https://developer.xamarin.com/guides/xamarin-forms/user-interface/layouts/device-orientation/Images/orientation_vs_iPhone.png)
要配置iPad方向,请选择面板左上角的“ iPad部署信息”选项卡,然后从可用的方向中选择:
![支持Visual Studio中的设备定向](https://developer.xamarin.com/guides/xamarin-forms/user-interface/layouts/device-orientation/Images/orientation_vs_iPad.png)
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
大于高度时,设备处于横向模式。有关详细信息,请参阅基于屏幕方向显示图像。
或者,可以覆盖一个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);
}
}
}
请注意以下事项:
- 由于页面的布局方式,有一种方法来更改控件的网格位置。