Okay, I figured it out and let me answer my own question.
-
Expander.Content
in my case is a question mark based on a Style resource asFontImage
. - I use
ScaleYTo
animation of the content (seemyAnim:ScaleYToAnimation
Class reference) , and for this I chose aBorder
control to contain theLabel
to display the Tip message. - Since animation requires a trigger, I decided to use the
SizeChanged
event of theBorder
. For this to work, the user input trigger ofExpander
'sExpandedChanged
event is used to do the trick forSizeChanged
to trigger programatically. - A
RelayCommand
is invoked with theExpandedChanged
which does most of the tricks as shown in theRelayCommand
method (see below). - The
ClassId
attached to theLabel
serves as an Id for what Tip message to display, because there are many Tips to be shown with the sameRelayCommand
and 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.