在 Windows 8.1 Store 应用程序中处理方向 [英] Handling Orientation in Windows 8.1 Store app
问题描述
我正在制作一个 Win Store 应用程序,并面临着处理方向的问题.
I am making a Win Store App, and facing the issue to handle orientation.
有一个网格,我想在改变方向时修改它的设计.两侧的堆栈面板(在横向视图中)应在纵向视图中转到顶部和底部.
There is a grid, I want to modify the design of it when the orientation is changed. The stack Panels in both the sides (in Landscape View) should goto Top and Bottom in Portrait View.
目前我已经创建了两个包含所有控件的网格,并根据方向调整它们,并使用 VisualStateManager 切换可见性属性.
Currently I have created two grids with all the controls and adjust them according to the orientation, and switching the visibility property, using VisualStateManager.
但我想用一个网格来实现这一点,任何建议对我都有很大帮助.
But I want to achieve this with a single grid, any suggestion will be a great help for me.
下图是应用的概念设计:
The below image is the concept design of the app:
推荐答案
用单个 Grid 做到这一点很困难,但可能.
Doing this with a single Grid is difficult, but possible.
首先,您可能想要做的是少担心方向,多担心水平宽度.这样,如果用户以没有太多水平空间(类似于纵向模式)的方式捕捉应用,您可以显示类似的体验.
Firstly, what you probably want to do is worry less about orientation and more about horizontal width. That way, if the user snaps the app in such a way that there isn't much horizontal space (similar to portrait mode), you can display a similar experience.
现在,进入网格.
这里的关键是您正在从本质上具有 3 列的 Grid
移动到具有 1 列的网格.因此,您需要修改单元格的 ColumnSpan
属性.
The key here is that you are moving from a Grid
with, in essence, 3 Columns to one with 1 Column. As such, you will need to modify the ColumnSpan
Property of your cells.
到目前为止您绘制的内容有 3 个 Columns
,每个的 Width
为 GridLength *
.从那里开始.
What you have drawn so far has 3 Columns
, each with a Width
of GridLength *
. Start there.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
</Grid>
接下来,我们要设置Rows
.最好使行数成为您需要的最大数量,这是我的计数 6.如果将它们全部设置为 Auto
,则空 Rows
(在横向)将消失.
Next, we want to set up the Rows
. It's better to make the number of Rows the largest that you'll need, which is by my count 6. If you set them all to Auto
, then the empty Rows
(in the Landscape orientation) will disappear.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Width="Auto"/>
<RowDefinition Width="Auto"/>
<RowDefinition Width="Auto"/>
<RowDefinition Width="Auto"/>
<RowDefinition Width="Auto"/>
<RowDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
</Grid>
现在,创建一些基本内容.我只是要创建一堆不同的 StackPanel
并命名它们包含在其中的内容.
Now, to create some basic contents. I'm just going to create a bunch of different StackPanel
s and name them what you have contained in them.
我将默认的 Grid/Row
值设置为 Landscape
的值.我还为第二行"使用了两行(包含 StackPanel
s 1 和 2).两个 StackPanel
都将有一个 RowSpan
为 2 来补偿.
I am setting the default Grid/Row
values to that of Landscape
. I am also using two rows for the 'Second Row' (containing StackPanel
s 1 and 2). Both StackPanel
s will have a RowSpan
of 2 to compensate.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Width="Auto"/>
<RowDefinition Width="Auto"/>
<RowDefinition Width="Auto"/>
<RowDefinition Width="Auto"/>
<RowDefinition Width="Auto"/>
<RowDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<StackPanel Name="HeaderRow" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3"/>
<StackPanel Name="StackPanel1" Grid.Row="1" Grid.Column="0" Grid.RowSpan="2"/>
<StackPanel Name="Content" Grid.Row="1" Grid.Column="1"/>
<StackPanel Name="BlueSection" Grid.Row="2" Grid.Column="1"/>
<StackPanel Name="StackPanel2" Grid.Row="1" Grid.Column="2" Grid.RowSpan="2"/>
<StackPanel Name="FooterRow" Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="3"/>
</Grid>
现在我们对 Landscape
方向有了一个很好的定义.它也会根据其中的内容自动调整垂直大小,但您可以随意调整所需的最小大小.
Now we have a nice definition for your Landscape
orientation. It will automatically size vertically based on the content within it as well, though you are free to do whatever minimum sizing you want.
既然我们已经做到了这一点,我们只需要为不同的尺寸创建一些VisualStates
.在一个 VisualState
中,我们将准确定义我们已经完成的工作.另一方面,我们将创建一个新的.我现在将它们命名为横向"和纵向",但我建议做一些类似中"和宽"的事情,然后根据给定的 Bounds
定义使用哪个.为了篇幅,我省略了之前的定义.
Now that we've done this, we just need to create some VisualStates
for our different sizes. In one VisualState
we will be defining exactly what we've already done. In the other, we will be creating a new one. I am naming them 'Landscape' and 'Portrait' for now, but I suggest doing something like 'Mid' and 'Wide', and then defining which is used based on the Bounds
given. I have omitted the previous definitions for the sake of space.
从技术上讲,我们不需要包含 Landscape
定义,但我将其作为附加示例包含在内.
Technically, we don't need to include the Landscape
definition, but I'm including it as an additional example.
注意:在第二张图片中,您有 StackPanel2
下面 Footer
.我在下面反映了这一点.如果需要更改,只需将 StackPanel2
的行定义更改为 4
,将 Footer
的行定义更改为 5
.
Note: In the second picture, you have StackPanel2
below Footer
. I have reflected this below. If you need that changed, just change the row definitions of StackPanel2
to 4
and of Footer
to 5
.
<Grid>
...
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="OrientationStates">
<!-- What we've already defined -->
<VisualState x:Name="Landscape">
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.RowSpan)" Storyboard.TargetName="StackPanel1">
<DiscreteObjectKeyFrame KeyTime="0" Value="2"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.ColumnSpan)" Storyboard.TargetName="StackPanel1">
<DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
</ObjectAnimationUsingKeyFrames>
<!-- Stack Panel 2 -->
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.RowSpan)" Storyboard.TargetName="StackPanel2">
<DiscreteObjectKeyFrame KeyTime="0" Value="2"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.ColumnSpan)" Storyboard.TargetName="StackPanel2">
<DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.Row)" Storyboard.TargetName="StackPanel2">
<DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.Column)" Storyboard.TargetName="StackPanel2">
<DiscreteObjectKeyFrame KeyTime="0" Value="2"/>
</ObjectAnimationUsingKeyFrames>
<!-- Content -->
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.Row)" Storyboard.TargetName="Content">
<DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.Column)" Storyboard.TargetName="Content">
<DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.ColumnSpan)" Storyboard.TargetName="Content">
<DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
</ObjectAnimationUsingKeyFrames>
<! -- Blue Section -->
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.Row)" Storyboard.TargetName="BlueSection">
<DiscreteObjectKeyFrame KeyTime="0" Value="2"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.Column)" Storyboard.TargetName="BlueSection">
<DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.ColumnSpan)" Storyboard.TargetName="BlueSection">
<DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
</ObjectAnimationUsingKeyFrames>
<!-- Footer -->
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.Row)" Storyboard.TargetName="Footer">
<DiscreteObjectKeyFrame KeyTime="0" Value="3"/>
</ObjectAnimationUsingKeyFrames>
</VisualState>
<!-- The New Section -->
<VisualState x:Name="Portrait">
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.RowSpan)" Storyboard.TargetName="StackPanel1">
<DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.ColumnSpan)" Storyboard.TargetName="StackPanel1">
<DiscreteObjectKeyFrame KeyTime="0" Value="3"/>
</ObjectAnimationUsingKeyFrames>
<!-- Stack Panel 2 -->
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.RowSpan)" Storyboard.TargetName="StackPanel2">
<DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.ColumnSpan)" Storyboard.TargetName="StackPanel2">
<DiscreteObjectKeyFrame KeyTime="0" Value="3"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.Row)" Storyboard.TargetName="StackPanel2">
<DiscreteObjectKeyFrame KeyTime="0" Value="5"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.Column)" Storyboard.TargetName="StackPanel2">
<DiscreteObjectKeyFrame KeyTime="0" Value="0"/>
</ObjectAnimationUsingKeyFrames>
<!-- Content -->
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.Row)" Storyboard.TargetName="Content">
<DiscreteObjectKeyFrame KeyTime="0" Value="2"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.Column)" Storyboard.TargetName="Content">
<DiscreteObjectKeyFrame KeyTime="0" Value="0"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.ColumnSpan)" Storyboard.TargetName="Content">
<DiscreteObjectKeyFrame KeyTime="0" Value="3"/>
</ObjectAnimationUsingKeyFrames>
<! -- Blue Section -->
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.Row)" Storyboard.TargetName="BlueSection">
<DiscreteObjectKeyFrame KeyTime="0" Value="3"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.Column)" Storyboard.TargetName="BlueSection">
<DiscreteObjectKeyFrame KeyTime="0" Value="0"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.ColumnSpan)" Storyboard.TargetName="BlueSection">
<DiscreteObjectKeyFrame KeyTime="0" Value="3"/>
</ObjectAnimationUsingKeyFrames>
<!-- Footer -->
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.Row)" Storyboard.TargetName="Footer">
<DiscreteObjectKeyFrame KeyTime="0" Value="4"/>
</ObjectAnimationUsingKeyFrames>
</VisualState>
</VisualStateGroup>
<VisualStateManager.VisualStateGroups>
</Grid>
你快完成了.您所需要的只是让您的 Page
监听 WindowSizeChanged
并响应它!它需要获得对您的 Grid
的引用.因此,我建议添加 x:Name="ContentGrid"
或类似于基本 Grid
定义的内容.如:
You're almost done. All you need left is for your Page
to listen for WindowSizeChanged
and respond to it! It needs to get a reference to your Grid
. As such, I suggest adding x:Name="ContentGrid"
or something similar to the base Grid
definition. Such as:
<Grid x:Name="ContentGrid">
我的 WindowSizeChanged
示例将假设您已完成此操作.
My example for WindowSizeChanged
will assume you have done this.
private void WindowSizeChanged(object sender, WindowSizeChangedEventArgs windowSizeChangedEventArgs)
{
if (windowSizeChangedEventArgs.Size.Width < 800)
{
VisualStateManager.GoToState(ContentGrid, "Portrait", true);
}
else
{
VisualStateManager.GoToState(ContentGrid, "Landscape", true);
}
}
然后,在您的 Page
的 OnNavigatedTo
和 OnNavigatedFrom
...
Then, in your Page
's OnNavigatedTo
and OnNavigatedFrom
...
protected override void OnNavigatedTo(NavigationEventArgs e)
{
Window.Current.SizeChanged += WindowSizeChanged;
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
Window.Current.SizeChanged -= WindowSizeChanged;
}
确保在从页面导航时删除 SizeChanged
event
处理程序,否则您的应用程序将无限期地在内存中保留您的页面副本.这是如何创建有趣的内存泄漏.
Make sure you remove the SizeChanged
event
handler on navigating from the page, otherwise your app will retain a copy of your page in memory indefinitely. This is how to create a fun memory leak.
就是这样!在大小改变时,您的主页将通知您的网格它需要重新配置自己,并且它将按照描述的方式进行.显然你不能直接粘贴它,但你应该可以使用很多.确保将 TargetNames
更改为您命名的控件.
And that's it! On size changed, your main page will notify your Grid that it needs to reconfigure itself and it will do so in the way described. Obviously you won't be able to directly paste this in, but you should be able to use a lot of it. Make sure to change the TargetNames
to your named controls.
希望这会有所帮助并祝您编码愉快!
Hope this helps and happy coding!
这篇关于在 Windows 8.1 Store 应用程序中处理方向的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!