Xamarin.Forms Floating Action Button NuGet Announcement

As promised, here is another release of one of my GitHub libraries for Xamarin! This time we are talking about the FloatingActionButton or “FAB”!

Here are some important links:

GitHub project: https://github.com/SuavePirate/Xamarin.Forms.Controls.FloatingActionButton
NuGet package: https://www.nuget.org/packages/SuaveControls.FloatingActionButton

Don’t forget to read up on my original post on how to create your own FloatingActionButton and how to use it: Xamarin.Controls – Xamarin.Forms FloatingActionButton (including iOS!)

Documentation


Xamarin.Forms.Controls.FloatingActionButton

A custom view to create a FloatingActionButton for both Android and iOS as part of Material Design

That’s right, even on iOS!

How to use

Clone the repository and open include the src projects in your Xamarin.Forms and Platform projects.

Now Available on NuGet!

Install-Package SuaveControls.FloatingActionButton

Special note for iOS: Make sure to call FloatingActionButtonRenderer.InitRenderer(); in your AppDelegate.cs in order to avoid linking it out.

Then you can include it in your XAML or call it from C# (See the example projects for a demo):

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:SuaveControls.FabExample"
             xmlns:controls="clr-namespace:SuaveControls.Views;assembly=SuaveControls.FloatingActionButton"
             x:Class="SuaveControls.FabExample.MainPage">
    <StackLayout Margin="32">
        <Label Text="This is a Floating Action Button!" 
           VerticalOptions="Center" 
           HorizontalOptions="Center"/>

        <controls:FloatingActionButton x:Name="FAB" HorizontalOptions="CenterAndExpand" WidthRequest="50" HeightRequest="50"  VerticalOptions="CenterAndExpand" Image="ic_add_white.png" ButtonColor="#03A9F4" Clicked="Button_Clicked"/>
    </StackLayout>
</ContentPage>

Android Example

Android Floating Action Button

iOS Example

iOS Floating Action Button

TODO:

  • Make it more flexible. Add Different color states, add sizing adjustments, etc.
  • Create UWP implementation
  • Create Xamarin Component

Come support the project and join the contributors list! We would love to see this TODO list dropped to nothing!

 

If you like what you see, don’t forget to follow me on twitter @Suave_Pirate, check out my GitHub, and subscribe to my blog to learn more mobile developer tips and tricks!

Interested in sponsoring developer content? Message @Suave_Pirate on twitter for details.

Advertisements

Xamarin.Controls – Xamarin.Forms FloatingActionButton (including iOS!)

You did actually read that title correctly – we have a FloatingActionButton to use in Xamarin.Forms that works in both Android and iOS!

I’ve put the source code up for this here: https://github.com/SuavePirate/Xamarin.Forms.Controls.FloatingActionButton

It’s rudimentary and has room for some more fun properties, but it is fully functional! If you would like to contribute to the repository, see the TODO: list at the bottom of the README and start forking and making pull requests!

To breakdown the steps to create your own Floating Action Button in Xamarin.Forms, you’ll need:

  1. A custom Xamarin.Forms `Element`
  2. An Android Custom renderer to use the native `Android.Compat.Design.Widgets.FloatingActionButton`
  3. An iOS Custom renderer to create a button that looks like a FAB.

So let’s go in that order.

In Xamarin.Forms PCL

FloatingActionButton.xaml.cs

  public partial class FloatingActionButton : Button
    {
        public static BindableProperty ButtonColorProperty = BindableProperty.Create(nameof(ButtonColor), typeof(Color), typeof(FloatingActionButton), Color.Accent);
        public Color ButtonColor
        {
            get
            {
                return (Color)GetValue(ButtonColorProperty);
            }
            set
            {
                SetValue(ButtonColorProperty, value);
            }
        }
        public FloatingActionButton()
        {
            InitializeComponent();
        }
    }

We added a new BindableProperty for the ButtonColor. This is done because setting the BackgroundColor will mess up the Android renderer and apply the background behind the FAB. We want to inherit from Button so that we can utilize some of the already useful properties that come with it – namely the Image property that consumes a FileImageSource. We can use this to set the icon for our FAB.

In Android

FloatingActionButtonRenderer.cs

using FAB = Android.Support.Design.Widget.FloatingActionButton;

[assembly: ExportRenderer(typeof(SuaveControls.Views.FloatingActionButton), typeof(FloatingActionButtonRenderer))]
namespace SuaveControls.FloatingActionButton.Droid.Renderers
{
    public class FloatingActionButtonRenderer : Xamarin.Forms.Platform.Android.AppCompat.ViewRenderer<SuaveControls.Views.FloatingActionButton, FAB>
    {
        protected override void OnElementChanged(ElementChangedEventArgs<SuaveControls.Views.FloatingActionButton> e)
        {
            base.OnElementChanged(e);

            if (e.NewElement == null)
                return;

            var fab = new FAB(Context);
            // set the bg
            fab.BackgroundTintList = ColorStateList.ValueOf(Element.ButtonColor.ToAndroid());

            // set the icon
            var elementImage = Element.Image;
            var imageFile = elementImage?.File;

            if (imageFile != null)
            {
                fab.SetImageDrawable(Context.Resources.GetDrawable(imageFile));
            }
            fab.Click += Fab_Click;
            SetNativeControl(fab);

        }
        protected override void OnLayout(bool changed, int l, int t, int r, int b)
        {
            base.OnLayout(changed, l, t, r, b);
            Control.BringToFront();
        }

        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            var fab = (FAB)Control;
            if (e.PropertyName == nameof(Element.ButtonColor))
            {
                fab.BackgroundTintList = ColorStateList.ValueOf(Element.ButtonColor.ToAndroid());
            }
            if (e.PropertyName == nameof(Element.Image))
            {
                var elementImage = Element.Image;
                var imageFile = elementImage?.File;

                if (imageFile != null)
                {
                    fab.SetImageDrawable(Context.Resources.GetDrawable(imageFile));
                }
            }
            base.OnElementPropertyChanged(sender, e);

        }

        private void Fab_Click(object sender, EventArgs e)
        {
            // proxy the click to the element
            ((IButtonController)Element).SendClicked();
        }
    }
}

A few important things to point out:

  • We add the additional using statement `using FAB = Android.Support.Design.Widget.FloatingActionButton;` to help us distinguish between our Xamarin.Forms element and the built in Android control.
  • We are NOT using a `ButtonRenderer` as our base class, but instead using a basic `ViewRenderer`. This is because the underlying control will not be a native Android `Button`, but the native Android `FloatingActionButton`.
  • Because we replace the `ButtonRenderer`, we need to make sure we still propagate click events up to the Xamarin.Forms element.

Now let’s look at iOS, which can utilize more of the built in pieces from Xamarin.Forms since it supports the BorderRadius property on Buttons.

In iOS

FloatingActionButtonRenderer.cs

[assembly: ExportRenderer(typeof(SuaveControls.Views.FloatingActionButton), typeof(FloatingActionButtonRenderer))]
namespace SuaveControls.FloatingActionButton.iOS.Renderers
{
    [Preserve]
    public class FloatingActionButtonRenderer : ButtonRenderer
    {
        public static void InitRenderer()
        {
        }
        public FloatingActionButtonRenderer()
        {
        }
        protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
        {
            base.OnElementChanged(e);

            if (e.NewElement == null)
                return;

            // remove text from button and set the width/height/radius
            Element.WidthRequest = 50;
            Element.HeightRequest = 50;
            Element.BorderRadius = 25;
            Element.BorderWidth = 0;
            Element.Text = null;

            // set background
            Control.BackgroundColor = ((SuaveControls.Views.FloatingActionButton)Element).ButtonColor.ToUIColor();
        }
        public override void Draw(CGRect rect)
        {
            base.Draw(rect);
            // add shadow
            Layer.ShadowRadius = 2.0f;
            Layer.ShadowColor = UIColor.Black.CGColor;
            Layer.ShadowOffset = new CGSize(1, 1);
            Layer.ShadowOpacity = 0.80f;
            Layer.ShadowPath = UIBezierPath.FromOval(Layer.Bounds).CGPath;
            Layer.MasksToBounds = false;

        }
        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);

            if (e.PropertyName == "ButtonColor")
            {
                Control.BackgroundColor = ((SuaveControls.Views.FloatingActionButton)Element).ButtonColor.ToUIColor();
            }
        }
    }
}

We set an explicit WidthRequest, HeightRequest, and BorderRadius to get ourselves a circle. I’m not a big fan of doing it here, since it’s better suited as a calculation, but for now it works.

Lastly in our Draw override, we set up the drop shadow behind out button, and make sure that our ShadowPath is actually built from an oval so that it rounds off with the Button.
Also note that we take the ButtonColor property and apply it as the BackgroundColor of the UIButton to override the color from Xamarin.Forms. Don’t forget to set Text to null so that we can’t add text to the button and mess it up.

As a side note, iOS might try to link our your custom renderer if you are using it in an iOS Class Library. In order to avoid this, make sure to call a static InitRenderer method in your AppDelegate.cs as it will prevent it from being linked out.

Using the FloatingActionButton

Now that we have our renderers registered for our new Element, we can use it in our XAML or C# of our PCL or Shared Project:

MainPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"              xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"              xmlns:local="clr-namespace:SuaveControls.FabExample"              xmlns:controls="clr-namespace:SuaveControls.Views;assembly=SuaveControls.FloatingActionButton"              x:Class="SuaveControls.FabExample.MainPage">
    <StackLayout Margin="32">
        <Label Text="This is a Floating Action Button!"             VerticalOptions="Center"             HorizontalOptions="Center"/>

        <controls:FloatingActionButton x:Name="FAB" HorizontalOptions="CenterAndExpand" WidthRequest="50" HeightRequest="50"  VerticalOptions="CenterAndExpand" Image="ic_add_white.png" ButtonColor="#03A9F4" Clicked="Button_Clicked"/>
    </StackLayout>
</ContentPage>

and our code behind:

MainPage.xaml.cs

namespace SuaveControls.FabExample
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();

        }

        private async void Button_Clicked(object sender, EventArgs e)
        {
            await DisplayAlert("FAB Clicked!", "Congrats on creating your FAB!", "Thanks!");
        }
    }
}

Then we get these results in our Android and iOS apps:

Android

Screenshot_1493173400

iOS

2017-04-25_10-38-38-PM

If you want to just pull down the control I built on GitHub, the steps are straight forward:

  1. Clone the repository
  2. Reference the PCL in your PCL/Shared Lib
  3. Reference the PCL and native projects in your respective native project
  4. Pull the namespace into your XAML (or C#)
  5. Start using it!

The repository also contains an example app that references the source libraries.

If you like what you see, don’t forget to follow me on twitter @Suave_Pirate, check out my GitHub, and subscribe to my blog to learn more mobile developer tips and tricks!

Interested in sponsoring developer content? Message @Suave_Pirate on twitter for details.