Skip to content

Commit

Permalink
Merge pull request #906 from unoplatform/dev/xygu/20231103/drawer-fly…
Browse files Browse the repository at this point in the history
…out-depth
  • Loading branch information
Xiaoy312 authored Nov 21, 2023
2 parents 9314b92 + 2383a03 commit 5850dc6
Show file tree
Hide file tree
Showing 9 changed files with 685 additions and 119 deletions.
97 changes: 89 additions & 8 deletions doc/controls/DrawerFlyoutPresenter.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,30 +15,77 @@ xmlns:utu="using:Uno.Toolkit.UI"
BasedOn="{StaticResource DrawerFlyoutPresenterStyle}"
TargetType="FlyoutPresenter">
<Setter Property="utu:DrawerFlyoutPresenter.OpenDirection" Value="Top" />
<Setter Property="utu:DrawerFlyoutPresenter.DrawerLength" Value="0.66*" />
<Setter Property="utu:DrawerFlyoutPresenter.LightDismissOverlayBackground" Value="#80808080" />
<Setter Property="utu:DrawerFlyoutPresenter.IsGestureEnabled" Value="True" />
</Style>
<!-- and/or -->
<utu:DrawerFlyoutPresenter OpenDirection="Top"
DrawerLength="0.66*"
LightDismissOverlayBackground="#80808080"
IsGestureEnabled="True" />
```

> [!IMPORTANT]
> There is currently a bug on windows that prevents the usage of attached property style setters. The workaround is to add the following code in your application:
```xml
<!--
microsoft/microsoft-ui-xaml#6388 (winui, and on windows only):
If you define attached property setter on a style with BasedOn another style with Template defined from a separate class library
it will throw when the template is materialized:
> Failed to assign to property 'Uno.Toolkit.UI.DrawerFlyoutPresenter.OpenDirection'.
^ It will mention the first attached property used in the template, regardless of which attached property setter that triggered it.
The workaround here is to define the template in the consuming assembly again.
It doesn't matter if it is used or not.
-->
<win:Style x:Key="MUX6388_Workaround_ForDefinitionOnly" TargetType="FlyoutPresenter">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="FlyoutPresenter">
<!-- This is not the full template, we are just making explicit reference to these definitions below -->
<utu:DrawerFlyoutPresenter OpenDirection="{TemplateBinding utu:DrawerFlyoutPresenter.OpenDirection}"
DrawerLength="{TemplateBinding utu:DrawerFlyoutPresenter.DrawerLength}"
LightDismissOverlayBackground="{TemplateBinding utu:DrawerFlyoutPresenter.LightDismissOverlayBackground}"
IsGestureEnabled="{TemplateBinding utu:DrawerFlyoutPresenter.IsGestureEnabled}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</win:Style>
```

### Properties
Property|Type|Description
-|-|-
OpenDirection|DrawerOpenDirection|Gets or sets the direction in which the drawer opens toward.<br/>note: The position of drawer when opened is the opposite of this value.
OpenDirection|DrawerOpenDirection=`Up`|Gets or sets the direction in which the drawer opens toward.<br/>note: The position of drawer when opened is the opposite of this value.
DrawerLength|GridLength=`0.66*`|Get or sets the length (width or height depending on the `OpenDirection`) of the drawer.\*
LightDismissOverlayBackground|Brush|Gets or sets the brush used to paint the light dismiss overlay. The default value is `#80808080` (from the default style).
IsGestureEnabled|bool|Get or sets a value that indicates whether the user can interact with the control using gesture. The default value is `true`.
IsGestureEnabled|bool=`true`|Get or sets a value that indicates whether the user can interact with the control using gesture.

## Usage
notes:
- For DrawerLength, this value has 3 mode based on `GridUnitType`:
```xml
<Style TargetType="FlyoutPresenter">
<Setter Property="utu:DrawerFlyoutPresenter.DrawerLength" Value="Auto" />
<Setter Property="utu:DrawerFlyoutPresenter.DrawerLength" Value="0.66*" />
<Setter Property="utu:DrawerFlyoutPresenter.DrawerLength" Value="150" />
<!-- and/or -->
<DrawerFlyoutPresenter DrawerLength="Auto" />
<DrawerFlyoutPresenter DrawerLength="0.66*" />
<DrawerFlyoutPresenter DrawerLength="150" />
```
- `GridUnitType.Auto`: Fit to flyout content.
- `GridUnitType.Star`: At given ratio of screen/flyout width or height. Valid range is between 0* and 1*, excluding 0* itself.
- `GridUnitType.Pixel`: Fixed at the given value.

## Usage
To use this, simply use a `Flyout` with `Placement="Full"` and one of the followings as the `FlyoutPresenterStyle`:
> note: The direction here indicates the initial position of the drawer. The open direction is the opposite.
- `LeftDrawerFlyoutPresenterStyle`
- `TopDrawerFlyoutPresenterStyle`
- `RightDrawerFlyoutPresenterStyle`
- `BottomDrawerFlyoutPresenterStyle`
> note: The name prefix here indicates the initial position of the drawer (where it opens from). The open animation direction (`OpenDirection`) is the opposite.
- `LeftDrawerFlyoutPresenterStyle` (OpenDirection=Right)
- `TopDrawerFlyoutPresenterStyle` (OpenDirection=Down)
- `RightDrawerFlyoutPresenterStyle` (OpenDirection=Left)
- `BottomDrawerFlyoutPresenterStyle` (OpenDirection=Up)

Example:
```xml
Expand All @@ -57,3 +104,37 @@ Example:
</Button>
```
> note: Here `VisibleBoundsPadding.PaddingMask` is used to prevent the content from being placed outside of the user-interactable area on mobile devices.
### Extended Use Cases
- Rounded Corner
```xml
<Flyout Placement="Full">
<Flyout.FlyoutPresenterStyle>
<Style BasedOn="{StaticResource BottomDrawerFlyoutPresenterStyle}" TargetType="FlyoutPresenter">
<Setter Property="CornerRadius" Value="16,16,0,0" />
</Style>
</Flyout.FlyoutPresenterStyle>
<Border toolkit:VisibleBoundsPadding.PaddingMask="All" Padding="16,16,0,0">
<!-- flyout content -->
</Border>
</Flyout>
```
> remarks: `Padding` is used on the flyout content to avoid content being clipped.
- Custom background
```xml
<Flyout Placement="Full">
<Flyout.FlyoutPresenterStyle>
<Style BasedOn="{StaticResource BottomDrawerFlyoutPresenterStyle}" TargetType="FlyoutPresenter">
<Setter Property="Background" Value="SkyBlue" />
</Style>
</Flyout.FlyoutPresenterStyle>
<Border toolkit:VisibleBoundsPadding.PaddingMask="All" >
<!-- flyout content -->
</Border>
</Flyout>
```
> remarks: Avoid setting `Background` directly on the flyout content:
> ```xml
> <Border toolkit:VisibleBoundsPadding.PaddingMask="All" Background="SkyBlue">
> ```
> Instead, `Background` should be set from style setter to avoid edge bleeding on certain platforms, and to avoid default background being painted on the rounded corners.
Original file line number Diff line number Diff line change
Expand Up @@ -7,42 +7,59 @@
xmlns:toolkit="using:Uno.UI.Toolkit"
xmlns:sample="using:Uno.Toolkit.Samples"
xmlns:utu="using:Uno.Toolkit.UI"
mc:Ignorable="d"
xmlns:todo="what should be done"
xmlns:win="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
mc:Ignorable="d todo"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Page.Resources>
<!--
microsoft/microsoft-ui-xaml/issues/6388 (winui, and on windows only):
If you define attached property setter on a style with BasedOn another style with Template defined from a separate class library
it will throw when the template is materialized:
> Failed to assign to property 'Uno.Toolkit.UI.DrawerFlyoutPresenter.OpenDirection'.
^ It will mention the first attached property used in the template, regardless of which attached property setter that triggered it.
The workaround here is to define the template in the consuming assembly again.
It doesn't matter if it is used or not.
-->
<win:Style x:Key="MUX6388_Workaround_ForDefinitionOnly" TargetType="FlyoutPresenter">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="FlyoutPresenter">
<utu:DrawerFlyoutPresenter todo:Note="This is not the full template, we are just making explicit reference to these definitions below"
OpenDirection="{TemplateBinding utu:DrawerFlyoutPresenter.OpenDirection}"
DrawerLength="{TemplateBinding utu:DrawerFlyoutPresenter.DrawerLength}"
LightDismissOverlayBackground="{TemplateBinding utu:DrawerFlyoutPresenter.LightDismissOverlayBackground}"
IsGestureEnabled="{TemplateBinding utu:DrawerFlyoutPresenter.IsGestureEnabled}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</win:Style>
</Page.Resources>

<Grid Background="{ThemeResource SurfaceBrush}">
<sample:SamplePageLayout x:Name="SamplePageLayout" IsDesignAgnostic="True">
<sample:SamplePageLayout.DesignAgnosticTemplate>
<DataTemplate>
<ScrollViewer HorizontalScrollMode="Disabled">
<StackPanel>
<TextBlock Text="Use a DrawerFlyoutPresenter to display flyout with gesture support."
Style="{StaticResource BodyTextBlockStyle}" />

<TextBlock Text="Use a DrawerFlyoutPresenter to display flyout with gesture support." Style="{StaticResource BodyTextBlockStyle}" />

<!-- basic usage -->
<TextBlock Text="DrawerFlyoutPresenter"
Margin="0,24,0,0"
Style="{StaticResource TitleTextBlockStyle}" />
<TextBlock Text="note: To use this, simply use a Placement=Full flyout with one of the followings as FlyoutPresenterStyle:"
Style="{StaticResource BodyTextBlockStyle}" />
<TextBlock Text="- LeftDrawerFlyoutPresenterStyle"
Style="{StaticResource BodyTextBlockStyle}" />
<TextBlock Text="- TopDrawerFlyoutPresenterStyle"
Style="{StaticResource BodyTextBlockStyle}" />
<TextBlock Text="- RightDrawerFlyoutPresenterStyle"
Style="{StaticResource BodyTextBlockStyle}" />
<TextBlock Text="- BottomDrawerFlyoutPresenterStyle"
Style="{StaticResource BodyTextBlockStyle}" />

<StackPanel Spacing="8"
Margin="0,24,0,0">
<TextBlock Text="note: To use this, simply use a Placement=Full flyout with one of the followings as FlyoutPresenterStyle:" Style="{StaticResource BodyTextBlockStyle}" />
<TextBlock Text="- LeftDrawerFlyoutPresenterStyle" Style="{StaticResource BodyTextBlockStyle}" />
<TextBlock Text="- TopDrawerFlyoutPresenterStyle" Style="{StaticResource BodyTextBlockStyle}" />
<TextBlock Text="- RightDrawerFlyoutPresenterStyle" Style="{StaticResource BodyTextBlockStyle}" />
<TextBlock Text="- BottomDrawerFlyoutPresenterStyle" Style="{StaticResource BodyTextBlockStyle}" />
<StackPanel Spacing="8" Margin="0,24,0,0">
<Button Content="Left Drawer">
<Button.Flyout>
<Flyout Placement="Full"
FlyoutPresenterStyle="{StaticResource LeftDrawerFlyoutPresenterStyle}">
<StackPanel toolkit:VisibleBoundsPadding.PaddingMask="All"
Background="{ThemeResource SurfaceBrush}"
MinWidth="200">
<Flyout Placement="Full" FlyoutPresenterStyle="{StaticResource LeftDrawerFlyoutPresenterStyle}">
<StackPanel toolkit:VisibleBoundsPadding.PaddingMask="All" Background="{ThemeResource SurfaceBrush}">
<TextBlock Text="text" />
<Button Content="button" />
</StackPanel>
Expand All @@ -51,11 +68,8 @@
</Button>
<Button Content="Top Drawer">
<Button.Flyout>
<Flyout Placement="Full"
FlyoutPresenterStyle="{StaticResource TopDrawerFlyoutPresenterStyle}">
<StackPanel toolkit:VisibleBoundsPadding.PaddingMask="All"
Background="{ThemeResource SurfaceBrush}"
MinHeight="200">
<Flyout Placement="Full" FlyoutPresenterStyle="{StaticResource TopDrawerFlyoutPresenterStyle}">
<StackPanel toolkit:VisibleBoundsPadding.PaddingMask="All" Background="{ThemeResource SurfaceBrush}">
<TextBlock Text="text" />
<Button Content="button" />
</StackPanel>
Expand All @@ -64,11 +78,8 @@
</Button>
<Button Content="Right Drawer">
<Button.Flyout>
<Flyout Placement="Full"
FlyoutPresenterStyle="{StaticResource RightDrawerFlyoutPresenterStyle}">
<StackPanel toolkit:VisibleBoundsPadding.PaddingMask="All"
Background="{ThemeResource SurfaceBrush}"
MinWidth="200">
<Flyout Placement="Full" FlyoutPresenterStyle="{StaticResource RightDrawerFlyoutPresenterStyle}">
<StackPanel toolkit:VisibleBoundsPadding.PaddingMask="All" Background="{ThemeResource SurfaceBrush}">
<TextBlock Text="text" />
<Button Content="button" />
</StackPanel>
Expand All @@ -77,18 +88,122 @@
</Button>
<Button Content="Bottom Drawer">
<Button.Flyout>
<Flyout Placement="Full"
FlyoutPresenterStyle="{StaticResource BottomDrawerFlyoutPresenterStyle}">
<StackPanel toolkit:VisibleBoundsPadding.PaddingMask="All"
Background="{ThemeResource SurfaceBrush}"
MinHeight="200">
<Flyout Placement="Full" FlyoutPresenterStyle="{StaticResource BottomDrawerFlyoutPresenterStyle}">
<StackPanel toolkit:VisibleBoundsPadding.PaddingMask="All" Background="{ThemeResource SurfaceBrush}">
<TextBlock Text="text" />
<Button Content="button" />
</StackPanel>
</Flyout>
</Button.Flyout>
</Button>
</StackPanel>

<!-- overriding DrawerLength -->
<TextBlock Text="You can inherit the above styles, and override utu:DrawerFlyoutPresenter.DrawerLength in a setter to customize the depth of drawer." Style="{StaticResource BodyTextBlockStyle}" />
<StackPanel Spacing="8" Margin="0,24,0,0">
<Button Content="Full Drawer (Value='*')">
<Button.Flyout>
<Flyout Placement="Full">
<Flyout.FlyoutPresenterStyle>
<Style BasedOn="{StaticResource BottomDrawerFlyoutPresenterStyle}" TargetType="FlyoutPresenter">
<Setter Property="utu:DrawerFlyoutPresenter.DrawerLength" Value="*" />
</Style>
</Flyout.FlyoutPresenterStyle>
<StackPanel toolkit:VisibleBoundsPadding.PaddingMask="All" Padding="8">
<TextBlock Text="text" />
<Button Content="button" />
</StackPanel>
</Flyout>
</Button.Flyout>
</Button>
<Button Content="Half Drawer (Value='0.5*')">
<Button.Flyout>
<Flyout Placement="Full">
<Flyout.FlyoutPresenterStyle>
<Style BasedOn="{StaticResource BottomDrawerFlyoutPresenterStyle}" TargetType="FlyoutPresenter">
<Setter Property="utu:DrawerFlyoutPresenter.DrawerLength" Value="0.5*" />
</Style>
</Flyout.FlyoutPresenterStyle>
<StackPanel toolkit:VisibleBoundsPadding.PaddingMask="All" Padding="8">
<TextBlock Text="text" />
<Button Content="button" />
</StackPanel>
</Flyout>
</Button.Flyout>
</Button>
<Button Content="Fit-to-Content Drawer (Value='Auto')">
<Button.Flyout>
<Flyout Placement="Full">
<Flyout.FlyoutPresenterStyle>
<Style BasedOn="{StaticResource BottomDrawerFlyoutPresenterStyle}" TargetType="FlyoutPresenter">
<Setter Property="utu:DrawerFlyoutPresenter.DrawerLength" Value="Auto" />
</Style>
</Flyout.FlyoutPresenterStyle>
<StackPanel toolkit:VisibleBoundsPadding.PaddingMask="All" Padding="8">
<TextBlock Text="text" />
<Button Content="button" />
</StackPanel>
</Flyout>
</Button.Flyout>
</Button>
<Button Content="150px fixed-size Drawer">
<Button.Flyout>
<Flyout Placement="Full">
<Flyout.FlyoutPresenterStyle>
<Style BasedOn="{StaticResource BottomDrawerFlyoutPresenterStyle}" TargetType="FlyoutPresenter">
<Setter Property="utu:DrawerFlyoutPresenter.DrawerLength" Value="150" />
</Style>
</Flyout.FlyoutPresenterStyle>
<StackPanel toolkit:VisibleBoundsPadding.PaddingMask="All" Padding="8">
<TextBlock Text="text" />
<Button Content="button" />
</StackPanel>
</Flyout>
</Button.Flyout>
</Button>
</StackPanel>

<!-- other custom examples -->
<TextBlock Text="Other custom examples:" Style="{StaticResource BodyTextBlockStyle}" />
<StackPanel Spacing="8" Margin="0,24,0,0">
<Button Content="Rounded Corner Drawer">
<Button.Flyout>
<Flyout Placement="Full">
<Flyout.FlyoutPresenterStyle>
<Style BasedOn="{StaticResource DrawerFlyoutPresenterStyle}" TargetType="FlyoutPresenter">
<Setter Property="CornerRadius" Value="16,16,0,0" />
<Setter Property="Background" Value="SkyBlue" />
</Style>
</Flyout.FlyoutPresenterStyle>
<StackPanel toolkit:VisibleBoundsPadding.PaddingMask="All" Padding="16,16,0,0">
<TextBlock Text="text" />
<Button Content="button" />
</StackPanel>
</Flyout>
</Button.Flyout>
</Button>
<Button Content="Custom LightDismiss Color Drawer">
<Button.Flyout>
<Flyout Placement="Full">
<Flyout.FlyoutPresenterStyle>
<Style BasedOn="{StaticResource DrawerFlyoutPresenterStyle}" TargetType="FlyoutPresenter">
<Setter Property="CornerRadius" Value="16,16,0,0" />
<Setter Property="Background" Value="SkyBlue" />
<Setter Property="utu:DrawerFlyoutPresenter.LightDismissOverlayBackground" Value="#80FFC0CB" />
<Setter Property="utu:DrawerFlyoutPresenter.IsGestureEnabled" Value="True" />
</Style>
</Flyout.FlyoutPresenterStyle>
<Border toolkit:VisibleBoundsPadding.PaddingMask="All" Padding="16,16,0,0">
<StackPanel Padding="8">
<TextBlock Text="text" />
<Button Content="button" />
</StackPanel>
</Border>
</Flyout>
</Button.Flyout>
</Button>
</StackPanel>

</StackPanel>
</ScrollViewer>
</DataTemplate>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#if !IS_WINUI || HAS_UNO
#if !IS_WINUI || HAS_UNO
#define SYS_NAV_MGR_SUPPORTED
#endif

Expand Down Expand Up @@ -239,6 +239,17 @@ object FindViewOfInterest()
// ...
// todo: add support for [RequiresFullWindow], flyout, nested navigation sample

var popups = VisualTreeHelper
#if IS_WINUI
.GetOpenPopupsForXamlRoot(XamlRoot);
#else
.GetOpenPopups(XamlWindow.Current);
#endif
if (popups.LastOrDefault() is { } popup)
{
return popup.Child;
}

var content = NavigationViewControl.Content;
if (content is RuntimeTestRunner runner)
{
Expand Down
Loading

0 comments on commit 5850dc6

Please sign in to comment.