简体   繁体   English

在 .NET MAUI 中,有一种方法可以根据设备是横向还是纵向来选择不同的 XAML 视图

[英]In .NET MAUI is there a way to choose a different XAML view based upon whether the device is in Landscape or Portrait

I am using .NET MAUI and I have a particular view that is rather complicated and I would rather have a different layout if the device orientation is in Portrait vs if the device orientation is in landscape.我正在使用 .NET MAUI,我有一个相当复杂的特定视图,如果设备方向是纵向,我宁愿有不同的布局,如果设备方向是横向。

I tinkered around with Android programming a long time ago and for Android Studio there was a way to choose a XAML file when the device was in landscape and a different XAML file when the device was in portrait.很久以前,我修改了 Android 编程,对于 Android Studio,有一种方法可以在设备横向时选择 XAML 文件,而在设备纵向时选择不同的 XAML 文件。

Is this possible with MAUI?这对 MAUI 来说可能吗? If not what is the best practice in regards to this?如果不是,这方面的最佳做法是什么?

Here is my layout and in landscape mode I can fit 3 major sections in one row but this won't work in portrait and in portrait I would like the middle major element to be on the next row.这是我的布局,在横向模式下,我可以在一行中放置 3 个主要部分,但这在纵向模式下不起作用,而在纵向模式下,我希望中间的主要元素位于下一行。

Here are examples of my portrait vs landscape mockup I created on Photoshop:以下是我在 Photoshop 上创建的肖像与风景模型的示例:

在此处输入图像描述

UPDATE WITH SOLUTION *************** I'm attempting the solution that FreakyAli posted and have a mostly working prototype, so anyone who is wanting to use a different XAML layout based upon the screen orientation can use this approach.更新解决方案*************** 我正在尝试 FreakyAli 发布的解决方案并且有一个主要工作的原型,所以任何想要根据屏幕方向使用不同的 XAML 布局的人可以使用这种方法。

I created a new folder called "ContentViews" in my solution.我在我的解决方案中创建了一个名为“ContentViews”的新文件夹。 I added 3 new ContentViews (the XAML with the code behind):我添加了 3 个新的 ContentViews(带有后面代码的 XAML):

  1. HomePageLandscape首页风景
  2. HomePagePortrait主页肖像
  3. HomePageOrientationViewLoader HomePageOrientationViewLoader

The HomePageOrientationViewLoader will get loaded directly into the HomePage.xaml file later on. HomePageOrientationViewLoader 稍后将直接加载到 HomePage.xaml 文件中。 This is the control that will load either the HomePagePortrait ContentView when in portrait mode or HomePageLandscape ContentView when in landscape mode.这是将在纵向模式下加载 HomePagePortrait ContentView 或在横向模式下加载 HomePageLandscape ContentView 的控件。

namespace ScoreKeepersBoard.ContentViews;

public partial class HomePageOrientationViewLoader : ContentView
{

    public ContentView homePagePortraitContentView;
    public ContentView homePageLandscapeContentView;

    public HomePageOrientationViewLoader()
    {
        InitializeComponent();

        homePagePortraitContentView = new HomePagePortrait();
        homePageLandscapeContentView = new HomePageLandscape();
        this.Content = homePageLandscapeContentView;

        DeviceDisplay.Current.MainDisplayInfoChanged += Current_MainDisplayInfoChanged;
        this.Content = DeviceDisplay.Current.MainDisplayInfo.Orientation == DisplayOrientation.Portrait ? homePagePortraitContentView : homePageLandscapeContentView;

    }

    private void Current_MainDisplayInfoChanged(object sender, DisplayInfoChangedEventArgs e)
    {

        if (e.DisplayInfo.Orientation == DisplayOrientation.Landscape)
        {
           // if (this.Content.GetType() is not typeof(HomePageLandscape))
           // {
                this.Content = homePageLandscapeContentView;
           // }
        }
        else if (e.DisplayInfo.Orientation == DisplayOrientation.Portrait)
        {
            // if (this.Content.GetType() is not typeof(HomePagePortrait))
            // {
            this.Content = homePagePortraitContentView;
            // }
        }
        else
        {
            //Whatever you would like to do if the orientation is unknown.
        }

    }
}

The HomePageOrientationViewLoader.xaml file: HomePageOrientationViewLoader.xaml 文件:

<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ScoreKeepersBoard.ContentViews.HomePageOrientationViewLoader">
    <VerticalStackLayout>
        <Label 
            Text="Welcome to .NET MAUI!"
            VerticalOptions="Center" 
            HorizontalOptions="Center" />
    </VerticalStackLayout>
</ContentView>

Here is the HomePagePortrait.xaml.cs file:这是 HomePagePortrait.xaml.cs 文件:

namespace ScoreKeepersBoard.ContentViews;

public partial class HomePagePortrait : ContentView
{
    public HomePagePortrait()
    {
        InitializeComponent();
    }
}

Here is the HomePagePortrait.xaml file:这是 HomePagePortrait.xaml 文件:

<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ScoreKeepersBoard.ContentViews.HomePagePortrait">
    <VerticalStackLayout>
        <Label 
            Text="Welcome to .NET MAUI portrait"
            VerticalOptions="Center" 
            HorizontalOptions="Center" />
    </VerticalStackLayout>
</ContentView>

Here is the HomePageLandscape.xaml.cs file:这是 HomePageLandscape.xaml.cs 文件:

namespace ScoreKeepersBoard.ContentViews;

public partial class HomePageLandscape : ContentView
{
    public HomePageLandscape()
    {
        InitializeComponent();
    }
}

Here is the HomePageLandscape.xaml file:这是 HomePageLandscape.xaml 文件:

<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ScoreKeepersBoard.ContentViews.HomePageLandscape">
    <VerticalStackLayout>
        <Label 
            Text="Welcome to .NET MAUI landscape"
            VerticalOptions="Center" 
            HorizontalOptions="Center" />
    </VerticalStackLayout>
</ContentView>

My project had an initial home Content Page called HomePage.我的项目有一个名为 HomePage 的初始主页内容页面。 We are loading the HomePageOrientationViewLoader ContentView into the xaml of HomePage Content Page as a custom control.我们正在将 HomePageOrientationViewLoader ContentView 作为自定义控件加载到 HomePage Content Page 的 xaml 中。 Note that I had to define the namespace that the ContentViews were located in and use that when defining the control in the xaml file:请注意,我必须定义 ContentView 所在的命名空间,并在 xaml 文件中定义控件时使用它:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:controls="clr-namespace:ScoreKeepersBoard.ContentViews"
             x:Class="ScoreKeepersBoard.Views.HomePage"
             Title="HomePage">
    <VerticalStackLayout>
        <Label 
            Text="Welcome to .NET MAUI Home Page Content Page"
            VerticalOptions="Center" 
            HorizontalOptions="Center" />

       <controls:HomePageOrientationViewLoader></controls:HomePageOrientationViewLoader>
        
    </VerticalStackLayout>
</ContentPage>

Here is the code behind for the home page这是主页背后的代码

namespace ScoreKeepersBoard.Views;

public partial class HomePage : ContentPage
{
    public HomePage(HomeViewModel homeViewModel)
    {
        
        InitializeComponent();
    }         
}

and when the project runs on my iphone simulator in portrait mode:当项目以纵向模式在我的 iphone 模拟器上运行时:

在此处输入图像描述

You will see the second label shown says "Welcome to .NET MAUI portrait" which is the view from the portrait content view and when I switch to landscape:您将看到显示的第二个 label 显示“欢迎使用 .NET MAUI 肖像”,这是肖像内容视图的视图,当我切换到风景时:

在此处输入图像描述

You will see the second label shown says "Welcome to .NET MAUI landscape" which is the view from the landscape content view.您将看到显示的第二个 label 显示“欢迎使用 .NET MAUI 横向”,这是横向内容视图中的视图。

ISSUES问题

  1. This works on my iPhone simulator but when I switch to my Android pixel 5 simulator and toggle my switch phone orientation it doesn't work and putting in line breaks the code defined in HomePageOrientationViewLoader is not triggered.这适用于我的 iPhone 模拟器,但是当我切换到我的 Android 像素 5 模拟器并切换我的切换手机方向时,它不起作用并且插入换行符,不会触发 HomePageOrientationViewLoader 中定义的代码。 NEW NOTE: I tried this on a physical Android phone and it is working so it must have just been the emulator.新注意事项:我在 Android 实体手机上试过这个,它正在工作,所以它一定是模拟器。

  2. I will need to use this for a non trivial example that has a view model that will be holding data on a sports game score, timing, etc. I guess I will just need to inject a singleton of the view model into each and they will just share and if the orientation switches the other Content View will load and the view model will bind to the appropriate controls?我需要将它用于一个非平凡的示例,该示例的视图 model 将保存体育比赛得分、计时等数据。我想我只需要将视图 model 的 singleton 注入每个视图,它们将只是分享,如果方向切换,其他内容视图将加载,视图 model 将绑定到适当的控件?

  3. The initial suggested code by FreakyAli had this check: FreakyAli 最初建议的代码有这个检查:

     if (e.DisplayInfo.Orientation == DisplayOrientation.Landscape) { if (this.Content.GetType() is not typeof(HomePageLandscape)) { this.Content = homePageLandscapeContentView; } }

but the part "typeof(HomePageLandscape) gives me an error and says a constant is expected.但是“typeof(HomePageLandscape)”部分给我一个错误,并说需要一个常数。

Other than that the different views for different orientations is working and I thank FreakyAli mightily, I am sure I will figure out why the Android emulator is not triggering the orientation switch code.除此之外,不同方向的不同视图正在工作,我非常感谢 FreakyAli,我相信我会弄清楚为什么 Android 模拟器没有触发方向切换代码。 but suggestions would be awesome.但建议会很棒。

Ideally this is how i would handle such a scenario:理想情况下,这就是我处理这种情况的方式:

In my constructor, I would get the DisplayInfoChanged event which notifies me if this info changes and i would also assign my current ContentView based on the current Orientation:在我的构造函数中,我会得到 DisplayInfoChanged 事件,如果此信息发生变化,它会通知我,我还会根据当前方向分配我当前的 ContentView:

DeviceDisplay.Current.MainDisplayInfoChanged += Current_MainDisplayInfoChanged;
this.Content = DeviceDisplay.Current.MainDisplayInfo.Orientation == DisplayOrientation.Portrait ? potraitView : landscapeView;

Here PortraitView is a ContentView that is the View I would display when my device is in Portrait and Vice Versa.这里的 PortraitView 是一个 ContentView,它是当我的设备处于纵向和反之亦然时我将显示的视图。

And then handle the runtime change of the orientation as follows:然后按如下方式处理方向的运行时变化:

private void Current_MainDisplayInfoChanged(object sender, DisplayInfoChangedEventArgs e)
{
        if(e.DisplayInfo.Orientation==DisplayOrientation.Landscape)
        {
            if(this.Content.GetType() is not typeof(LandscapeView))
            {
                this.Content = landscapeView;
            }
        }
        else if (e.DisplayInfo.Orientation == DisplayOrientation.Portrait)
        {
            if (this.Content.GetType() is not typeof(PortraitView))
            {
                this.Content = portraitView;
            }
        }
        else
        {
            //Whatever you would like to do if the orientation is unknown.
        }
}

Hope this helps you!希望这对你有帮助!

The proper way to do this is through ContentViews where you have 2 ContentViews, one for portrait and one for landscape.执行此操作的正确方法是通过 ContentViews,其中您有 2 个 ContentView,一个用于纵向,一个用于横向。 You have another ContentView that is used to choose to load in either landscape or portrait depending on the orientation.您有另一个 ContentView,用于根据方向选择横向或纵向加载。 I created a tutorial that puts all of the pieces together: https://codeshadowhand.com.net-maui-different-layouts-for-portrait-vs-landscape/ Thanks a million to FreakyAli for pointing me in the right direction!!!我创建了一个教程,将所有部分放在一起: https://codeshadowhand.com.net-maui-different-layouts-for-portrait-vs-landscape/ 非常感谢 FreakyAli 为我指明了正确的方向!! !

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM