12+ Jahre App-Entwicklung
Alles aus einer Hand
50+ Erfolgreiche App-Projekte

Blog

Responsive Layouts in .NET MAUI

.NET MAUI ermöglicht es uns, plattform- und geräteunabhängige Anwendungen zu schreiben, was eine dynamische Anpassung an die Bildschirmgröße und -form des Benutzers erforderlich macht. In diesem Blog-Beitrag erfahren Sie, wie Sie Ihre XAML-Layouts an unterschiedliche Geräteausrichtungen anpassen können. Dabei verwenden Sie eine ähnliche Syntax wie OnIdiom und OnPlatform, die Ihnen vielleicht schon bekannt ist.

Artikelbild für Responsive Layouts in .NET MAUI

This post is part of the MAUI UI July 2023 community series of blog posts and videos, hosted by Matt Goldman. Be sure to check out the other posts in this series!

Let's have a look at how we can use the MarkupExtension OnOrientation:

Why make .NET MAUI apps responsive?

Layouts of mobile apps should be responsive and adapt to various screen sizes and different orientations, to provide an engaging user experience. While we are accustomed to using devices in portrait orientation where there is more vertical screen space than horizontal, there are still cases where it makes sense to switch to landscape orientation, even on phones.

Making a .NET MAUI app switch between Portrait and Landscape seamlessly can be a challenge. The first step in the right direction can be to avoid fixed sizes where possible and let the controls scale automatically. However, oftentimes the app ends up with lots of blank space in either of the orientations, as you can see in the example below.

By providing different values to properties of layouts like ColumnDefinitions from Grid we can make better use of the additional horizontal screen space.

This can easily be done by using a custom MarkupExtension so that it can be used directly in XAML like this:

<Grid ColumnDefinitions="{OnOrientation Default='*', Landscape='*,*', TypeConverter={x:Type ColumnDefinitionCollectionTypeConverter}}">

Why TypeConverter is specified here will be explained below.

If you have a project in Xamarin or .NET MAUI, we can help you save time.

Before proceeding on your own, take a look at our services. Our team of experienced developers is enthusiastic about discussing your project and helping you finish with an excellent standard.

Have a look at app development services

How the OnOrientation MarkupExtension works

In contrast to other MarkupExtensions like OnPlatform and OnIdiom, where the factor deciding which value to use is determined at startup, OnOrientation works differently, since the orientation changes at runtime. That means OnOrientation needs to provide a value that changes at runtime. This can be achieved by returning a Binding in ProvideValue(IServiceProvider serviceProvider), with a Source that implements INotifyPropertyChanged, in this case an object of OnOrientationSource. OnOrientationExtension uses the DeviceDisplay.MainDisplayInfoChanged event to publish a message via the WeakReferenceMessenger.

OnOrientationSource provides the current value via the Value property. It's getter evaluates the current orientation and returns the appropriate value. When the orientation changes, it receives the OrientationChangedMessage and fires the PropertyChanged event for Value resulting in an update in the view.

You may have noticed that OnOrientationExtension also defines the property TypeConverter. Unfortunately, when using a MarkupExtension the TypeConverter mechanism does not kick in, normally resulting in a type mismatch. That's why TypeConverter can be used to specify which kind of TypeConverter to use for converting the string value from the OnOrientation expression, providing a simple workaround to that limitation. To find out which TypeConverter should be applied developers can check out the TypeConverterAttribute the BindableProperty is annotated with as in this example.

Using OnOrientation

  1. Install CommunityToolkit.Maui into the project
  2. Add UseMauiCommunityToolkit() to MauiProgram.cs when configuring the MauiAppBuilder
  3. Add both classes, OnOrientationExtension.cs and OnOrientationSource.cs, to the .NET MAUI project
  4. Add the namespace alias to the XAML file
  5. Use OnOrientation either inline as MarkupExtension in attribute syntax, or via property element syntax

Make sure to always specify a value for Default.

Inline in attribute syntax

Primitive values can simply be used like this:

<Label Grid.Row="{OnOrientation Default=0, Landscape=1}" />

Since the values you provide in a MarkupExtension must be of a primitive type like int or string, and type conversion using TypeConverters does not kick in, sometimes you may need to use x:Static to refer to static variables or Enum values.

<Label HorizontalOptions="{OnOrientation Default={x:Static LayoutOptions.Start}, Landscape={x:Static LayoutOptions.Center}}" />

Converting a complex value from string can be achieved by specifying a TypeConverter:

<Grid ColumnDefinitions="{OnOrientation Default='*', Landscape='*,*', TypeConverter={x:Type ColumnDefinitionCollectionTypeConverter}}">

Property Element Syntax

When a complex value is needed and no matching TypeConverter exists, then you can also use property element syntax to specify the different values. Although one can argue that this is way too verbose for practical use.

<Grid.ColumnDefinitions>
    <ext:OnOrientation>
        <ext:OnOrientation.Default>
            <ColumnDefinitionCollection>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="0" />
            </ColumnDefinitionCollection>
        </ext:OnOrientation.Default>
        <ext:OnOrientation.Landscape>
            <ColumnDefinitionCollection>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
            </ColumnDefinitionCollection>
        </ext:OnOrientation.Landscape>
    </ext:OnOrientation>
</Grid.ColumnDefinitions>

However, this syntax could also be used to switch out entire views:

<ContentView>
    <ContentView.Content>
        <ext:OnOrientation>
            <Label Text="This text is visible in Default" />
            <ext:OnOrientation.Landscape>
                <Label Text="This text is visible in Landscape" />
            </ext:OnOrientation.Landscape>
        </ext:OnOrientation>
    </ContentView.Content>
</ContentView>

Gained some interest in our work?

We assume that you have gained some interest in our work since you have made it this far. Please feel free to give us your feedback or discuss a project of yours. We would be pleased to hear from you.

Let's talk

Limitations

OnOrientation is based on the orientation provided by DeviceDisplay.MainDisplayInfo.Orientation, therefore it does not work properly on desktop platforms. Also, a Binding expression can not be used as one of the values.

Conclusion: Adapting layouts in .NET MAUI for device orientation

Adapting the layout with OnOrientationExtension can be quite comfortable and flexible. But keep in mind that there are other ways to handle orientation changes too, so make sure to check out these articles:

Feel free to check out the OnOrientationExtension branch in the PokeApp-Maui repository where you can see this in action. You can also click here for the Gist of it and leave some feedback or other comments.

Flavio Goncalves

Flavio Goncalves

As Head of Technology, I support my team and our clients with the latest technologies and trends in Android and iOS development. Our projects benefit from my Xamarin and .NET MAUI experience, as well as my penchant for clean code, attractive UIs and intuitive UX. You are welcome to book me for a workshop.

Verwandte Artikel

LiveCharts2: Die moderne .NET MAUI Charts-Alternative zu Microcharts
LiveCharts2: Die moderne .NET MAUI Charts-Alternative zu Microcharts

Suchst du nach einer leistungsstarken Bibliothek für Charts in .NET MAUI? Viele Entwickler greifen zunächst zu Microcharts, stellen aber schnell fest, dass die Bibliothek nicht mehr aktiv gepflegt wird und unter .NET 8 Probleme bereitet. Die Lösung ist LiveCharts2: eine moderne, performante und aktiv gewartete Microcharts Alternative, die deine Datenvisualisierung auf das nächste Level hebt.

Erstellen eines .NET MAUI Karten-Steuerelements
Erstellen eines .NET MAUI Karten-Steuerelements

Ich arbeite derzeit an der Portierung einer Xamarin Forms App zu .NET MAUI. Die App verwendet auch Karten von Apple oder Google Maps, um Standorte anzuzeigen. Obwohl es bis zur Veröffentlichung von .NET 7 keine offizielle Unterstützung in MAUI gab, möchte ich Ihnen eine Möglichkeit zeigen, Karten über einen benutzerdefinierten Handler anzuzeigen.

Using voice commands in .NET MAUI
Using voice commands in .NET MAUI

This post is a continuation of the Hackathon topic post, where the technical implementation of voice commands in .NET MAUI is revealed, as well as the challenges the development team faced and how they successfully solved them.