🏗️
MauiReactor
  • What is MauiReactor?
  • What's new in Version 2
  • What's new in Version 3
  • Getting Started
  • Getting Started Version 2
  • Components
    • State-less Components
    • Stateful Components
      • Inline Components
    • Component life-cycle
    • Component Properties
    • Component with children
    • Component Parameters
    • Theming
    • Navigation
      • NavigationPage
      • Shell
      • Back button
    • Controls
      • Button
      • RadioButton
      • FlyoutPage
      • CollectionView
        • Interactions
        • Layout
        • Selection
        • Empty view
        • Scrolling
        • Grouping
      • IndicatorView
      • Picker
      • Shell
      • Label
    • Wrap 3rd party controls
      • Lottie animations
      • Provide DataTemplate to native controls
    • Accessing native controls
    • Animation
      • Property-Based
      • AnimationController
      • Timer
    • Graphics
      • CanvasView control
    • Window
    • Testing
    • XAML Integration
  • Deep dives
    • Native tree and Visual tree
    • Dependency injection
    • Working with the GraphicsView
    • Migrating from MVVM Model
    • Using XAML Resources
    • Behaviors
  • resources
    • Source and Sample Applications
  • Q&A
    • How to deal with state shared across Components?
    • Does this support ObservableCollection for CollectionView?
    • Do we need to add states to create simple animations such as ScaleTo, FadeTo, etc on tap?
    • How to deal with custom dialogs/popups?
  • How to create a Menu/ContextMenu?
Powered by GitBook
On this page
  • Use a component, with a layout control containing the Children element and animate it when tapped:
  • Create an extension function for the MauiReactor widget that realizes the animation:
  • Create a component that renders just one child animated when tapped:

Was this helpful?

Edit on GitHub
  1. Q&A

Do we need to add states to create simple animations such as ScaleTo, FadeTo, etc on tap?

Even if RxAnimations or AnimationController class are the primary way to create animations in MauiReactor, aren't strictly required.

Take for example how we can create an animated button: we want the user to see a scale animation when clicking over a widget (Image, Button, etc).

Apart from RxAnimation, we can easily just call the ScaleTo view extension method over the native control to achieve the same effect.

Following, we'll see possible implementations:

Use a component, with a layout control containing the Children element and animate it when tapped:

class AnimatedComponent: Component
{
    private Func<Task>? _action;
    private MauiControls.Grid? _containerGrid;

    public AnimatedComponent OnTapped(Func<Task> action)
    {
        _action = action;
        return this;
    }

    public override VisualNode Render()
    {
        return new Grid(grid => _containerGrid = grid)
        {
            Children()
        }
        .OnTapped(async () =>
        {
            if (_containerGrid != null && _action != null)
            {
                await MauiControls.ViewExtensions.ScaleTo(_containerGrid, 0.7);
                await _action.Invoke();
                await MauiControls.ViewExtensions.ScaleTo(_containerGrid, 1.0);
            }
        });
    }
}

Create an extension function for the MauiReactor widget that realizes the animation:

static class AnimatedButtonExtensions
{
    public static T OnTappedWithAnimation<T>(this T view, Func<Task> action) where T : IView
    {
        view.OnTapped(async (sender, args) =>
        {
            var visualElement = (MauiControls.VisualElement?)sender;
            if (visualElement == null)
            {
                return;
            }
            await MauiControls.ViewExtensions.ScaleTo(visualElement, 0.7);
            await action.Invoke();
            await MauiControls.ViewExtensions.ScaleTo(visualElement, 1.0);
        });
        return view; 
    }
}

Create a component that renders just one child animated when tapped:

class AnimatedComponent2: Component
{
    private Func<Task>? _action;

    public AnimatedComponent2 OnTapped(Func<Task> action)
    {
        _action = action;
        return this;
    }

    public override VisualNode Render()
    {
        var child = Children().FirstOrDefault();
        if (child == null)
        {
            return null!;
        }

        if (child is IView viewChild)
        {
            viewChild.OnTapped(async (sender, args) =>
            {
                var visualElement = (MauiControls.VisualElement?)sender;
                if (visualElement == null)
                {
                    return;
                }

                if (_action != null)
                {
                    await MauiControls.ViewExtensions.ScaleTo(visualElement, 0.7);
                    await _action.Invoke();
                    await MauiControls.ViewExtensions.ScaleTo(visualElement, 1.0);
                }
            });
        }

        return child;
    }
}

Let's put everything on a page to show the same resulting effect of each variation:

class AnimatedButtonPage: Component
{
    public override VisualNode Render()
    {
        return new ContentPage("Animated image sample")
        {
            new VStack(spacing: 20)
            {
                new AnimatedComponent
                {
                    new Image("tab_home.png"),
                }
                .OnTapped(OnTapped),

                new Image("tab_home.png")
                    .OnTappedWithAnimation(OnTapped),

                new AnimatedComponent2
                {
                    new Image("tab_home.png"),
                }
                .OnTapped(OnTapped)
            }
            .VCenter()
        };
    }

    async Task OnTapped()
    {
        if (ContainerPage != null)
        {
            await ContainerPage.DisplayAlert("MauiReactor", "Tapped!", "OK");
        }
    }
}
PreviousDoes this support ObservableCollection for CollectionView?NextHow to deal with custom dialogs/popups?

Last updated 3 months ago

Was this helpful?