{"id":38161,"date":"2018-10-16T13:32:32","date_gmt":"2018-10-16T17:32:32","guid":{"rendered":"https:\/\/blog.xamarin.com\/?p=38161"},"modified":"2019-04-04T15:50:11","modified_gmt":"2019-04-04T22:50:11","slug":"complex-animations-xamarin-forms-using-finite-state-machine","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/xamarin\/complex-animations-xamarin-forms-using-finite-state-machine\/","title":{"rendered":"Complex Animations in Xamarin.Forms using Finite State Machine"},"content":{"rendered":"<p><em>This guest post was contributed by Slava Chernikoff, a Principal Engineer at <a href=\"https:\/\/binwell.com\">Binwell<\/a>. Microsoft MVP and Xamarin Certified experienced mobile cross-platform and native developer. Also, a previously honored Nokia Champion and Qt Certified Developer.<\/em><\/p>\n<h2>Introduction<\/h2>\n<p>If you have been a student of a technical specialty, you will surely remember the course devoted to the  <a href=\"https:\/\/en.wikipedia.org\/wiki\/Finite-state_machine\">Finite State Machines<\/a>.<\/p>\n<p>This simple, but very capacious model of finite state machine (a.k.a. FSM) is used widely, although most programmers have unfortunately forgotten about it. Today we will talk about finite state machines and their application in complex animations for Xamarin.Forms apps.<\/p>\n<p>If you already use Xamarin.Forms in real projects, you probably saw a built-in animation engine. If not, then we recommend you start with the articles\u202f<a href=\"https:\/\/blog.xamarin.com\/creating-animations-with-xamarin-forms\/\">\u201cCreating Animations with Xamarin.Forms\u201d<\/a> and <a href=\"http:\/\/xfcomplete.net\/animation\/2016\/01\/18\/compound-animations\/\">\u201cCompound Animations\u201d<\/a>.<\/p>\n<h3>Modifying Properties<\/h3>\n<p>Most often, you need to animate the following properties:<\/p>\n<ul>\n<li><strong>Scale<\/strong> of the element<\/li>\n<li><strong>Opacity<\/strong> transparency<\/li>\n<li><strong>Translation<\/strong> additional offset x, y, relative to the position obtained in the layout<\/li>\n<li><strong>Rotation<\/strong> rotation around the x, y, z-axes<\/li>\n<\/ul>\n<p>There are low-level iOS\/Android mechanisms used in Xamarin.Forms to modify these properties which have a great effect on performance, so\u200athere is no problem animating a lot of controls at once.<\/p>\n<p>In our example we will focus on the set of properties shown before, however you can expand the mechanisms by yourself for supporting BackgroundColor property, for example.<\/p>\n<h3>Finite State\u202fMachines<\/h3>\n<p><figure id=\"attachment_38167\" aria-labelledby=\"figcaption_attachment_38167\" class=\"wp-caption aligncenter\" ><img decoding=\"async\" class=\"wp-image-38167\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/44\/2019\/03\/FSM_IMG.01.png\" alt=\"\" width=\"900\" height=\"483\" \/><figcaption id=\"figcaption_attachment_38167\" class=\"wp-caption-text\">Figure 1. Sample of a Finite State Machine diagram<\/figcaption><\/figure><\/p>\n<p>A Finite State Machine is an object that can be in different stable states (i.e. \u201cdownload\u201d or \u201cerror\u201d). The machine changes its states under the influence of external events. The number of states is finite. Examples of such machines are elevators and traffic lights.<\/p>\n<p>How do finite state machines relate to animations and especially to Xamarin.Forms? Let\u2019s see.<\/p>\n<h3>One Screen, Many States, and Animated Transitions<\/h3>\n<p>To learn more about page states it is suggested to start with\u202f<a href=\"https:\/\/github.com\/xDelivered-Patrick\/Xamarin.Forms.Essentials\/blob\/master\/Essentials\/Controls\/State\/StateContainer.cs\">StateContainer component by Patrick McCurley<\/a>. This control simplifies the development of complex user interfaces and is suitable for most screens in business applications.<\/p>\n<p>This component works well when all states exist independently of each other and there is a simple transition between them, \u201cone disappeared\u200a\u2014\u200athe second appeared\u201d.<\/p>\n<p><figure id=\"attachment_38168\" aria-labelledby=\"figcaption_attachment_38168\" class=\"wp-caption aligncenter\" ><img decoding=\"async\" class=\"wp-image-38168\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/44\/2019\/03\/FSM_IMG.02.png\" alt=\"\" width=\"900\" height=\"360\" \/><figcaption id=\"figcaption_attachment_38168\" class=\"wp-caption-text\">Figure 2. State switching using the StateContainer<\/figcaption><\/figure><\/p>\n<p>But what if you need to implement a complex and animated transition from one state to another? As an example, let\u2019s look at the screen for entering addresses and working with the map. It is implemented in navigators or taxi services.<\/p>\n<p>Imagine that we have animated transitions between the following states of ONE screen:<\/p>\n<p><figure id=\"attachment_38169\" aria-labelledby=\"figcaption_attachment_38169\" class=\"wp-caption aligncenter\" ><img decoding=\"async\" class=\"wp-image-38169\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/44\/2019\/03\/FSM_IMG.03.png\" alt=\"\" width=\"900\" height=\"412\" \/><figcaption id=\"figcaption_attachment_38169\" class=\"wp-caption-text\">Figure 3. Screen with transition animations between\u202fstates<\/figcaption><\/figure><\/p>\n<p>As shown, we have such a finite state machine that shown on Figure 4.<\/p>\n<p><figure id=\"attachment_38170\" aria-labelledby=\"figcaption_attachment_38170\" class=\"wp-caption aligncenter\" ><img decoding=\"async\" class=\"wp-image-38170\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/44\/2019\/03\/FSM_IMG.04.png\" alt=\"\" width=\"900\" height=\"443\" \/><figcaption id=\"figcaption_attachment_38170\" class=\"wp-caption-text\">Figure 4. State transitions for navigator app main page<\/figcaption><\/figure><\/p>\n<p>It is necessary to implement the following animations when changing from state to state:<\/p>\n<ul>\n<li><em>Entering FindAddress state<\/em>, will hide the old content with the animation and smoothly display the new one. Also, it will animate the buttons at the time of appearance.<\/li>\n<li><em>Switching to ShowRoute<\/em>, it is necessary to hide the old state and a route information component will appear from the bottom.<\/li>\n<li><em>Switching to Drive<\/em>, it is necessary to hide the old state and display route information on the top of the screen.<\/li>\n<li><em>When going to Main (except for the first run)<\/em>, hide the current state and smoothly display the button with a small zoom animation.<\/li>\n<\/ul>\n<p><a href=\"https:\/\/www.youtube.com\/watch?v=8qDfWoq-zpg\">Here you can find a demo video.<\/a>\n<iframe width=\"560\" height=\"315\" src=\"https:\/\/www.youtube.com\/embed\/8qDfWoq-zpg\" frameborder=\"0\" allow=\"autoplay; encrypted-media\" allowfullscreen=\"allowfullscreen\"><\/iframe><\/center><\/p>\n<h3>Write Your\u202fFSM<\/h3>\n<p>Take the simplest implementation of FSM:<\/p>\n<ul>\n<li>The machine has a fixed set of states that can be specified at initialization &#8211; <strong>Method Add<\/strong>.<\/li>\n<li>Each state is described by a set of necessary animations, or final properties values, for UI elements (buttons, labels, etc.).<\/li>\n<li>When it enters to a new state, all animations that were added at the initialization of the machine are started in parallel.<\/li>\n<\/ul>\n<p>We will not store any transition history. It also doesn&#8217;t matter which user event triggered the transition from one state to another. There is only a transition to a new state &#8211; <strong>the Go method<\/strong>, which is accompanied by animations.<\/p>\n<p>So, the simplest FSM, called <em>Storyboard<\/em>, will look like this:<\/p>\n<pre><code>\r\npublic enum AnimationType { \r\n    Scale, \r\n    Opacity, \r\n    TranslationX, \r\n    TranslationY, \r\n    Rotation \r\n} \r\n\r\npublic class Storyboard { \r\n    readonly Dictionary&lt;string, ViewTransition[]&gt; _stateTransitions = new Dictionary&lt;string, ViewTransition[]&gt;(); \r\n\r\npublic void Add(object state, ViewTransition[] viewTransitions) { \r\n        var stateStr = state?.ToString().ToUpperInvariant(); \r\n\r\n_stateTransitions.Add(stateStr, viewTransitions); \r\n    } \r\n\r\npublic void Go(object newState, bool withAnimation = true) { \r\n        var newStateStr = newState?.ToString().ToUpperInvariant(); \r\n\r\n\/\/ Get all ViewTransitions  \r\n        var viewTransitions = _stateTransitions[newStateStr]; \r\n\r\n\/\/ Get transition tasks \r\n        var tasks = viewTransitions.Select(viewTransition =&gt; viewTransition.GetTransition(withAnimation)); \r\n\r\n\/\/ Run all transition tasks \r\n        Task.WhenAll(tasks); \r\n    } \r\n} \r\n\r\n\r\npublic class ViewTransition { \r\n\/\/ Some trivial code was skipped. See complete sample in repository below \r\n\r\npublic async Task GetTransition(bool withAnimation) { \r\n        VisualElement targetElement; \r\n        if( !_targetElementReference.TryGetTarget(out targetElement) ) \r\n           throw new ObjectDisposedException(nameof(targetElement), \"Target VisualElement was disposed\"); \r\n\r\nif( _delay &gt; 0 ) \r\n        await Task.Delay(_delay); \r\n\r\nwithAnimation &amp;= _length &gt; 0; \r\n\r\nswitch ( _animationType ) { \r\n        case AnimationType.Scale: \r\n            if( withAnimation ) \r\n               await targetElement.ScaleTo(_endValue, _length, _easing); \r\n            else \r\n               targetElement.Scale = _endValue; \r\n            break; \r\n\r\n\/\/ See complete sample in repository below \r\n\r\ndefault: \r\n            throw new ArgumentOutOfRangeException(); \r\n        } \r\n    } \r\n} \r\n<\/code><\/pre>\n<p>In the example above, the input data checks are omitted. A full version of the example can be <a href=\"https:\/\/github.com\/binwell\/xamarinstatemachine\">found in the repository<\/a>.<\/p>\n<p>As you can see, when you move to a new state, only the necessary smooth changes are started in parallel. There is also the possibility to enter a new state without animation.<\/p>\n<h3>Using Finite State Machine<\/h3>\n<p>So, we have a machine and can connect it to set the necessary states of UI elements. Example of adding a new state:<\/p>\n<pre><code>\r\n_storyboard.Add(States.Drive, new[] { \r\n   new ViewTransition(ShowRouteView, AnimationType.TranslationY, 200), \r\n   new ViewTransition(ShowRouteView, AnimationType.Opacity, 0, 0, delay: 250), \r\n   new ViewTransition(DriveView, AnimationType.TranslationY, 0, 300, delay: 250), \/\/ Active and visible \r\n   new ViewTransition(DriveView, AnimationType.Opacity, 1, 0) \/\/ Active and visible \r\n}); \r\n<\/code><\/pre>\n<p>For the Drive state, set an array of individual animations. <em>ShowRouteView<\/em> and <em>DriveView<\/em> are the usual Views, specified in XAML displayed on the example below.<\/p>\n<p>To go to a new state it is enough to call the <em>Go() method<\/em>:<\/p>\n<pre><code>\r\n_storyboard.Go(States.Drive); \r\n<\/code><\/pre>\n<p>The code is relatively small and group animations are created by a simple set of numbers. Our state machine can work not only with pages, but also with individual View which expands the variants of its application. It is better to use Storyboard inside the page\u2019s C# code behind(Page.cs) and not mix it with business logic (ViewModels).<\/p>\n<p>Here is an example of XAML, which describes all the elements of the user interface.<\/p>\n<p><figure id=\"attachment_38171\" aria-labelledby=\"figcaption_attachment_38171\" class=\"wp-caption aligncenter\" ><img decoding=\"async\" class=\"wp-image-38171\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/44\/2019\/03\/FSM_IMG.05.png\" alt=\"\" width=\"900\" height=\"345\" \/><figcaption id=\"figcaption_attachment_38171\" class=\"wp-caption-text\">Figure 5. Sample of XAML page with Storyboard<\/figcaption><\/figure><\/p>\n<h2>Conclusion<\/h2>\n<p>This article describes the Finite State Machine model and its application for complex page state transitions. If you decide to add the ability to change the color of items with animations, we recommend the article \u202f<a href=\"https:\/\/blog.xamarin.com\/building-custom-animations-in-xamarin-forms\/\">\u201cBuilding Custom Animations in Xamarin. Forms\u201d<\/a>.<\/p>\n<p>The full code of the demo project can be found in <a href=\"https:\/\/github.com\/binwell\/xamarinstatemachine\">this repository<\/a>.\t\t<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Using a Finite State Machine (a.k.a. FSM) and its appliance for complex page state transitions to create complex animations for Xamarin.Forms apps.<\/p>\n","protected":false},"author":803,"featured_media":40945,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[2,367],"tags":[851,589],"class_list":["post-38161","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-developers","category-xamarin-forms","tag-animations","tag-community"],"acf":[],"blog_post_summary":"<p>Using a Finite State Machine (a.k.a. FSM) and its appliance for complex page state transitions to create complex animations for Xamarin.Forms apps.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/posts\/38161","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/users\/803"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/comments?post=38161"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/posts\/38161\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/media\/40945"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/media?parent=38161"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/categories?post=38161"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/tags?post=38161"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}