-
Notifications
You must be signed in to change notification settings - Fork 491
Add ExpanderAnimationBehavior, IExpansionController #3124
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
Open
stephenquan
wants to merge
10
commits into
CommunityToolkit:main
Choose a base branch
from
stephenquan:feature/stephenquan/2521-expander-v2
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
50f76f4
Add ExpanderAnimationBehavior, IExpansionController, ExpandedChanging…
stephenquan b828c27
Implemented Copilot feedback
stephenquan acdc9e2
Add new unit tests ExpanderController, Expanding and ExpanderAnimatio…
stephenquan 18803ea
Implement unit tests changes as well as TCS gate as recommended by Co…
stephenquan 71888e6
Make InstantExpansionController a sealed singleton with private const…
stephenquan 4186bbd
Reverted ExpanderPage. Made Expander.ExpansionController nullable.
stephenquan c38ce1c
Create expansionGate early
stephenquan b8e5785
Reset Expander.ContentHost when Expander.Content is cleared
stephenquan 8036ab4
Windows workaround no longer needed?
stephenquan 4289947
Updated unit test. Refactored ExpanderAnimationBehavior animations.
stephenquan File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
9 changes: 9 additions & 0 deletions
9
...ommunityToolkit.Maui.Core/Primitives/Defaults/ExpanderAnimationBehaviorDefaults.shared.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| namespace CommunityToolkit.Maui.Core; | ||
|
|
||
| static class ExpanderAnimationBehaviorDefaults | ||
| { | ||
| public const uint CollapsingLength = 250u; | ||
| public static Easing CollapsingEasing { get; } = Easing.Linear; | ||
| public const uint ExpandingLength = 250u; | ||
| public static Easing ExpandingEasing { get; } = Easing.Linear; | ||
| } |
17 changes: 17 additions & 0 deletions
17
src/CommunityToolkit.Maui.Core/Primitives/ExpandedChangingEventArgs.shared.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| namespace CommunityToolkit.Maui.Core; | ||
|
|
||
| /// <summary> | ||
| /// Provides data for an event that occurs when an Expander is about to change its IsExpanded state. | ||
| /// </summary> | ||
| public class ExpandedChangingEventArgs(bool oldIsExpanded, bool newIsExpanded) : EventArgs | ||
| { | ||
| /// <summary> | ||
| /// True if expander was expanded before the change. | ||
| /// </summary> | ||
| public bool OldIsExpanded { get; } = oldIsExpanded; | ||
|
|
||
| /// <summary> | ||
| /// True if expander will be expanded after the change. | ||
| /// </summary> | ||
| public bool NewIsExpanded { get; } = newIsExpanded; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
93 changes: 93 additions & 0 deletions
93
src/CommunityToolkit.Maui/Behaviors/ExpanderAnimationBehavior.shared.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,93 @@ | ||
| using CommunityToolkit.Maui.Core; | ||
|
|
||
| namespace CommunityToolkit.Maui.Behaviors; | ||
|
|
||
| /// <summary> | ||
| /// A behavior that adds smooth expand and collapse animations to an <see cref="Views.Expander"/>. | ||
| /// </summary> | ||
| public partial class ExpanderAnimationBehavior : BaseBehavior<Views.Expander>, IExpansionController | ||
| { | ||
| /// <summary> | ||
stephenquan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| /// Gets or sets the easing function used when the expander collapses. | ||
| /// </summary> | ||
| [BindableProperty] | ||
| public partial Easing CollapsingEasing { get; set; } = ExpanderAnimationBehaviorDefaults.CollapsingEasing; | ||
|
|
||
| /// <summary> | ||
| /// Gets or sets the duration, in milliseconds, of the collapse animation. | ||
| /// </summary> | ||
| [BindableProperty] | ||
| public partial uint CollapsingLength { get; set; } = ExpanderAnimationBehaviorDefaults.CollapsingLength; | ||
|
|
||
| /// <summary> | ||
| /// Gets or sets the easing function used when the expander expands. | ||
| /// </summary> | ||
| [BindableProperty] | ||
| public partial Easing ExpandingEasing { get; set; } = ExpanderAnimationBehaviorDefaults.ExpandingEasing; | ||
|
|
||
| /// <summary> | ||
| /// Gets or sets the duration, in milliseconds, of the expansion animation. | ||
| /// </summary> | ||
| [BindableProperty] | ||
| public partial uint ExpandingLength { get; set; } = ExpanderAnimationBehaviorDefaults.ExpandingLength; | ||
|
|
||
| IExpansionController? previousController; | ||
|
|
||
| /// <summary> | ||
| /// Attaches the behavior to the specified expander and assigns it as the controller responsible for handling expansion animations. | ||
| /// </summary> | ||
| /// <param name="bindable">The Expander control to which the behavior is being attached to.</param> | ||
| protected override void OnAttachedTo(Views.Expander bindable) | ||
| { | ||
| base.OnAttachedTo(bindable); | ||
| previousController = bindable.ExpansionController; | ||
| bindable.ExpansionController = this; | ||
| } | ||
stephenquan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| /// <summary> | ||
| /// Detaches the behavior from the specified Expander control and restores its previous expansion controller. | ||
| /// </summary> | ||
| /// <param name="bindable">The Expander control from which the behavior is being detached.</param> | ||
| protected override void OnDetachingFrom(Views.Expander bindable) | ||
| { | ||
| base.OnDetachingFrom(bindable); | ||
| if (bindable.ExpansionController == this) | ||
| { | ||
| bindable.ExpansionController = previousController; | ||
| } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Performs the animation that runs when the expander transitions from a collapsed to an expanded state. | ||
| /// </summary> | ||
| /// <param name="expander">The Expander control that is expanding.</param> | ||
| public async Task OnExpandingAsync(Views.Expander expander) | ||
| { | ||
| if (expander.ContentHost is ContentView host && expander.Content is View view) | ||
| { | ||
| var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); | ||
| var size = view.Measure(host.Width, double.PositiveInfinity); | ||
| var animation = new Animation(v => host.HeightRequest = v, 0, size.Height); | ||
| animation.Commit(expander, "ExpanderAnimation", 16, ExpandingLength, ExpandingEasing, (v, c) => tcs.TrySetResult()); | ||
| await tcs.Task; | ||
| host.HeightRequest = -1; | ||
| } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Performs the animation that runs when the expander transitions from an expanded to a collapsed state. | ||
| /// </summary> | ||
| /// <param name="expander">The Expander control that is collapsing.</param> | ||
| public async Task OnCollapsingAsync(Views.Expander expander) | ||
| { | ||
| if (expander.ContentHost is ContentView host && expander.Content is View view) | ||
| { | ||
| var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); | ||
| var size = view.Measure(host.Width, double.PositiveInfinity); | ||
| var animation = new Animation(v => host.HeightRequest = v, size.Height, 0); | ||
| animation.Commit(expander, "ExpanderAnimation", 16, CollapsingLength, CollapsingEasing, (v, c) => tcs.TrySetResult()); | ||
| await tcs.Task; | ||
| host.HeightRequest = 0; | ||
| } | ||
| } | ||
| } | ||
24 changes: 24 additions & 0 deletions
24
src/CommunityToolkit.Maui/Interfaces/IExpansionController.shared.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| namespace CommunityToolkit.Maui; | ||
|
|
||
| /// <summary> | ||
| /// Defines a pluggable controller responsible for handling expansion | ||
| /// and collapse transitions for an <see cref="Views.Expander"/>. | ||
| /// </summary> | ||
| public interface IExpansionController | ||
| { | ||
| /// <summary> | ||
| /// Executes asynchronous logic when the expander transitions | ||
| /// from a collapsed to an expanded state. | ||
| /// </summary> | ||
| /// <param name="expander">The <see cref="Views.Expander"/> instance initiating the expansion.</param> | ||
| /// <returns>A task representing the asynchronous operation.</returns> | ||
| Task OnExpandingAsync(Views.Expander expander); | ||
|
|
||
| /// <summary> | ||
| /// Executes asynchronous logic when the expander transitions | ||
| /// from an expanded to a collapsed state. | ||
| /// </summary> | ||
| /// <param name="expander">The <see cref="Views.Expander"/> instance initiating the collapse.</param> | ||
| /// <returns>A task representing the asynchronous operation.</returns> | ||
| Task OnCollapsingAsync(Views.Expander expander); | ||
stephenquan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.