Skip to content

Commit

Permalink
feat(responsive): add support for non-FrameworkElement
Browse files Browse the repository at this point in the history
  • Loading branch information
Xiaoy312 committed Mar 28, 2024
1 parent b6b81c1 commit 5c24d2d
Show file tree
Hide file tree
Showing 5 changed files with 285 additions and 32 deletions.
20 changes: 20 additions & 0 deletions doc/helpers/responsive-extension.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,26 @@ xmlns:utu="using:Uno.Toolkit.UI"
<TextBlock Background="{utu:Responsive Narrow=Red, Wide=Blue}" Text="Asd" />
```

`ResponsiveExpression` does not normally work directly on non-FrameworkElement. We have added some workaround to cover common usages:

```xml
<Page.Resources>
<GridLength x:Key="GL50">50</GridLength>
<GridLength x:Key="GL150">150</GridLength>
<SolidColorBrush x:Key="Red">Red</SolidColorBrush>
<SolidColorBrush x:Key="Green">Green</SolidColorBrush>
<SolidColorBrush x:Key="Blue">Blue</SolidColorBrush>

<Grid utu:ResponsiveBehavior.IsEnabled="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{utu:Responsive Narrow={StaticResource GL50}, Wide={StaticResource GL150}}" />

<TextBlock utu:ResponsiveBehavior.IsEnabled="True">
<Run Text="asd" Foreground="{utu:Responsive Narrow={StaticResource Red}, Wide={StaticResource Green}}" />
```

If you have a setup that is not covered, feel free to [open an issue in the toolkit repo](https://github.com/unoplatform/uno.toolkit.ui/issues/new/choose).

### Custom thresholds

```xml
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@
<sample:SamplePageLayout.DesignAgnosticTemplate>
<DataTemplate>
<StackPanel Spacing="20">
<StackPanel.Resources>
<GridLength x:Key="GL50">50</GridLength>
<GridLength x:Key="GL150">150</GridLength>
<SolidColorBrush x:Key="Red">Red</SolidColorBrush>
<SolidColorBrush x:Key="Green">Green</SolidColorBrush>
<SolidColorBrush x:Key="Blue">Blue</SolidColorBrush>
</StackPanel.Resources>

<!-- string literal -->
<TextBlock Text="Text test" FontWeight="Bold" />
Expand Down Expand Up @@ -53,6 +60,35 @@
<Border Grid.Column="{utu:Responsive Narrowest=0, Narrow=1, Normal=0, Wide=1, Widest=0}" Background="Pink" />
</Grid>

<!-- non-FE: Grid.Column/RowDefinitions -->
<TextBlock Text="Grid.ColumnDefinition test" />
<Grid utu:ResponsiveBehavior.IsEnabled="True"
Height="50"
HorizontalAlignment="Left">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{utu:Responsive Narrow={StaticResource GL150}, Normal={StaticResource GL50}, Wide={StaticResource GL150}, Widest={StaticResource GL50}}" />
<ColumnDefinition Width="{utu:Responsive Narrow={StaticResource GL50}, Normal={StaticResource GL150}, Wide={StaticResource GL50}, Widest={StaticResource GL150}}" />
</Grid.ColumnDefinitions>

<Border Grid.Column="0" Background="Pink" />
<Border Grid.Column="1" Background="SkyBlue" />
</Grid>

<!-- non-FE: TextBlock.Inlines -->
<TextBlock Text="TextBlock.Inlines test" />
<TextBlock utu:ResponsiveBehavior.IsEnabled="True">
<Run Text="asd" Foreground="{utu:Responsive Narrow={StaticResource Red}, Normal={StaticResource Blue}, Wide={StaticResource Green}, Widest={StaticResource Red}}" />
<Run Text="qwe" Foreground="{utu:Responsive Narrow={StaticResource Green}, Normal={StaticResource Red}, Wide={StaticResource Blue}, Widest={StaticResource Green}}" />
<Run Text="zxc" Foreground="{utu:Responsive Narrow={StaticResource Blue}, Normal={StaticResource Green}, Wide={StaticResource Red}, Widest={StaticResource Blue}}" />
<Span FontStyle="Italic">
<Run Text="asd" Foreground="{utu:Responsive Narrow={StaticResource Red}, Normal={StaticResource Blue}, Wide={StaticResource Green}, Widest={StaticResource Red}}" />
<Run Text="qwe" Foreground="{utu:Responsive Narrow={StaticResource Green}, Normal={StaticResource Red}, Wide={StaticResource Blue}, Widest={StaticResource Green}}" />
<Span>
<Run Text="zxc" Foreground="{utu:Responsive Narrow={StaticResource Blue}, Normal={StaticResource Green}, Wide={StaticResource Red}, Widest={StaticResource Blue}}" />
</Span>
</Span>
</TextBlock>

<!-- layout overriding -->
<TextBlock Text="Custom values override" FontWeight="Bold" />
<StackPanel>
Expand Down Expand Up @@ -83,6 +119,7 @@
<TextBlock Text="{utu:Responsive Layout={StaticResource CustomLayout}, Narrowest=Narrowest, Narrow=Narrow, Normal=Normal, Wide=Wide, Widest=Widest}" />
</StackPanel>
</StackPanel>

</StackPanel>
</DataTemplate>
</sample:SamplePageLayout.DesignAgnosticTemplate>
Expand Down
102 changes: 102 additions & 0 deletions src/Uno.Toolkit.UI/Behaviors/ResponsiveBehavior.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;

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

namespace Uno.Toolkit.UI;

public static class ResponsiveBehavior
{
#region DependencyProperty: IsEnabled

public static DependencyProperty IsEnabledProperty { [DynamicDependency(nameof(GetIsEnabled))] get; } = DependencyProperty.RegisterAttached(
"IsEnabled",
typeof(bool),
typeof(ResponsiveBehavior),
new PropertyMetadata(default(bool), OnIsEnabledChanged));

[DynamicDependency(nameof(SetIsEnabled))]
public static bool GetIsEnabled(DependencyObject obj) => (bool)obj.GetValue(IsEnabledProperty);
[DynamicDependency(nameof(GetIsEnabled))]
public static void SetIsEnabled(DependencyObject obj, bool value) => obj.SetValue(IsEnabledProperty, value);

#endregion

internal static bool IsChildSupported(DependencyObject? child) => child switch
{
ColumnDefinition or RowDefinition => true,
Inline => true,

_ => false,
};

private static void OnIsEnabledChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
if (sender is Grid g)
{
g.Loaded += OnGridLoaded;
}
else if (sender is TextBlock tb)
{
tb.Loaded += OnTextBlockLoaded;
}
else
{
throw new NotSupportedException($"ResponsiveBehavior is not supported on '{sender.GetType()}'.");
}
}

private static void OnGridLoaded(object sender, RoutedEventArgs e)
{
if (sender is not Grid host) return;

var markups = Enumerable
.Concat<DependencyObject>(host.ColumnDefinitions, host.RowDefinitions)
.SelectMany(ResponsiveExtension.GetAllInstancesFor);
foreach (var markup in markups)
{
markup.InitializeByProxy(host);
}
}

private static void OnTextBlockLoaded(object sender, RoutedEventArgs e)
{
if (sender is not TextBlock host) return;

// There is actually be more elements than what's defined in the xaml;
// these come from the whitespaces... and, they are fine.
var markups = FlattenInlines(host)
.SelectMany(ResponsiveExtension.GetAllInstancesFor);
foreach (var markup in markups)
{
markup.InitializeByProxy(host);
}
}

private static IEnumerable<Inline> FlattenInlines(TextBlock tb) => FlattenInlines(tb.Inlines);
private static IEnumerable<Inline> FlattenInlines(InlineCollection inlines)
{
foreach (var inline in inlines)
{
yield return inline;

if (inline is Span span)
{
foreach (var nested in FlattenInlines(span.Inlines))
{
yield return nested;
}
}
}
}
}
Loading

0 comments on commit 5c24d2d

Please sign in to comment.