Skip to content

Commit

Permalink
feat: Responsive markup extension (#926)
Browse files Browse the repository at this point in the history
Co-authored-by: eriklimakc <[email protected]>
Co-authored-by: Steve Bilogan <[email protected]>
  • Loading branch information
3 people authored Dec 5, 2023
1 parent 838a07a commit 747e368
Show file tree
Hide file tree
Showing 9 changed files with 578 additions and 7 deletions.
110 changes: 110 additions & 0 deletions doc/helpers/responsive-extension.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
---
uid: Toolkit.Helpers.ResponsiveExtension
---
# ResponsiveExtension

## Summary
The `ResponsiveExtension` class is a markup extension that enables the customization of `UIElement` properties based on screen size.
This functionality provides a dynamic and responsive user interface experience.

### Inheritance
Object &#8594; MarkupExtension &#8594; ResponsiveExtension

### Constructors
| Constructor | Description |
|-----------------------|----------------------------------------------------------------|
| ResponsiveExtension() | Initializes a new instance of the `ResponsiveExtension` class. |

## Properties
| Property | Type | Description |
| ---------- | ---------------- | ---------------------------------------------------------- |
| Narrowest | object | Value to be used when the screen size is at its narrowest. |
| Narrow | object | Value to be used when the screen size is narrow. |
| Normal | object | Value to be used when the screen size is normal. |
| Wide | object | Value to be used when the screen size is wide. |
| Widest | object | Value to be used when the screen size is at its widest. |
| Layout | ResponsiveLayout | Overrides the screen size thresholds/breakpoints. |

### ResponsiveLayout
Provides the ability to override the default breakpoints (i.e., the window widths at which the value changes) for the screen sizes.
This is done using an instance of the `ResponsiveLayout` class.

#### Properties
| Property | Type | Description |
| ---------- | ---------------- | ---------------------- |
| Narrowest | double | Default value is 150. |
| Narrow | double | Default value is 300. |
| Normal | double | Default value is 600. |
| Wide | double | Default value is 800. |
| Widest | double | Default value is 1080. |

## Remarks
**Platform limitation**: The ability to update property values when the window size changes is only available on targets other than Windows UWP.
Due to a limitation of the UWP API (Windows target only), the `MarkupExtension.ProvideValue(IXamlServiceProvider)` overload is unavailable, which is required to continuously update the value.
Because of this, the markup extension will only provide the initial value, and will not respond to window size changes.

**Initialization**: The `ResponsiveHelper` needs to be hooked up to the window's `SizeChanged` event in order for it to receive updates when the window size changes.
This is typically done in the `OnLaunched` method in the `App` class, where you can get the current window and call the `HookupEvent` method on the `ResponsiveHelper`.
It is important to do this when the app launches, otherwise the `ResponsiveExtension` won't be able to update the property values when the window size changes.

Here is an example of how this might be achieved:

```cs
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
#if NET6_0_OR_GREATER && WINDOWS && !HAS_UNO
MainWindow = new Window();
#else
MainWindow = Microsoft.UI.Xaml.Window.Current;
#endif
// ...
var helper = Uno.Toolkit.UI.ResponsiveHelper.GetForCurrentView();
helper.HookupEvent(MainWindow);
}
```

**Property type limitation**: Content property values other than strings must be appropriately typed for the markup extension to interpret them correctly.
In the basic usage example below, the values `NarrowRed` and `WideBlue` are properly typed as they refer to the `StaticResource` keys defined in `Page.Resources`.
For instance, using `Background={utu:Responsive Narrow=SkyBlue, Wide=Pink}` would be incorrect, while the string literal usage under `<TextBlock Text="{utu:Responsive Narrow='Narrow format', Wide='Wide format'}" />` is accepted.

## Usage

### Basic example
```xml
xmlns:utu="using:Uno.Toolkit.UI"
...
<Page.Resources>
<SolidColorBrush x:Key="NarrowRed">Crimson</SolidColorBrush>
<SolidColorBrush x:Key="WideBlue">Blue</SolidColorBrush>
</Page.Resources>
...
<TextBlock Text="Asd"
Background="{utu:Responsive Narrow={StaticResource NarrowRed}, Wide={StaticResource WideBlue}}" />
```

### Custom thresholds
```xml
xmlns:utu="using:Uno.Toolkit.UI"
xmlns:hlp="using:Uno.Toolkit.UI.Helpers"
...
<Page.Resources>
<hlp:ResponsiveLayout x:Key="CustomLayout"
Narrowest="200"
Narrow="350"
Normal="800"
Wide="1200"
Widest="1500" />
</Page.Resources>
...
<TextBlock>
<TextBlock.Text>
<utu:ResponsiveExtension Layout="{StaticResource CustomLayout}"
Narrowest="This is the narrowest screen size."
Narrow="This is a narrow screen size."
Normal="This is a normal screen size."
Wide="This is a wide screen size."
Widest="This is the widest screen size." />
</TextBlock.Text>
</TextBlock>
```

3 changes: 3 additions & 0 deletions doc/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@
href: helpers/input-extensions.md
- name: ItemsRepeater Extensions
href: helpers/itemsrepeater-extensions.md
- name: Responsive markup extension
href: helpers/responsive-extension.md
- name: StatusBar attached properties
- name: Resource Extensions
href: helpers/resource-extensions.md
- name: Selector Extensions
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<Page x:Class="Uno.Toolkit.Samples.Content.Helpers.ResponsiveExtensionsSamplePage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:sample="using:Uno.Toolkit.Samples"
xmlns:utu="using:Uno.Toolkit.UI"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Page.Resources>
<Orientation x:Key="NarrowOrientation">Vertical</Orientation>
<Orientation x:Key="WideOrientation">Horizontal</Orientation>
<x:Double x:Key="NarrowFontSize">15</x:Double>
<x:Double x:Key="WideFontSize">25</x:Double>
<SolidColorBrush x:Key="NarrowRed">Crimson</SolidColorBrush>
<SolidColorBrush x:Key="WideBlue">Blue</SolidColorBrush>
<utu:ResponsiveLayout x:Key="CustomLayout"
Narrowest="200"
Narrow="350"
Normal="800"
Wide="1200"
Widest="1500" />
</Page.Resources>

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<sample:SamplePageLayout IsDesignAgnostic="True">
<sample:SamplePageLayout.DesignAgnosticTemplate>
<DataTemplate>
<StackPanel Spacing="20">
<TextBlock Text="Orientation test | Normal=Vertical | Wide=Horizontal"
FontWeight="Bold" />
<StackPanel Orientation="{utu:Responsive Normal={StaticResource NarrowOrientation}, Wide={StaticResource WideOrientation}}">
<TextBlock Text="A" />
<TextBlock Text="B" />
<TextBlock Text="C" />
</StackPanel>

<TextBlock Text="Text test"
FontWeight="Bold" />
<TextBlock Text="{utu:Responsive Narrow='Narrow Threshold 300', Normal='Normal Threshold 600', Wide='Wide Threshold 800'}" />

<TextBlock Text="FontSize test"
FontWeight="Bold" />
<TextBlock Text="Normal 15 Wide 25"
FontSize="{utu:Responsive Normal={StaticResource NarrowFontSize},
Wide={StaticResource WideFontSize}}" />

<TextBlock Text="Color test | Normal Red | Wide Blue"
FontWeight="Bold" />
<Border Width="30"
Height="30"
HorizontalAlignment="Left"
Background="{utu:Responsive Normal={StaticResource NarrowRed},
Wide={StaticResource WideBlue}}" />

<TextBlock Text="Custom values override"
FontWeight="Bold" />
<TextBlock>
<TextBlock.Text>
<utu:ResponsiveExtension Layout="{StaticResource CustomLayout}"
Narrowest="This is the narrowest screen size."
Narrow="This is a narrow screen size."
Normal="This is a normal screen size."
Wide="This is a wide screen size."
Widest="This is the widest screen size." />
</TextBlock.Text>
</TextBlock>
</StackPanel>
</DataTemplate>
</sample:SamplePageLayout.DesignAgnosticTemplate>
</sample:SamplePageLayout>
</Grid>
</Page>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using Uno.Toolkit.Samples.Entities;

#if IS_WINUI
using Microsoft.UI.Xaml.Controls;
#else
using Windows.UI.Xaml.Controls;
#endif

namespace Uno.Toolkit.Samples.Content.Helpers;

[SamplePage(SampleCategory.Helpers, "Responsive Extensions", SourceSdk.UnoToolkit)]
public sealed partial class ResponsiveExtensionsSamplePage : Page
{
public ResponsiveExtensionsSamplePage()
{
this.InitializeComponent();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@
<Compile Include="$(MSBuildThisFileDirectory)Content\Helpers\BindingExtensionsSamplePage.xaml.cs">
<DependentUpon>BindingExtensionsSamplePage.xaml</DependentUpon>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)Content\Helpers\ResponsiveExtensionsSamplePage.xaml.cs">
<DependentUpon>ResponsiveExtensionsSamplePage.xaml</DependentUpon>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)Content\NestedSamples\FluentNavigationBarSampleNestedPage1.xaml.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Content\NestedSamples\FluentNavigationBarSampleNestedPage2.xaml.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Content\NestedSamples\M3MaterialBottomBarSampleNestedPage.xaml.cs">
Expand Down Expand Up @@ -296,6 +299,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="$(MSBuildThisFileDirectory)Content\Helpers\ResponsiveExtensionsSamplePage.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="$(MSBuildThisFileDirectory)Content\NestedSamples\FluentNavigationBarSampleNestedPage1.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
Expand Down
Loading

0 comments on commit 747e368

Please sign in to comment.