Xamarin.Forms是否已经包含一个根据屏幕方向或大小排序内容的控件/布局?我想要的:如果屏幕有足够的空间,两个水平排列的堆栈布局。当屏幕改变,屏幕没有足够的水平空间时,两个堆栈布局应该垂直排列。我不想在代码后面做。我寻找一个只使用xaml的解决方案。
0qx6xfy61#
我猜你不能只使用XAML来实现这一点。当然,你需要一些c#代码。Xamarin.Forms上的XAML被设计成响应式的,并且你经常以相对模式(而不是绝对模式)定义视图属性。您可以在本主题中看到所需行为的示例,其中我们可以看到屏幕根据设备方向更改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; } } }
希望能帮到你。
ac1kyiln2#
据我所知,这是不可能的。我基本上完全按照你的要求“手动”完成了。不过,这并不太难。首先,你必须将你的堆栈布局 Package 在另一个StackLayout中
StackLayout
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="App.Views.TestPage"> <ContentPage.Content> <StackLayout x:Name="OuterStackLayout"> <StackLayout> <!-- Inner stack layout 1 --> </StackLayout> <StackLayout> <!-- Inner stack layout 2 --> </StackLayout> </StackLayout> </ContentPage.Content> </ContentPage>
接下来,必须重写OnSizeAllocated,并根据屏幕方向设置外部OuterStackLayout.Orientation
OnSizeAllocated
OuterStackLayout.Orientation
protected override void OnSizeAllocated(double width, double height) { base.OnSizeAllocated(width, height); if (SizeHasChanged(width, height)) // elided, just compare width, height with the stored values { StoreSize(width, height); // store in private members if (IsLandscape) { this.OuterStackLayout.Orientation = StackOrientation.Horizontal; } else { this.OuterStackLayout.Orientation = StackOrientation.Vertical; } } } public bool IsLandscape => _width > _height;
也许您需要稍微修改一下内部StackLayout的水平选项或其他布局参数,但基本上这就足够了。
igsr9ssn3#
选项#1“方向状态”-纵向和横向。在可视状态管理器中使用“OrientationStates”,如下所示:在.XAML文件内部
<Grid x:Name="myGrid" Margin="10,30,10,10"> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="OrientationStates"> <!-- Row & Column Definitions of Grid - [2 Rows, 1 Col = Portrait] & [1 Row, 2 Cols = Landscape] --> <VisualState x:Name="Portrait"> <VisualState.Setters> <Setter Property="Grid.RowDefinitions" Value="*,*" /> <Setter Property="Grid.ColumnDefinitions" Value="*" /> </VisualState.Setters> </VisualState> <VisualState x:Name="Landscape"> <VisualState.Setters> <Setter Property="Grid.RowDefinitions" Value="*" /> <Setter Property="Grid.ColumnDefinitions" Value="*,*" /> </VisualState.Setters> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <!-- Change position of stack layouts in grid, to match above stated orientation requirement --> <StackLayout x:Name="firstStackLayout"> <Entry Placeholder="Enter first words" /> <Button Text="Nothing Happens" /> <VisualStateManager.VisualStateGroups> <VisualStateGroup> <VisualState x:Name="Portrait"> <VisualState.Setters> <Setter Property="Grid.Row" Value="0" /> <Setter Property="Grid.Column" Value="0" /> </VisualState.Setters> </VisualState> <VisualState x:Name="Landscape"> <VisualState.Setters> <Setter Property="Grid.Row" Value="0" /> <Setter Property="Grid.Column" Value="0" /> </VisualState.Setters> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> </StackLayout> <StackLayout x:Name="secondStackLayout"> <Entry Placeholder="Enter last words" /> <Button Text="Still Nothing Happens" /> <VisualStateManager.VisualStateGroups> <VisualStateGroup> <VisualState x:Name="Portrait"> <VisualState.Setters> <Setter Property="Grid.Row" Value="1" /> <Setter Property="Grid.Column" Value="0" /> </VisualState.Setters> </VisualState> <VisualState x:Name="Landscape"> <VisualState.Setters> <Setter Property="Grid.Row" Value="0" /> <Setter Property="Grid.Column" Value="1" /> </VisualState.Setters> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> </StackLayout> </Grid>
在CodeBehind中添加了“OnSizeAllocated()”函数,如下所示:在. XAML.CS文件内部
public partial class RegisterPage : ContentPage { public RegisterPage() { InitializeComponent(); } protected override void OnSizeAllocated(double width, double height) { base.OnSizeAllocated(width, height); var state = (width > height) ? "Landscape" : "Portrait"; // Call the 'Portrait' & 'Landscape' States in .XAML File VisualStateManager.GoToState(myGrid, state); VisualStateManager.GoToState(firstStackLayout, state); VisualStateManager.GoToState(secondStackLayout, state); } }
[或]选项#2魔术子弹-您的唯一的.XAML文件解决方案该问题。“方向触发器”-纵向和横向。在可视化状态中使用“状态触发器”内的“OrientationStateTriggers”,如下所示:在.XAML文件内部
<Grid Margin="10,30,10,10"> <VisualStateManager.VisualStateGroups> <VisualStateGroup> <!-- Row & Column Definitions of Grid - [2 Rows, 1 Col = Portrait] & [1 Row, 2 Cols = Landscape] --> <VisualState x:Name="gridPortrait"> <VisualState.StateTriggers> <OrientationStateTrigger Orientation="Portrait" /> </VisualState.StateTriggers> <VisualState.Setters> <Setter Property="Grid.RowDefinitions" Value="*,*" /> <Setter Property="Grid.ColumnDefinitions" Value="*" /> </VisualState.Setters> </VisualState> <VisualState x:Name="gridLandscape"> <VisualState.StateTriggers> <OrientationStateTrigger Orientation="Landscape" /> </VisualState.StateTriggers> <VisualState.Setters> <Setter Property="Grid.RowDefinitions" Value="*" /> <Setter Property="Grid.ColumnDefinitions" Value="*,*" /> </VisualState.Setters> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <!-- Change position of stack layouts in grid, to match above stated orientation requirement --> <StackLayout> <Entry Placeholder="Enter first words" /> <Button Text="Nothing Happens" /> <VisualStateManager.VisualStateGroups> <VisualStateGroup> <VisualState x:Name="myPortraitState"> <VisualState.StateTriggers> <OrientationStateTrigger Orientation="Portrait" /> </VisualState.StateTriggers> <VisualState.Setters> <Setter Property="Grid.Row" Value="0" /> <Setter Property="Grid.Column" Value="0" /> </VisualState.Setters> </VisualState> <VisualState x:Name="myLandscapeState"> <VisualState.StateTriggers> <OrientationStateTrigger Orientation="Landscape" /> </VisualState.StateTriggers> <VisualState.Setters> <Setter Property="Grid.Row" Value="0" /> <Setter Property="Grid.Column" Value="0" /> </VisualState.Setters> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> </StackLayout> <StackLayout> <Entry Placeholder="Enter last words" /> <Button Text="Still Nothing Happens" /> <VisualStateManager.VisualStateGroups> <VisualStateGroup> <VisualState x:Name="myPortraitState"> <VisualState.StateTriggers> <OrientationStateTrigger Orientation="Portrait" /> </VisualState.StateTriggers> <VisualState.Setters> <Setter Property="Grid.Row" Value="1" /> <Setter Property="Grid.Column" Value="0" /> </VisualState.Setters> </VisualState> <VisualState x:Name="myLandscapeState"> <VisualState.StateTriggers> <OrientationStateTrigger Orientation="Landscape" /> </VisualState.StateTriggers> <VisualState.Setters> <Setter Property="Grid.Row" Value="0" /> <Setter Property="Grid.Column" Value="1" /> </VisualState.Setters> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> </StackLayout> </Grid>
o75abkj44#
希望我还不算太晚,使用Xamarin.Essentials对我来说是一个更简单的解决方案。Model.cs
Xamarin.Essentials
Model.cs
using Xamarin.Essentials; . . . private DisplayOrientation orientation = DeviceDisplay.MainDisplayInfo.Orientation; public DisplayOrientation Orientation { get => orientation; set => orientation = value; }
View.xaml.cs
using Xamarin.Essentials; . . . protected override void OnSizeAllocated(double width, double height) { base.OnSizeAllocated(width, height); model.Orientation = DeviceDisplay.MainDisplayInfo.Orientation; }
View.xaml
<ContentPage xmlns:ess="clr-namespace:Xamarin.Essentials;assembly=Xamarin.Essentials"> <ContentPage.BindingContext> <!--Model here--> </ContentPage.BindingContext> <DataTrigger TargetType="..." Binding="{Binding Orientation}" Value="{x:Static ess:DisplayOrientation.Portrait}"> <Setter Property="..." Value="..." /> </DataTrigger> <DataTrigger TargetType="..." Binding="{Binding Orientation}" Value="{x:Static ess:DisplayOrientation.Landscape}"> <Setter Property="..." Value="..." /> </DataTrigger> </ContentPage>
不要忘记INotifyPropertyChanged的含义。
INotifyPropertyChanged
4条答案
按热度按时间0qx6xfy61#
我猜你不能只使用XAML来实现这一点。当然,你需要一些c#代码。Xamarin.Forms上的XAML被设计成响应式的,并且你经常以相对模式(而不是绝对模式)定义视图属性。
您可以在本主题中看到所需行为的示例,其中我们可以看到屏幕根据设备方向更改StackLayout的方向(您可以将其作为编写自己的布局组件的指南)
纵向模式下的屏幕:
横向模式下的屏幕:
这是通过以下XAML实现的:
一些C#用于根据设备的方向更改outerStack的方向:
希望能帮到你。
ac1kyiln2#
据我所知,这是不可能的。我基本上完全按照你的要求“手动”完成了。不过,这并不太难。首先,你必须将你的堆栈布局 Package 在另一个
StackLayout
中接下来,必须重写
OnSizeAllocated
,并根据屏幕方向设置外部OuterStackLayout.Orientation
也许您需要稍微修改一下内部
StackLayout
的水平选项或其他布局参数,但基本上这就足够了。igsr9ssn3#
选项#1“方向状态”-纵向和横向。在可视状态管理器中使用“OrientationStates”,如下所示:
在.XAML文件内部
在CodeBehind中添加了“OnSizeAllocated()”函数,如下所示:
在. XAML.CS文件内部
[或]
选项#2魔术子弹-您的唯一的.XAML文件解决方案该问题。
“方向触发器”-纵向和横向。
在可视化状态中使用“状态触发器”内的“OrientationStateTriggers”,如下所示:
在.XAML文件内部
o75abkj44#
希望我还不算太晚,使用
Xamarin.Essentials
对我来说是一个更简单的解决方案。Model.cs
View.xaml.cs
View.xaml
不要忘记
INotifyPropertyChanged
的含义。