Visual State Transitions in Xamarin Forms with Animations

Visual State Transitions in Xamarin Forms with Animations

In previous posts (Visual States in Xamarin.Forms using BuildIt.Forms and Xamarin.Forms Visual States with View Models) I demonstrated how the BuildIt.Forms library (https://www.nuget.org/packages/BuildIt.Forms) could be used to declare visual states for pages, and controls, within Xamarin Forms. Today we just added some basic support for animations so that as you transition between visual states you can animate elements of the screen:

The following visual states define animations for rotating a green square:

<Grid HeightRequest=”100″ WidthRequest=”100″ x_Name=”AnimateGrid” HorizontalOptions=”Start” BackgroundColor=”Green” />

The Hide visual state defines three animations that run in parallel, with the rotation being a sequence of animations. The Show visual state has the reverse animations to return the green square to the original starting position. Unlike the setters, there’s no built in support for returning the element to its unchanged state.

<vsm:VisualStateManager.VisualStateGroups>
     <x:Array Type=”{x:Type vsm:VisualStateGroup}”>
         <vsm:VisualStateGroup Name=”SampleStates”>
             <vsm:VisualState Name=”Show”>
                 <vsm:VisualState.Animations>
                     <vsm:TranslateAnimation TranslationX=”0″ Duration=”500″ Target=”AnimateGrid”/>
                     <vsm:FadeAnimation Opacity=”1″ Duration=”500″ Target=”AnimateGrid”/>
                     <vsm:RotateAnimation Rotation=”0″ Duration=”500″ Target=”AnimateGrid”/>
                 </vsm:VisualState.Animations>
             </vsm:VisualState>
             <vsm:VisualState Name=”Hide”>
                 <vsm:VisualState.Setters>
                     <vsm:Setter Value=”false”
                                 Target=”WelcomeText.IsVisible” />
                 </vsm:VisualState.Setters>
                 <vsm:VisualState.Animations>
                     <vsm:ParallelAnimation>
                         <vsm:TranslateAnimation TranslationX=”200″ Duration=”3000″ Target=”AnimateGrid”/>
                         <vsm:FadeAnimation Opacity=”0.2″ Duration=”3000″ Target=”AnimateGrid”/>
                         <vsm:SequenceAnimation>
                             <vsm:RotateAnimation Rotation=”135″ Duration=”750″ Target=”AnimateGrid”/>
                             <vsm:RotateAnimation Rotation=”0″ Duration=”750″ Target=”AnimateGrid”/>
                             <vsm:RotateAnimation Rotation=”135″ Duration=”750″ Target=”AnimateGrid”/>
                             <vsm:RotateAnimation Rotation=”0″ Duration=”750″ Target=”AnimateGrid”/>
                         </vsm:SequenceAnimation>
                     </vsm:ParallelAnimation>
                 </vsm:VisualState.Animations>
             </vsm:VisualState>
         </vsm:VisualStateGroup>
     </x:Array>
</vsm:VisualStateManager.VisualStateGroups>

This is how these animations play out:

animations

Adding Fluent Design Acrylic Material to UWP via Xamarin.Forms.

Adding Fluent Design Acrylic Material to UWP via Xamarin.Forms.

At Build Microsoft made a big deal out of the new Fluent Design that they’re encouraging developers to start taking advantage of. Out of the box it’s a little harder to take advantage of these features but using BuildIt.Forms it’s easy to start using acrylic material resources. Let’s extend the example I’ve covered in the last couple of posts (Visual States in Xamarin.Forms using BuildIt.Forms and Xamarin.Forms Visual States with View Models). I’ve added a Grid, that will span the whole page (the StackLayout was positioned to keep all the elements in the centre of the page) and included the BackgroundEffect to set the background of the whole page.

<Grid>
     <Grid.Effects>
         <ctrls:BackgroundEffect Resource=”SystemControlAcrylicWindowBrush” />
     </Grid.Effects>

     <StackLayout VerticalOptions=”Center”
                     HorizontalOptions=”Center”>


        <Label x_Name=”WelcomeText”
                 Text=”{Binding WelcomeText}” />
         <StackLayout Orientation=”Horizontal”>
             <Button Text=”Show”
                     Clicked=”ShowClicked” />
             <Button Text=”Hide”
                     Clicked=”HideClicked” />
         </StackLayout>
     </StackLayout>

</Grid>

The Resource attribute defines the UWP brush resource that will be used as the background. In this case the SystemControlAcrylicWindowBrush is one of the build in arcylic brushes. As you can see the page appears as translucent, allowing what’s behind the app to taint the background of the app.

image

It’s also possible to use a custom acrylic resource, defined in the App.xaml of the UWP application

<Application
     x_Class=”FormsWithStates.UWP.App”
     http://schemas.microsoft.com/winfx/2006/xaml/presentation"”>http://schemas.microsoft.com/winfx/2006/xaml/presentation”
     http://schemas.microsoft.com/winfx/2006/xaml"”>http://schemas.microsoft.com/winfx/2006/xaml”
    
     RequestedTheme=”Light”>
     <Application.Resources>
         <ResourceDictionary>
             <ResourceDictionary.ThemeDictionaries>
                 <ResourceDictionary x_Key=”Default”>
                    <AcrylicBrush x_Key=”MyAcrylicBrush”
                                   BackgroundSource=”HostBackdrop”
                                   TintColor=”#FFFF0000″
                                   TintOpacity=”0.4″
                                   FallbackColor=”#FF7F0000″ />

                 </ResourceDictionary>


                <ResourceDictionary x_Key=”HighContrast”>
                     <SolidColorBrush x_Key=”MyAcrylicBrush”
                                      Color=”{ThemeResource SystemColorWindowColor}” />

                 </ResourceDictionary>


                <ResourceDictionary x_Key=”Light”>
                     <AcrylicBrush x_Key=”MyAcrylicBrush”
                                   BackgroundSource=”HostBackdrop”
                                   TintColor=”#FFFF0000″
                                   TintOpacity=”0.4″
                                   FallbackColor=”#FFFF7F7F” />

                 </ResourceDictionary>
             </ResourceDictionary.ThemeDictionaries>
         </ResourceDictionary>
     </Application.Resources>
</Application>

image

The BackgroundEffect also supports a FallbackColor attribute which can be used to set the background colour on all platforms.

Xamarin.Forms Visual States with View Models

Xamarin.Forms Visual States with View Models

In my previous post, Visual States in Xamarin.Forms using BuildIt.Forms, I showed how to use BuildIt.Forms (https://www.nuget.org/packages/BuildIt.Forms) to create visual states that can be used to define how the user interface changes to reflect different states of the page. The example demonstrated switching between visual states in the code behind with calls to VisualStateManager.GoToState. In this post I’m going to extend the example to allow the states to be switched from a view model.

I’ll start by creating a view model that will be data bound to the page. Usually I’d use a framework like MvvmCross to drive the view model/view instantiation but for this example I’ll keep it simple. I will however still put the view model in a separate project – again this promotes good separation between the view models and their associated view. I’ll create a new .NET Standard library, FormsWithStates.Core, and add a reference to it into the FormsWithStates.UI project.

image

I’ll add a new class to the project, MainViewModel, which will be the view model for the MainPage of the application. To track states within the view model, I need to add a reference to the BuildIt.States library on NuGet.

image

The MainViewModel will define a simple property WelcomeText to demonstrate that the view model is indeed data bound to the page. It also implements the interface IHasStates which defines a property StateManager – you can think of the IStateManager implementation as an object that can track states and state transitions.

public enum SampleStates
{
     Base,
     Show,
     Hide
}


public class MainViewModel : IHasStates
{
     public IStateManager StateManager { get; } = new StateManager();


    public string WelcomeText => “Welcome to Forms!”;


    public MainViewModel()
     {
         StateManager.Group<SampleStates>().DefineAllStates();
     }


    public void Show()
     {
         StateManager.GoToState(SampleStates.Show);
     }
     public void Hide()
     {
         StateManager.GoToState(SampleStates.Hide);
     }
}

The enumeration SampleStates defines the states that the MainViewModel references – both the enumeration and the states themselves have to match the names of the visual state group and visual states defined in the XAML for the page. The final step is to link the visual states on the page to the IStateManager instance, so that when there is a state change in the IStateManager, it will be reflected on the page via a change to the visual states. This is done by the Bind method on the VisualStateManager class.

public partial class MainPage : ContentPage
{
     private MainViewModel ViewModel { get; } = new MainViewModel();
     public MainPage()
     {
         InitializeComponent();


        BindingContext = ViewModel;
         VisualStateManager.Bind(this, ViewModel.StateManager);
     }


    public void ShowClicked(object sender, EventArgs e)
     {
         ViewModel.Show();
     }
     public void HideClicked(object sender, EventArgs e)
     {
         ViewModel.Hide();
     }
}

Whilst from the perspective of a user, there is no difference (since the Show and Hide buttons do the same thing), state management has been shifted to the view model where it can be tested. This separation of views and view models is important to ensure all application logic can be tested.

Visual States in Xamarin.Forms using BuildIt.Forms

Visual States in Xamarin.Forms using BuildIt.Forms

A couple of weeks ago I started building out some helpers to make working with Xamarin.Forms a little nicer (see Styling Pages and Controls in Xamarin Forms using Visual States,Rebuilding the Xamarin.Forms Button with Visual States and Control Templates and Ambient Properties in Xamarin.Forms). Since then we’ve been working on building out a library that encapsulates these features, again making it easier for us and others to build apps using Xamarin.Forms. There is now a pre-release version of BuildIt.Forms (https://www.nuget.org/packages/BuildIt.Forms) that anyone can reference to take advantage of these helpers. The library makes use of some methods/properties that are only available in the pre-release version of Xamarin.Forms, which is why we don’t have an actual release out yet.

In this post I’m going to walk through using visual states in a Xamarin.Forms project. To set the scene, I’m going to step through creating a new Xamarin.Forms project in Visual Studio 2017 (current RTM build, not the preview, although the preview build should be similar). I’ll do this in this post to make sure the basics of creating a Xamarin.Forms project that uses a .NET Standard Library instead of a PCL library is covered. I highly recommend switching to a .NET Standard library as soon as possible to avoid issues with upgrading nuget references etc (most third party library now have a .NET Standard version and it will become increasingly harder to maintain and update your old PCL libraries).

Ok, so let’s get started with a new project – I’m going with the Cross Platform App (Xamarin) template in the New Projects dialog:

image

Next, I’ll select the Blank App template, using Xamarin.Forms (UI Technology) and Portable Class Library (Code Sharing Strategy). Side note here – I highly recommend not using the Shared Project option for Code Sharing Strategy; using this option is a recipe for disaster as it promote poorly separated UI logic and allows for using conditional compilation based on #defines which is not a good strategy if you want maintainable code.

image

After clicking OK my solution has four projects: A PCL which has got the Xamarin.Forms UI defined in XAML files, and three “head” projects, one for each target platform. At this point, I would suggest running each project to make sure you have a working application before going any further (and commit this code to your source repository before going any further!)

image

Now to replace the PCL with a .NET Standard library. I’ll add a new .NET Standard class library. I like to make it clear that this library will contain the UI for my Xamarin.Forms project by using the .UI suffix. I do not include my view models in this library – I’ll talk about this in a subsequent post.

image

After creating the new class library, I just need to copy across the XAML and .cs files that were in the PCL library (App.xaml, App.xaml.cs, MainPage.xaml, MainPage.xaml.cs).  I can then remove the PCL library from the solution. Of course, I need to go through each of the head projects and add a reference to the UI project.

image

At this point I would again build and run the application on each platform – If you do this without doing anything the solution won’t compile as the UI library doesn’t have a reference to the Xamarin.Forms NuGet library. I suggest adding a reference to the Xamarin.Forms NuGet library and then upgrading any libraries where there is an update available. Again before proceeding, build and run each platform.

The next step is to add a reference to BuildIt.Forms. This is a prerelease library so you’ll need to check the “Include prerelease” option when searching. You need to add this library to all projects, even though you’ll only be adding code into the UI project – this makes sure the platform specific libraries that are included in BuildIt.Forms are correctly referenced and will be included.

image

As part of referencing BuildIt.Forms you will notice that the reference to Xamarin.Forms has also been updated to the prerelease version – as BuildIt.Forms takes advantage of some prerelease APIs this is unavoidable at the moment. The official release of BuildIt.Forms will not be available until the next drop of Xamarin.Forms where these APIs come out of prerelease.

Now we can start to make use of some of the helpers in BuildIt.Forms. In this case we’re going to use visual states in the XAML for the MainPage to hide and show a Label. The following XAML includes a Label and two Button elements. There are two visual states defined: Show and Hide (the actual names are only relevant when switching visual states, they have no bearing on what the visual states do). Note that the Show visual state doesn’t need to explicitly set the IsVisible property on the WelcomeText Label to true, since this is the default value for that property.

<?xml version=”1.0″ encoding=”utf-8″ ?>
<ContentPage http://xamarin.com/schemas/2014/forms"”>http://xamarin.com/schemas/2014/forms”
              http://schemas.microsoft.com/winfx/2009/xaml"”>http://schemas.microsoft.com/winfx/2009/xaml”
             
             
              x_Class=”FormsWithStates.MainPage”>
     <vsm:VisualStateManager.VisualStateGroups>
         <x:Array Type=”{x:Type vsm:VisualStateGroup}”>
             <vsm:VisualStateGroup Name=”SampleStates”>
                <vsm:VisualState Name=”Show” />
                 <vsm:VisualState Name=”Hide”>
                     <vsm:VisualState.Setters>
                         <vsm:Setter Value=”false”
                                     Target=”WelcomeText.IsVisible” />
                     </vsm:VisualState.Setters>
                 </vsm:VisualState>

             </vsm:VisualStateGroup>
         </x:Array>
     </vsm:VisualStateManager.VisualStateGroups>
     <StackLayout VerticalOptions=”Center”
                  HorizontalOptions=”Center”>
         <Label x_Name=”WelcomeText”
                Text=”Welcome to Xamarin Forms!” />
         <StackLayout Orientation=”Horizontal”>
             <Button Text=”Show”
                     Clicked=”ShowClicked” />
             <Button Text=”Hide”
                     Clicked=”HideClicked” />
         </StackLayout>
     </StackLayout>
</ContentPage>

The code for the event handlers for the two button is relatively simple:

public void ShowClicked(object sender, EventArgs e)
{
     VisualStateManager.GoToState(this, “Show”);
}
public void HideClicked(object sender, EventArgs e)
{
     VisualStateManager.GoToState(this, “Hide”);


}

And the final result is an interface that shows and hides the welcome text on the page:

imageimage

Feel free to try out the BuildIt.Forms library and get started using visual states within your Xamarin.Forms project.