Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

responsive enhancements #944

Merged
merged 8 commits into from
Dec 6, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 20 additions & 44 deletions doc/controls/ResponsiveView.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,14 @@ uid: Toolkit.Controls.ResponsiveView
---
# ResponsiveView

## Summary

The `ResponsiveView` provides the ability to display different content based on screen size, making it easy to adapt to various devices.

## Remarks

The ResponsiveView Control adapts to different screen sizes by dynamically choosing the right template. It looks at the current screen width and the defined templates. Since not all templates need a value, the control ensures a smooth user experience by picking the smallest defined template that satisfies the width requirements. If no match is found, it defaults to the largest defined template.
The `ResponsiveView` control adapts to different screen sizes by dynamically choosing the right template. It looks at the current screen width and the defined templates. Since not all templates need a value, the control ensures a smooth user experience by picking the smallest defined template that satisfies the width requirements. If no match is found, it defaults to the largest defined template.

**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`.

Here is an example of how this might be achieved:

**Initialization**: The `ResponsiveHelper` needs to be hooked up to the window's `SizeChanged` event in order for this control 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` instance for `ResponsiveHelper.HookupEvent`:
```cs
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
Expand All @@ -24,13 +19,14 @@ protected override void OnLaunched(LaunchActivatedEventArgs args)
#else
MainWindow = Microsoft.UI.Xaml.Window.Current;
#endif

// ...
var helper = Uno.Toolkit.UI.ResponsiveHelper.GetForCurrentView();
helper.HookupEvent(MainWindow);
}
```

## Inheritance
## Inheritance
Object → DependencyObject → UIElement → FrameworkElement → Control → ContentControl

## Properties
Expand All @@ -44,7 +40,7 @@ Object → DependencyObject → UIElement → FrameworkElement &#859
| ResponsiveLayout | ResponsiveLayout | Overrides the screen size threshold/breakpoints. |

### ResponsiveLayout
Provides the ability to override the MaxWidth for each screen size: `Narrowest`, `Narrow`, `Normal`, `Wide`, and `Widest`.
Provides the ability to override the breakpoint for each screen size: `Narrowest`, `Narrow`, `Normal`, `Wide`, and `Widest`.

### Properties
| Property | Type | Description |
Expand All @@ -57,35 +53,25 @@ Provides the ability to override the MaxWidth for each screen size: `Narrowest`,

## Usage

> [!TIP]
> It is not necessary to define every template or layout breakpoints: Narrowest,Narrow,Normal,Wide,Widest. You can just define the bare minimum needed.
Xiaoy312 marked this conversation as resolved.
Show resolved Hide resolved

```xml
xmlns:utu="using:Uno.Toolkit.UI"
...

<utu:ResponsiveView>
<utu:ResponsiveView.NarrowestTemplate>
<DataTemplate>
<!-- Narrowest content -->
</DataTemplate>
</utu:ResponsiveView.NarrowestTemplate>
<!-- note: -->
<utu:ResponsiveView.NarrowTemplate>
<DataTemplate>
<!-- Narrow content -->
</DataTemplate>
</utu:ResponsiveView.NarrowTemplate>
<utu:ResponsiveView.NormalTemplate>
<DataTemplate>
<!-- Normal content -->
</DataTemplate>
</utu:ResponsiveView.NormalTemplate>
<utu:ResponsiveView.WideTemplate>
<DataTemplate>
<!-- Wide content -->
</DataTemplate>
</utu:ResponsiveView.WideTemplate>
<utu:ResponsiveView.WidestTemplate>
<DataTemplate>
<!-- Widest content -->
</DataTemplate>
</utu:ResponsiveView.WidestTemplate>
</utu:ResponsiveView>
```

Expand All @@ -97,37 +83,27 @@ xmlns:utu="using:Uno.Toolkit.UI"
<utu:ResponsiveView>
<utu:ResponsiveView.ResponsiveLayout>
<utu:ResponsiveLayout>
<utu:ResponsiveLayout.Narrowest>200</utu:ResponsiveLayout.Narrowest>
<utu:ResponsiveLayout.Narrow>350</utu:ResponsiveLayout.Narrow>
<utu:ResponsiveLayout.Normal>800</utu:ResponsiveLayout.Normal>
<utu:ResponsiveLayout.Wide>1200</utu:ResponsiveLayout.Wide>
<utu:ResponsiveLayout.Widest>1500</utu:ResponsiveLayout.Widest>
</utu:ResponsiveLayout>
</utu:ResponsiveView.ResponsiveLayout>
<utu:ResponsiveView.NarrowestTemplate>
<DataTemplate>
<!-- Narrowest content -->
</DataTemplate>
</utu:ResponsiveView.NarrowestTemplate>

<utu:ResponsiveView.NarrowTemplate>
<DataTemplate>
<!-- Narrow content -->
</DataTemplate>
</utu:ResponsiveView.NarrowTemplate>
<utu:ResponsiveView.NormalTemplate>
<DataTemplate>
<!-- Normal content -->
</DataTemplate>
</utu:ResponsiveView.NormalTemplate>
<utu:ResponsiveView.WideTemplate>
<DataTemplate>
<!-- Wide content -->
</DataTemplate>
</utu:ResponsiveView.WideTemplate>
<utu:ResponsiveView.WidestTemplate>
<DataTemplate>
<!-- Widest content -->
</DataTemplate>
</utu:ResponsiveView.WidestTemplate>
</utu:ResponsiveView>
```
```

> [!NOTE]
Xiaoy312 marked this conversation as resolved.
Show resolved Hide resolved
> This `ResponsiveLayout` can also be provided from different locations. In the order of precedences, they are:
> - from the `.ResponsiveLayout` property
> - in `ResponsiveView`'s parent `.Resources` with `x:Key="DefaultResponsiveLayout"`, or its ancestor's...
> - in `Application.Resources` with `x:Key="DefaultResponsiveLayout"`
Xiaoy312 marked this conversation as resolved.
Show resolved Hide resolved
> - from the hardcoded `ResponsiveHelper.Layout`
79 changes: 34 additions & 45 deletions doc/helpers/responsive-extension.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,12 @@ 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 |
| ---------- | ---------------- | ---------------------------------------------------------- |
Expand All @@ -39,16 +33,8 @@ This is done using an instance of the `ResponsiveLayout` class.
| 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:

**Initialization**: The `ResponsiveHelper` needs to be hooked up to the window's `SizeChanged` event in order for this markup 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` instance for `ResponsiveHelper.HookupEvent`:
```cs
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
Expand All @@ -57,54 +43,57 @@ protected override void OnLaunched(LaunchActivatedEventArgs args)
#else
MainWindow = Microsoft.UI.Xaml.Window.Current;
#endif

// ...
var helper = Uno.Toolkit.UI.ResponsiveHelper.GetForCurrentView();
helper.HookupEvent(MainWindow);
}
```
## Platform limitation (UWP-desktop)
`ResponsiveExtension` relies on `MarkupExtension.ProvideValue(IXamlServiceProvider)` to find the target control and property for continuous update of value, and to obtain the property type to apply automatic type conversion as its value properties are parsed as string by the xaml engine. Because this overload is a new addition to WinUI only, UWP project targeting windows will not have access to these features. Uno UWP project against non-windows targets do not have this limitation. However, the windows app may crash or misbehave if you attempt to use this markup on non-string property.
Xiaoy312 marked this conversation as resolved.
Show resolved Hide resolved
```xml
<Border Background="{utu:Responsive Narrow=Red, Wide=Blue}"
Tag="This will not work on Uwp for windows" />
```
You can workaround this, by declaring the values are resources and use `{StaticResource}` to refer to them:
Xiaoy312 marked this conversation as resolved.
Show resolved Hide resolved
```xml
<Page.Resources>
<SolidColorBrush x:Key="RedBrush">Red</SolidColorBrush>
<SolidColorBrush x:Key="BlueBrush">Blue</SolidColorBrush>
...

**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.

<Border Background="{utu:Responsive Narrow={StaticResource RedBrush},
Wide={StaticResource BlueBrush}}" />
```
## Usage

### Basic example
> [!TIP]
> It is not necessary to define every template or layout breakpoints: Narrowest,Narrow,Normal,Wide,Widest. You can just define the bare minimum needed.
Xiaoy312 marked this conversation as resolved.
Show resolved Hide resolved

```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}}" />

<TextBlock Background="{utu:Responsive Narrow=Red, Wide=Blue}" Text="Asd" />
```

### 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" />
<utu:ResponsiveLayout x:Key="CustomLayout" Narrow="400" Wide="800" />
</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>

<TextBlock Text="{utu:Responsive Layout={StaticResource CustomLayout}, Narrow=Narrow, Wide=Wide}" />
```

> [!NOTE]
> This `ResponsiveLayout` can also be provided from different locations. In the order of precedences, they are:
> - from the `Layout` property
> - in the property owner's parent `.Resources` with `x:Key="DefaultResponsiveLayout"`, or the property owner's parent's parent's...
> - in `Application.Resources` with `x:Key="DefaultResponsiveLayout"`
> - from the hardcoded `ResponsiveHelper.Layout`

Loading
Loading