A Microsoft open-source framework for building native device applications spanning mobile, tablet, and desktop.
Okay, I figured it out and let me answer my own question.
-
Expander.Contentin my case is a question mark based on a Style resource asFontImage. - I use
ScaleYToanimation of the content (seemyAnim:ScaleYToAnimationClass reference) , and for this I chose aBordercontrol to contain theLabelto display the Tip message. - Since animation requires a trigger, I decided to use the
SizeChangedevent of theBorder. For this to work, the user input trigger ofExpander'sExpandedChangedevent is used to do the trick forSizeChangedto trigger programatically. - A
RelayCommandis invoked with theExpandedChangedwhich does most of the tricks as shown in theRelayCommandmethod (see below). - The
ClassIdattached to theLabelserves as an Id for what Tip message to display, because there are many Tips to be shown with the sameRelayCommandand each is made distinct with itsClassId. - ScreenToGif recording of a working demo is shown at the end.
This is what I did, and if you have a simpler and better solution, please share.
xmlns:ctk="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
xmlns:myAnim="clr-namespace:ExpanderTest.Animations"
...
<ctk:Expander
Grid.Row="9"
Grid.Column="0"
Grid.ColumnSpan="4"
Margin="12"
Padding="0"
Command="{Binding TellMeMoreTipClickedCommand}"
CommandParameter="{Binding Source={RelativeSource Self}}">
<ctk:Expander.Header>
<!--
CircledQuestion is a styled FontImage with
FontAwesome.QuestionCircle Glyph
-->
<ImageButton
Margin="0"
Aspect="AspectFit"
BackgroundColor="{StaticResource CyanBlueWhite}"
HorizontalOptions="Start"
Source="{StaticResource CircledQuestion}"
VerticalOptions="Center" />
</ctk:Expander.Header>
<ctk:Expander.Content>
<Border
Margin="12,0"
Padding="18"
BackgroundColor="PowderBlue"
HorizontalOptions="Fill"
StrokeThickness="1">
<Border.StrokeShape>
<RoundRectangle CornerRadius="9" />
</Border.StrokeShape>
<Border.Behaviors>
<ctk:AnimationBehavior EventName="SizeChanged">
<ctk:AnimationBehavior.AnimationType>
<myAnim:ScaleYToAnimation Easing="{x:Static Easing.Linear}" Length="500" />
</ctk:AnimationBehavior.AnimationType>
</ctk:AnimationBehavior>
</Border.Behaviors>
<Label ClassId="_TipVeriCode" Text="This Id can serve as an identifier of what tip message to show." />
</Border>
</ctk:Expander.Content>
</ctk:Expander>
using CommunityToolkit.Maui.Animations;
namespace ExpanderTest.Animations;
class ScaleYToAnimation : BaseAnimation
{
public override async Task Animate(VisualElement view)
{
await view.ScaleYTo(0.0, Length, Easing);
await view.ScaleYTo(1.2, Length, Easing);
await view.ScaleYTo(1, Length, Easing);
}
}
double originalBorderHeight = -1;
[RelayCommand]
private async void TellMeMoreTipClicked(Expander expander)
{
if (expander is null) return;
// Nothing to do if Expander is collapsing
if (!expander.IsExpanded) return;
// Use VisualTreeHelper to get to child controls
// There is only one Border and one Label.
var label = expander.FirstChild<Label>();
string id = label.ClassId;
label.Text = "<message-from-database-with-id";
var border = expander.FirstChild<Border>();
border.ScaleY = 0; // makes expansion to start from a collapsed Height.
if (border.Height > 0)
{
// capture initially set value
if (originalBorderHeight < 0) originalBorderHeight = border.Height;
// keep changing border.Height every time to trigger Border.SizeChanged() event
if (border.Height != originalBorderHeight)
{
border.HeightRequest = originalBorderHeight;
}
else
{
border.HeightRequest = originalBorderHeight + 1;
}
}
else
{
// This is startup and SizeChanged will trigger anyway.
}
}
The ScreenToGif recording is shown below.