Xamarin.Tip – Playing Audio Through the Earpiece in iOS

There is plenty of documentation from Xamarin on how to play audio files in our Xamarin.iOS apps (or Xamarin.Forms apps):

But none of these talk about piping the audio to either the speaker or the earpiece (the onboard one used for phone calls). Handling this logic is useful for applications that have a “voicemail” sort of feature or a real-time communications app. Here’s a brief bit of code that can handle playing an audio file through the speaker or through the earpiece:

AudioService.cs

 public class AudioService : IAudioService
    {
        public AudioService()
        {
        }

        public void PlaySoundThroughEarPiece(string fileName)
        {
            var session = AVAudioSession.SharedInstance();
            session.SetCategory(AVAudioSessionCategory.PlayAndRecord);
            session.SetActive(true);
            NSError error;
            var player = new AVAudioPlayer(new NSUrl(fileName), "mp3", out error);
            player.Volume = 1.0f;
            player.Play();

        }

        public void PlaySoundThroughSpeaker(string fileName)
        {
            var session = AVAudioSession.SharedInstance();
            session.SetCategory(AVAudioSessionCategory.Playback);
            session.SetActive(true);
            NSError error;
            var player = new AVAudioPlayer(new NSUrl(fileName), "mp3", out error);
            player.Volume = 1.0f;
            player.Play();
            
        }
    }

The key is calling the SetCategory with the appropriate AVAudioSessionCategory and setting the session to active before playing the sound through the AVAudioPlayer.

and you can call it like so:

var audioService = new AudioService();
audioService.PlaySoundThroughEarPiece("sample_sound.mp3");
audioService.PlaySoundThroughSpeaker("sample_sound.mp3");

Check out an example of this on my GitHub here in Xamarin.Forms: https://github.com/SuavePirate/XamarinEarpieceAudioTest

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.

Xamarin.Tip – Borderless Editor

I previously put out a post on removing the border of a Xamarin.Forms Entry which was then used to create a custom PinView as well as a MaterialEntry that follows the material design standards for text fields. Check those out here:

In this post, we’ll apply some of the same principles to create a BorderlessEditor. It’s going to use a simple custom renderer, although this could and should be done using an Effect if being used on its own. However, this BorderlessEditor will be the foundation for future controls.

You can find this code as part of my library in progress to create Material Design Form controls for Xamarin.Forms – https://github.com/SuavePirate/SuaveControls.MaterialFormControls.

Let’s get started with our custom control by first creating a custom subclass of Xamarin.Forms.Editor followed by a custom renderer class for iOS, Android, and UWP that kills the border.

BorderlessEditor.cs

namespace SuaveControls.MaterialForms
{
    public class BorderlessEditor : Editor
    {
    }
}

Nothing special here since we are using the default behavior of the Editor.

Android

Now let’s create an Android custom renderer.

BorderlessEditorRenderer.cs – Android

[assembly: ExportRenderer(typeof(BorderlessEditor), typeof(BorderlessEditorRenderer))]
namespace SuaveControls.MaterialForms.Android.Renderers
{
    public class BorderlessEditorRenderer : EditorRenderer
    {
        public static void Init() { }
        protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
        {
            base.OnElementChanged(e);
            if (e.OldElement == null)
            {
                Control.Background = null;

                var layoutParams = new MarginLayoutParams(Control.LayoutParameters);
                layoutParams.SetMargins(0, 0, 0, 0);
                LayoutParameters = layoutParams;
                Control.LayoutParameters = layoutParams;
                Control.SetPadding(0, 0, 0, 0);
                SetPadding(0, 0, 0, 0);
            }
        }
    }
}

We simple kill the default padding and margins while setting the Background property to null. This Background is what creates the drawable underline for the AppCompat Editor.

iOS

Follow with an iOS renderer.

BorderlessEditorRenderer.cs – iOS

[assembly: ExportRenderer(typeof(BorderlessEditor), typeof(BorderlessEditorRenderer))]
namespace SuaveControls.MaterialForms.iOS.Renderers
{
    public class BorderlessEditorRenderer : EditorRenderer
    {
        public static void Init() { }
        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);

            Control.Layer.BorderWidth = 0;
        }
    }
}

All we do here is set the BorderWidth to 0.

UWP

Lastly a renderer for UWP

BorderlessEditorRenderer.cs – UWP


[assembly: ExportRenderer(typeof(BorderlessEditor), typeof(BorderlessEditorRenderer))]

namespace SuaveControls.MaterialForms.UWP.Renderers
{
    public class BorderlessEditorRenderer : EditorRenderer
    {
        public static void Init() { }
        protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
        {
            base.OnElementChanged(e);

            if (Control != null)
            {
                Control.BorderThickness = new Windows.UI.Xaml.Thickness(0);
                Control.Margin = new Windows.UI.Xaml.Thickness(0);
                Control.Padding = new Windows.UI.Xaml.Thickness(0);
            }
        }
    }
}

Similar to how we did it on Android, we set both the Margin and Padding to 0 and also set the BorderThickness to a 0’d Thickness.

Using the BorderlessEditor

Now you can use the BorderlessEditor in your XAML or C# code:

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:ExampleMaterialApp"
             xmlns:suave="clr-namespace:SuaveControls.MaterialForms;assembly=SuaveControls.MaterialForms"
             x:Class="ExampleMaterialApp.MainPage">

    <ScrollView>
        <StackLayout Spacing="16" Margin="16" BackgroundColor="Blue">
            <Label Text="Borderless Editor!" Margin="32" HorizontalOptions="Center" HorizontalTextAlignment="Center"/>
            <suave:BorderlessEditor BackgroundColor="Black" TextColor="White" HeightRequest="300" Margin="32"/>

        </StackLayout>
    </ScrollView>

</ContentPage>

Check out those results on iOS:

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.

Xamarin.Tip – Borderless TimePicker

I previously put out a post on removing the border of a Xamarin.Forms Entry which was then used to create a custom PinView as well as a MaterialEntry that follows the material design standards for text fields. I also added a post just like this one that talks about creating a BorderlessPicker. Check those out here:

In this post, we’ll do exactly what we did with the BorderlessPicker, but apply it to the Xamarin.Forms.TimePicker control to remove the border. This would ideally be done using an Effect, however we will be using this control in a later post to create a MaterialTimePicker to fit the Material Design standards for form inputs, so we will create custom renderers for Android, iOS, and UWP.

You can find this code as part of my library in progress to create Material Design Form controls for Xamarin.Forms – https://github.com/SuavePirate/SuaveControls.MaterialFormControls.

Let’s get started with our custom control by first creating a custom subclass of Xamarin.Forms.TimePicker followed by a custom renderer class for iOS, Android, and UWP that kills the border.

BorderlessTimePicker.cs

namespace SuaveControls.MaterialForms
{
    public class BorderlessTimePicker : TimePicker
    {
    }
}

Nothing special here since we are using the default behavior of the TimePicker.

Android

Now let’s create an Android custom renderer.

BorderlessTimePickerRenderer.cs – Android

[assembly: ExportRenderer(typeof(BorderlessTimePicker), typeof(BorderlessTimePickerRenderer))]
namespace SuaveControls.MaterialForms.Android.Renderers
{
    public class BorderlessTimePickerRenderer : TimePickerRenderer
    {
        public static void Init() { }
        protected override void OnElementChanged(ElementChangedEventArgs<TimePicker> e)
        {
            base.OnElementChanged(e);
            if (e.OldElement == null)
            {
                Control.Background = null;

                var layoutParams = new MarginLayoutParams(Control.LayoutParameters);
                layoutParams.SetMargins(0, 0, 0, 0);
                LayoutParameters = layoutParams;
                Control.LayoutParameters = layoutParams;
                Control.SetPadding(0, 0, 0, 0);
                SetPadding(0, 0, 0, 0);
            }
        }
    }
}

We simple kill the default padding and margins while setting the Background property to null. This Background is what creates the drawable underline for the AppCompat TimePicker.

iOS

Follow with an iOS renderer.

BorderlessTimePickerRenderer.cs – iOS

[assembly: ExportRenderer(typeof(BorderlessTimePicker), typeof(BorderlessTimePickerRenderer))]
namespace SuaveControls.MaterialForms.iOS.Renderers
{
    public class BorderlessTimePickerRenderer : TimePickerRenderer
    {
        public static void Init() { }
        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);

            Control.Layer.BorderWidth = 0;
            Control.BorderStyle = UITextBorderStyle.None;
        }
    }
}

All we do here is set the BorderWidth to 0 and the BorderStyle to UITextBorderStyle.None.

UWP

Lastly a renderer for UWP

BorderlessTimePickerRenderer.cs – UWP


[assembly: ExportRenderer(typeof(BorderlessTimePicker), typeof(BorderlessTimePickerRenderer))]

namespace SuaveControls.MaterialForms.UWP.Renderers
{
    public class BorderlessTimePickerRenderer : TimePickerRenderer
    {
        public static void Init() { }
        protected override void OnElementChanged(ElementChangedEventArgs<TimePicker> e)
        {
            base.OnElementChanged(e);

            if (Control != null)
            {
                Control.BorderThickness = new Windows.UI.Xaml.Thickness(0);
                Control.Margin = new Windows.UI.Xaml.Thickness(0);
                Control.Padding = new Windows.UI.Xaml.Thickness(0);
            }
        }
    }
}

Similar to how we did it on Android, we set both the Margin and Padding to 0 and also set the BorderThickness to a 0’d Thickness.

Using the BorderlessTimePicker

Now you can use the BorderlessTimePicker in your XAML or C# code:

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:ExampleMaterialApp"
             xmlns:suave="clr-namespace:SuaveControls.MaterialForms;assembly=SuaveControls.MaterialForms"
             x:Class="ExampleMaterialApp.MainPage">

    <ScrollView>
        <StackLayout Spacing="16" Margin="16">
            <Label Text="Borderless TimePicker!" Margin="32" HorizontalOptions="Center" HorizontalTextAlignment="Center"/>
            <suave:BorderlessTimePicker/>

        </StackLayout>
    </ScrollView>

</ContentPage>

Check out those results on iOS:

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.

Xamarin.Tip – Borderless DatePicker

I previously put out a post on removing the border of a Xamarin.Forms Entry which was then used to create a custom PinView as well as a MaterialEntry that follows the material design standards for text fields. I also added a post just like this one that talks about creating a BorderlessPicker. Check those out here:

In this post, we’ll do exactly what we did with the BorderlessPicker, but apply it to the Xamarin.Forms.DatePicker control to remove the border. This would ideally be done using an Effect, however we will be using this control in a later post to create a MaterialDatePicker to fit the Material Design standards for form inputs, so we will create custom renderers for Android, iOS, and UWP.

You can find this code as part of my library in progress to create Material Design Form controls for Xamarin.Forms – https://github.com/SuavePirate/SuaveControls.MaterialFormControls.

Let’s get started with our custom control by first creating a custom subclass of Xamarin.Forms.DatePicker followed by a custom renderer class for iOS, Android, and UWP that kills the border.

BorderlessDatePicker.cs

namespace SuaveControls.MaterialForms
{
    public class BorderlessDatePicker : DatePicker
    {
    }
}

Nothing special here since we are using the default behavior of the DatePicker.

Android

Now let’s create an Android custom renderer.

BorderlessDatePickerRenderer.cs – Android

[assembly: ExportRenderer(typeof(BorderlessDatePicker), typeof(BorderlessDatePickerRenderer))]
namespace SuaveControls.MaterialForms.Android.Renderers
{
    public class BorderlessDatePickerRenderer : DatePickerRenderer
    {
        public static void Init() { }
        protected override void OnElementChanged(ElementChangedEventArgs<DatePicker> e)
        {
            base.OnElementChanged(e);
            if (e.OldElement == null)
            {
                Control.Background = null;

                var layoutParams = new MarginLayoutParams(Control.LayoutParameters);
                layoutParams.SetMargins(0, 0, 0, 0);
                LayoutParameters = layoutParams;
                Control.LayoutParameters = layoutParams;
                Control.SetPadding(0, 0, 0, 0);
                SetPadding(0, 0, 0, 0);
            }
        }
    }
}

We simple kill the default padding and margins while setting the Background property to null. This Background is what creates the drawable underline for the AppCompat DatePicker.

iOS

Follow with an iOS renderer.

BorderlessDatePickerRenderer.cs – iOS

[assembly: ExportRenderer(typeof(BorderlessDatePicker), typeof(BorderlessDatePickerRenderer))]
namespace SuaveControls.MaterialForms.iOS.Renderers
{
    public class BorderlessDatePickerRenderer : DatePickerRenderer
    {
        public static void Init() { }
        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);

            Control.Layer.BorderWidth = 0;
            Control.BorderStyle = UITextBorderStyle.None;
        }
    }
}

All we do here is set the BorderWidth to 0 and the BorderStyle to UITextBorderStyle.None.

UWP

Lastly a renderer for UWP

BorderlessDatePickerRenderer.cs – UWP


[assembly: ExportRenderer(typeof(BorderlessDatePicker), typeof(BorderlessDatePickerRenderer))]

namespace SuaveControls.MaterialForms.UWP.Renderers
{
    public class BorderlessDatePickerRenderer : DatePickerRenderer
    {
        public static void Init() { }
        protected override void OnElementChanged(ElementChangedEventArgs<DatePicker> e)
        {
            base.OnElementChanged(e);

            if (Control != null)
            {
                Control.BorderThickness = new Windows.UI.Xaml.Thickness(0);
                Control.Margin = new Windows.UI.Xaml.Thickness(0);
                Control.Padding = new Windows.UI.Xaml.Thickness(0);
            }
        }
    }
}

Similar to how we did it on Android, we set both the Margin and Padding to 0 and also set the BorderThickness to a 0’d Thickness.

Using the BorderlessDatePicker

Now you can use the BorderlessDatePicker in your XAML or C# code:

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:ExampleMaterialApp"
             xmlns:suave="clr-namespace:SuaveControls.MaterialForms;assembly=SuaveControls.MaterialForms"
             x:Class="ExampleMaterialApp.MainPage">

    <ScrollView>
        <StackLayout Spacing="16" Margin="16">
            <Label Text="Borderless DatePicker!" Margin="32" HorizontalOptions="Center" HorizontalTextAlignment="Center"/>
            <suave:BorderlessDatePicker/>

        </StackLayout>
    </ScrollView>

</ContentPage>

Check out those results on iOS:

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.

Xamarin.Tip – Borderless Picker

I previously put out a post on removing the border of a Xamarin.Forms Entry which was then used to create a custom PinView as well as a MaterialEntry that follows the material design standards for text fields. Check those out here:

In this post, we’ll apply some of the same principles to create a BorderlessPicker. It’s going to use a simple custom renderer, although this could and should be done using an Effect if being used on its own. However, this BorderlessPicker will be the foundation for future controls we will create such as the MaterialPicker that applies Material Design standards to the Xamarin.Forms Picker control on Android, iOS, and UWP.

You can find this code as part of my library in progress to create Material Design Form controls for Xamarin.Forms – https://github.com/SuavePirate/SuaveControls.MaterialFormControls.

Let’s get started with our custom control by first creating a custom subclass of Xamarin.Forms.Picker followed by a custom renderer class for iOS, Android, and UWP that kills the border.

BorderlessPicker.cs

namespace SuaveControls.MaterialForms
{
    public class BorderlessPicker : Picker
    {
    }
}

Nothing special here since we are using the default behavior of the Picker.

Android

Now let’s create an Android custom renderer.

BorderlessPickerRenderer.cs – Android

[assembly: ExportRenderer(typeof(BorderlessPicker), typeof(BorderlessPickerRenderer))]
namespace SuaveControls.MaterialForms.Android.Renderers
{
    public class BorderlessPickerRenderer : PickerRenderer
    {
        public static void Init() { }
        protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
        {
            base.OnElementChanged(e);
            if (e.OldElement == null)
            {
                Control.Background = null;

                var layoutParams = new MarginLayoutParams(Control.LayoutParameters);
                layoutParams.SetMargins(0, 0, 0, 0);
                LayoutParameters = layoutParams;
                Control.LayoutParameters = layoutParams;
                Control.SetPadding(0, 0, 0, 0);
                SetPadding(0, 0, 0, 0);
            }
        }
    }
}

We simple kill the default padding and margins while setting the Background property to null. This Background is what creates the drawable underline for the AppCompat Picker.

iOS

Follow with an iOS renderer.

BorderlessPickerRenderer.cs – iOS

[assembly: ExportRenderer(typeof(BorderlessPicker), typeof(BorderlessPickerRenderer))]
namespace SuaveControls.MaterialForms.iOS.Renderers
{
    public class BorderlessPickerRenderer : PickerRenderer
    {
        public static void Init() { }
        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);

            Control.Layer.BorderWidth = 0;
            Control.BorderStyle = UITextBorderStyle.None;
        }
    }
}

All we do here is set the BorderWidth to 0 and the BorderStyle to UITextBorderStyle.None.

UWP

Lastly a renderer for UWP

BorderlessPickerRenderer.cs – UWP


[assembly: ExportRenderer(typeof(BorderlessPicker), typeof(BorderlessPickerRenderer))]

namespace SuaveControls.MaterialForms.UWP.Renderers
{
    public class BorderlessPickerRenderer : PickerRenderer
    {
        public static void Init() { }
        protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
        {
            base.OnElementChanged(e);

            if (Control != null)
            {
                Control.BorderThickness = new Windows.UI.Xaml.Thickness(0);
                Control.Margin = new Windows.UI.Xaml.Thickness(0);
                Control.Padding = new Windows.UI.Xaml.Thickness(0);
            }
        }
    }
}

Similar to how we did it on Android, we set both the Margin and Padding to 0 and also set the BorderThickness to a 0’d Thickness.

Using the BorderlessPicker

Now you can use the BorderlessPicker in your XAML or C# code:

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:ExampleMaterialApp"
             xmlns:suave="clr-namespace:SuaveControls.MaterialForms;assembly=SuaveControls.MaterialForms"
             x:Class="ExampleMaterialApp.MainPage">

    <ScrollView>
        <StackLayout Spacing="16" Margin="16">
            <Label Text="Borderless Picker!" Margin="32" HorizontalOptions="Center" HorizontalTextAlignment="Center"/>
            <suave:BorderlessPicker x:Name="PickerDemo" Title="Options"/>

        </StackLayout>
    </ScrollView>

</ContentPage>

MainPage.xaml.cs

    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();

            PickerDemo.ItemsSource = new List<string>
            {
                "Option 1",
                "Option 2",
                "Option 3",
                "Option 4"
            };
        }
    }

Check out those results on iOS:

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.

Xamarin.Control – Xamarin.Forms MaterialEntry

Back by popular demand, bringing more Material Design controls to you Xamarin.Forms app! This time we will look at implementing the standards in Material Design’s text fields by building a MaterialEntry control. You can find the source code and example app here: https://github.com/SuavePirate/MaterialEntry but you can build your own by following this post.

Let’s build our Xamarin.Forms control to work the same on not only Android where Material Design is baked in, but also to run on iOS AND UWP. In the end, we should be able to use our floating label, set an accent color that expands on the label and underline when focused while being able to bind these properties through MVVM.

Simulator Screen Shot Jul 14, 2017, 3.42.03 PM

The first thing we need to do is create a BorderlessEntry that removes the border from our entry on all 3 platforms. I’ve done this in a previous blog post here: Xamarin.Forms Borderless Entry, so we won’t be implementing it here. This code is also in the GitHub link above.

With our BorderlessEntry we can now create our custom control WITHOUT ANY MORE CUSTOM RENDERERS!

Let’s set up the layout structure in our XAML file, and then wire up the animation logic in our code behind.

MaterialEntry.xaml

<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"               xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"              xmlns:local="clr-namespace:SuaveControls.MaterialEntry"              x:Class="SuaveControls.MaterialEntry.MaterialEntry">
  <ContentView.Content>
        <Grid ColumnSpacing="16" Margin="0,8">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="1"/>
            </Grid.RowDefinitions>
            <Label x:Name="HiddenLabel" FontSize="10" IsVisible="False" Margin="0"/>
            <local:BorderlessEntry x:Name="EntryField" Text="{Binding Text, Mode=TwoWay}" Margin="0,12,0,0"/>
            <BoxView x:Name="BottomBorder" BackgroundColor="Gray"  Grid.Row="1" HeightRequest="1" Margin="0" HorizontalOptions="FillAndExpand"/>
            <BoxView x:Name="HiddenBottomBorder" BackgroundColor="Gray" Grid.Row="1" HeightRequest="1" Margin="0" WidthRequest="0" HorizontalOptions="Center"/>
        </Grid>
    </ContentView.Content>
</ContentView>

We set up our BorderlessEntry that will act as our formal point for entering text. We also add a label that is initially hidden and laid out on top of the BorderlessEntry. This is the label we will be using to animate the floating action that Material Design uses based while we fade out the placeholder text. The last bit is two BoxViews that act as the bottom line below the Entry. One is the unfocused which has a standard gray color, while the other has a width of 0 and will have a background color of our selected AccentColor. This will have an animated width expansion when the BorderlessEntry is focused.

Now let’s look at the animation and bindings in the code behind:

MaterialEntry.xaml.cs

public partial class MaterialEntry : ContentView
    {
        public static void Init() { }
        public static BindableProperty TextProperty = BindableProperty.Create(nameof(Text), typeof(string), typeof(MaterialEntry), defaultBindingMode: BindingMode.TwoWay);
        public static BindableProperty PlaceholderProperty = BindableProperty.Create(nameof(Placeholder), typeof(string), typeof(MaterialEntry), defaultBindingMode: BindingMode.TwoWay, propertyChanged: (bindable, oldVal, newval) =>
        {
            var matEntry = (MaterialEntry)bindable;
            matEntry.EntryField.Placeholder = (string)newval;
            matEntry.HiddenLabel.Text = (string)newval;
        });

        public static BindableProperty IsPasswordProperty = BindableProperty.Create(nameof(IsPassword), typeof(bool), typeof(MaterialEntry), defaultValue: false, propertyChanged: (bindable, oldVal, newVal) =>
        {
            var matEntry = (MaterialEntry)bindable;
            matEntry.EntryField.IsPassword = (bool)newVal;
        });
        public static BindableProperty KeyboardProperty = BindableProperty.Create(nameof(Keyboard), typeof(Keyboard), typeof(MaterialEntry), defaultValue: Keyboard.Default, propertyChanged: (bindable, oldVal, newVal) =>
        {
            var matEntry = (MaterialEntry)bindable;
            matEntry.EntryField.Keyboard = (Keyboard)newVal;
        });
        public static BindableProperty AccentColorProperty = BindableProperty.Create(nameof(AccentColor), typeof(Color), typeof(MaterialEntry), defaultValue: Color.Accent);
        public Color AccentColor
        {
            get
            {
                return (Color)GetValue(AccentColorProperty);
            }
            set
            {
                SetValue(AccentColorProperty, value);
            }
        }
        public Keyboard Keyboard
        {
            get
            {
                return (Keyboard)GetValue(KeyboardProperty);
            }
            set
            {
                SetValue(KeyboardProperty, value);
            }
        }

        public bool IsPassword
        {
            get
            {
                return (bool)GetValue(IsPasswordProperty);
            }
            set
            {
                SetValue(IsPasswordProperty, value);
            }
        }

        public string Text
        {
            get
            {
                return (string)GetValue(TextProperty);
            }
            set
            {
                SetValue(TextProperty, value);
            }
        }
        public string Placeholder
        {
            get
            {
                return (string)GetValue(PlaceholderProperty);
            }
            set
            {
                SetValue(PlaceholderProperty, value);
            }
        }
        public MaterialEntry()
        {
            InitializeComponent();
            EntryField.BindingContext = this;
            EntryField.Focused += async (s, a) =>
            {
                HiddenBottomBorder.BackgroundColor = AccentColor;
                HiddenLabel.TextColor = AccentColor;
                HiddenLabel.IsVisible = true;
                if (string.IsNullOrEmpty(EntryField.Text))
                {
                    // animate both at the same time
                    await Task.WhenAll(
                        HiddenBottomBorder.LayoutTo(new Rectangle(BottomBorder.X, BottomBorder.Y, BottomBorder.Width, BottomBorder.Height), 200),
                        HiddenLabel.FadeTo(1, 60),
                        HiddenLabel.TranslateTo(HiddenLabel.TranslationX, EntryField.Y - EntryField.Height + 4, 200, Easing.BounceIn)
                     );
                    EntryField.Placeholder = null;
                }
                else
                {
                    await HiddenBottomBorder.LayoutTo(new Rectangle(BottomBorder.X, BottomBorder.Y, BottomBorder.Width, BottomBorder.Height), 200);
                }
            };
            EntryField.Unfocused += async (s, a) =>
            {
                HiddenLabel.TextColor = Color.Gray;
                if (string.IsNullOrEmpty(EntryField.Text))
                {
                    // animate both at the same time
                    await Task.WhenAll(
                        HiddenBottomBorder.LayoutTo(new Rectangle(BottomBorder.X, BottomBorder.Y, 0, BottomBorder.Height), 200),
                        HiddenLabel.FadeTo(0, 180),
                        HiddenLabel.TranslateTo(HiddenLabel.TranslationX, EntryField.Y, 200, Easing.BounceIn)
                     );
                    EntryField.Placeholder = Placeholder;
                }
                else
                {
                    await HiddenBottomBorder.LayoutTo(new Rectangle(BottomBorder.X, BottomBorder.Y, 0, BottomBorder.Height), 200);
                }
            };
        }
    }

We first set up the BindableProperties and public properties to enable the binding of the AccentColor, Text, Placeholder, and Keyboard. These BindableProperties also handle their own PropertyChanged events to update the view elements dynamically.

After that, we handle our constructor and wire up our Focused and Unfocused events on our BorderlessEntry. In the Focused event, we set the colors of the hidden bar, and the floating label to the accent color. We then start the animations of expanding the hidden bar, and the fade in and float up of the floating label.

On the Unfocused event, we do the inverse of setting the floating label color back to the unfocused color, check if there is text, if there is not – float the label back down, and then animate the collapse of the colored bar.

With all these things together, we get a nicely animated text field that has a floating label and expanding bottom bar with a given accent color!

ios_Material_Entry2

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.

Xamarin.Basics – Ad Hoc iOS Builds, Part 2a: Publishing in HockeyApp

Before Getting Started

Before learning how to upload your iOS builds to HockeyApp, be sure to check out Part 1 of this series: Xamarin.Basics – Ad Hoc iOS Builds, Part1: Certificates and Profiles to learn about the requirements for producing Ad Hoc builds that will be distributed in HockeyApp.

Quick Intro

Up to this point, we should have everything we need to build our iOS application in Release/Ad Hoc mode to produce an .ipa file. This output .ipa is what we will be uploading to HockeyApp and other distribution channels such as Mobile Center. It’s important to note that HockeyApp is actually on its way out the door and being booted by the new Visual Studio Mobile Center produced by Microsoft after acquiring HockeyApp and their team. At this point, Mobile Center is still in Preview, so if you’re looking for a production ready solution for the time being, stay here. If not, follow my next blog post (to be posted here) on doing this in Mobile Center.

Building

Now that we have our Distribution Certificate and Ad Hoc Provisioning Profile created in the Apple Developer Portal and downloaded on our Mac, we can move into Visual Studio and build our Application for Ad Hoc Release. The screenshots you’ll see below will be from Visual Studio 2017 on Windows, but the same principles apply to Visual Studio for Mac.

Ensure your Bundle Identifiers Match

In the Apple Developer portal, we created an App ID and in this definition, we set a Bundle Identifier. This ID needs to match the ID of our actual application. You can set the Bundle Identifier in the Info.plist file of your iOS project in Visual Studio.

Screen Shot 2017-07-12 at 1.54.00 PM

Set Build Configuration to Release – iPhone

Screen Shot 2017-07-12 at 2.07.06 PM

In order to build for iOS Ad Hoc distribution, you’ll need to build against an actual iOS device. Building for simulators does some things differently behind the scenes that makes it faster to install in a simulator. Since our app needs to run against devices, we need to build against a real device. We also need to build in Release mode since we shouldn’t be debugging an Ad Hoc build.

Double Check Your Bundle Signing

Before building, double check that your app is going to use the proper Signing Identity and Provisioning Profile. You can do this by opening the Properties (“Options” if your in VS for Mac) and go to the Bundle Signing tab. Here you can explicitly set a Profile and Certificate to use or let it automatically choose the profile and hope it works out.

Screen Shot 2017-07-12 at 2.12.12 PM.png

Build and Deploy

Now simply build and deploy your app by right clicking the project in the Solution Explorer and clicking the Deploy option.

Screen Shot 2017-07-12 at 2.21.49 PM

This will now create the .ipa file in your bin. Locate your .ipa at YOUR_IOS_PROJECT\bin\Ad-Hoc\YOUR_BUNDLE.ipa. This .ipa is what will be uploaded to HockeyApp and distributed.

Using HockeyApp

HockeyApp has some great getting started documentation for creating your app and also viewing crash reports etc. You can find that here: https://support.hockeyapp.net/kb.

We will focus on uploading a new build using the .ipa file we created. In order to do this, you will need to have created an account with HockeyApp and created an iOS Alpha or Beta application slot.

From here you can click on the Add Version button which will then prompt you to upload your .ipa file.

Screen Shot 2017-07-12 at 2.39.05 PMScreen Shot 2017-07-12 at 2.39.12 PM

Now you’ll be able to add some release notes to your version that is being uploaded. Then enable the people who are allowed to install your app and send them notifications.

Once this is done, your users whose devices are registered by their UDID to the Apple Developer Portal and the Provisioning Profile used will be able to download and install it through the HockeyApp mobile website!

With your users having their hands on the app, you’ll be able to view crash reports, respond to feedback and more through the HockeyApp portal!

Next Steps

Now that we’ve been able to manually upload builds to HockeyApp, we’ll be able to look at using Continuous Integration and Deployment to distribute our new versions as we commit our changes in the source code. James Montemagno has a great blog post in the official Xamarin blog here: https://blog.xamarin.com/continuous-integration-for-ios-apps-with-visual-studio-team-services/.

In a following post, we will look at the future of deploying our iOS applications internally by using the new Visual Studio Mobile Center.

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.

[Video] Xamarin.Basics – Ad Hoc iOS Builds, Part 1: Certificates and Profiles

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.

Xamarin.Basics – Ad Hoc iOS Builds, Part 1: Certificates and Profiles

For those who are newer to iOS application development and are trying to run their app on devices or deploy it to others’ devices, let me first offer you my condolences. Now let’s look at the overwhelming number of steps required to do a basic build on an iOS device!

Resources Required Before Starting

  1. A Mac. You can’t do this without an actual Mac device running OSX
  2. XCode installed on the Mac
  3. An Apple Developer license (read below)

Join the Apple Developer Program

In order to distribute apps, you’ll need to create certificates and profiles in the end. Before you can do that, you’ll need to join the Apple developer program for iOS. Keep in mind, this can take time (multiple days).

Head over to https://developer.apple.com/programs/ and click on the Enroll button.

apple_enroll

You’ll see an intimidating following something like this:

Enrolling as an Individual

If you are an individual or sole proprietor/single person business, sign in with your Apple ID to get started. You’ll need to provide basic personal information, including your legal name and address.

Enrolling as an Organization

If you’re enrolling your organization, you’ll need an Apple ID as well as the following to get started:

 
A D-U-N-S® Number

Your organization must have a D-U-N-S Number so that we can verify your organization’s identity and legal entity status. These unique nine-digit numbers are assigned by Dun & Bradstreet and are widely used as standard business identifiers. You can check to see if your organization already has a D-U-N-S Number and request one if necessary. They are free in most jurisdictions. Learn more

 
Legal Entity Status

Your organization must be a legal entity so that it can enter into contracts with Apple. We do not accept DBAs, fictitious businesses, trade names, or branches.

Legal Binding Authority

As the person enrolling your organization in the Apple Developer Program, you must have the legal authority to bind your organization to legal agreements. You must be the organization’s owner/founder, executive team member, senior project lead, or have legal authority granted to you by a senior employee.

Follow all the steps for either an individual or organization. PS. This costs about $100 (as of June 2017). Once you’ve submitted your enrollment application, an Apple employee will review your request and get back to you within 1-2 business days (usually) with your accepted (or declined) enrollment. Once this is done, you’ll be able to access the developer portal where you can add other members of your organization, manage certificates, apps, devices, and profiles.

Getting the Proper Requirements for Ad Hoc

Now that you can access the portal, go to the Developer portal and click on Account to sign in with your Apple ID.

After signing in, you’ll see some options on the left navigation bar. Click on Certificates, IDs, and Profiles

Components You Will Get From This Post

There are 4 major components you will need in order to be able to deploy an app to multiple devices:

  1. An App ID
  2. An Ad Hoc Certificate – created, downloaded, and installed on the machine.
  3. The UDIDs of every iOS device that will run the app
  4. A Provisioning Profile that combines all three things

Creating an App ID

In the developer portal Certificates, IDs, and Profiles section, click on App IDs from the left menu, then click the plus button in the top right:
Screen Shot 2017-06-21 at 10.33.47 AMScreen Shot 2017-06-21 at 10.23.59 AMScreen Shot 2017-06-21 at 10.24.04 AM

Then fill out the fields for Name and Bundle Identifier.
Screen Shot 2017-06-21 at 10.24.22 AMScreen Shot 2017-06-21 at 10.24.36 AM

Scroll on down and select the additional App Services this app will need to support:Screen Shot 2017-06-21 at 10.24.50 AM

Click Continue and you’ll be done creating your App ID and can continue to creating a certificate.

Creating a Distribution Certificate

Over in the left navigation, click on Certificates > Production then click the plus button in the top right:Screen Shot 2017-06-21 at 10.25.06 AMScreen Shot 2017-06-21 at 10.25.10 AM

In the Production select App Store and Ad Hoc, then scroll down to Continue:

Screen Shot 2017-06-21 at 10.25.20 AM

You’ll then see a page that explains how to create a Certificate Signing Request that is required to generate the Certificate. Click Continue, then in the Mac open the Keychain Access application.
Then from the Keychain Access menu, go to Certificate Assistant and Request a Certificate from a Certificate Authority:
cert_request

Fill out the form and save the request file locally:
Screen Shot 2017-06-21 at 10.26.09 AM

Take this newly saved file and go back to the Apple Developer Portal and upload it:

upload_cert

Click Continue and you’ll now be able to download the Certificate. Double click / open the newly downloaded certificate, and it will be installed into your keychain.

Important Notes About Certificates

Guess what! It gets more complicated and annoying!

Once you’ve created a certificate, you can ONLY USE IT on the machine that created the signing request due to the signing mechanism. In order to allow a user to use the certificate, you’ll need to export it to a .p12 file which is then signed by a new password. The other Mac user can then take that .p12 file and save it to their keychain using said password. We won’t go into depth about this process in this post, but perhaps in a follow-up.

Adding iOS Devices

In order to install an ad-hoc or non-App Store iOS app, the devices that will install and run the app need to be registered and eventually included in part of the build process. In the Apple Developer Portal we can add devices to our profile (up to 100 devices).

In the left navigation, click on Devices > All then once again click the plus button in the top right:Screen Shot 2017-06-21 at 10.26.56 AM

Give your new device a Name and then get the UDID of the device.

Getting the UDID of an iOS Device

Plug in your iOS device to your Mac and open iTunes if it doesn’t open automatically. In iTunes, click on the device button to get to the device details:Screen Shot 2017-06-21 at 11.50.49 AM.png

You’ll notice that there is no UDID field! Here’s the secret: click the device’s Serial Number to reveal the UDID:

Copy the UDID.

Back in the Apple Developer Portal add the UDID and click Continue to save the device.

Now that we have an App ID, Certificate, and our devices, the last step is to create a Provisioning Profile and install it on the Mac.

Creating an Ad Hoc Provisioning Profile

In the left navigation, click on Provisioning Profiles > Distribution and then the plus button in the top right.Screen Shot 2017-06-21 at 10.33.16 AM

Next you’ll be asked which type of Profile you want to create. Select Ad Hoc under the Distribution section.Screen Shot 2017-06-21 at 10.33.22 AM

Click Continue and you’ll then need to select which App ID this profile is for. In the dropdown, select the App ID you created:select_app_id

Click Continue and you’ll need to select the Distribution Certificate to associate with the profile. Select the certificate you just created:
Screen Shot 2017-06-21 at 10.33.50 AM

Click Continue and you’ll need to select the devices that are allowed to run this application built with this profile. Select the devices you added or want to enable:Screen Shot 2017-06-21 at 10.34.00 AM

Click Continue and give your profile a Nameprofile_preview
Click Continue and you can review the profile before generating it.

Click Generate and then Download the profile. Double-Click or open the newly downloaded profile and it will then be instlled into XCode.

Now with your certificate installed on the machine’s keychain and the profile installed into XCode, you’ll be able to build against iOS devices in Release. Doing this build will then generate an .ipa file. This file is what can be uploaded to Mobile Center, HockeyApp, or any other distribution channel you want to use.

Next Steps

In the next few blog posts, we’ll look at actually uploading a new build .ipa file to both HockeyApp and Mobile Center so that test users can download and install it on their devices. Stay tuned!

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.

Xamarin.Tip – Adding Dynamic Elevation to Your Xamarin.Forms Buttons

Before Reading

In a previous post, I talked about bringing Material Design to your iOS applications in Xamarin.Forms and adding drop shadows to them. You might want to read that here first: Xamarin.Tips – Creating a Material Design Button in iOS

In another post, we learned how to override the Android Button Elevations. We will be doing this in this post in order to set a dynamic elevation. You can read that here: Xamarin.Tips – Overriding Android Button Shadows/Elevation

Now in this post, we will combine these two concepts with a new custom Xamarin.Forms component called MaterialButton that will have a new Elevation property to control the elevation and shadow of the underlying button control.

The source code and an example can be found here: https://github.com/SuavePirate/MaterialButton

Using the existing code

You can of course use the code I wrote and put on GitHub for this. In order to use it, simply:

  1. Clone the repository at  https://github.com/SuavePirate/MaterialButton
  2. Include all 3 `src` projects in your Solution
  3. Reference the Shared project in all Xamarin.Forms and platform projects
  4. Reference the Android project in your Android projects
  5. Reference the iOS project in your iOS projects
  6. Use the control as below (see example projects to demo)

Reference the control in your XAML:

MainPage.xaml

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"              xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"              xmlns:local="clr-namespace:MaterialButtonExample"              xmlns:suave="clr-namespace:SuaveControls.MaterialButton.Shared;assembly=SuaveControls.MaterialButton.Shared"              x:Class="MaterialButtonExample.MainPage">

	<suave:MaterialButton x:Name="MyButton"                            BackgroundColor="#03A9F4"                            TextColor="White"                            Text="Click to raise elevation"                            Elevation="1"                            VerticalOptions="Center"                            HorizontalOptions="Center"                           WidthRequest="300"                           Clicked="MyButton_Clicked"/>

</ContentPage>

MainPage.xaml.cs

namespace MaterialButtonExample
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
        }

        private void MyButton_Clicked(object sender, EventArgs e)
        {
            MyButton.Elevation++;
        }
    }
}

In your iOS AppDelegate you’ll also need to call the Initialize method to ensure that the Custom renderer does not get excluded during linking:

AppDelegate.cs

namespace MaterialButtonExample.iOS
{
    [Register("AppDelegate")]
    public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
    {

        public override bool FinishedLaunching(UIApplication app, NSDictionary options)
        {
            global::Xamarin.Forms.Forms.Init();
            MaterialButtonRenderer.Initialize();
            LoadApplication(new App());

            return base.FinishedLaunching(app, options);
        }
    }
}

Now you can see your results!

Creating Your Own Material Design Button

First things first, let’s create our new Xamarin.Forms control before we implement our custom renderers:

MaterialButton.cs

namespace SuaveControls.MaterialButton.Shared
{
    public class MaterialButton : Button
    {
        public static BindableProperty ElevationProperty = BindableProperty.Create(nameof(Elevation), typeof(float), typeof(MaterialButton), 4.0f);

        public float Elevation
        {
            get
            {
                return (float)GetValue(ElevationProperty);
            }
            set
            {
                SetValue(ElevationProperty, value);
            }
        }
    }
}

Now let’s implement our iOS and Android custom renderers.

iOS:
MaterialButtonRenderer


[assembly: ExportRenderer(typeof(MaterialButton), typeof(MaterialButtonRenderer))]
namespace SuaveControls.MaterialButton.iOS
{
    public class MaterialButtonRenderer : ButtonRenderer
    {
        public static void Initialize()
        {
            // empty, but used for beating the linker
        }
        protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
        {
            base.OnElementChanged(e);

            if (e.NewElement == null)
                return;

        }

        public override void Draw(CGRect rect)
        {
            base.Draw(rect);
            UpdateShadow();
        }

        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);
            if(e.PropertyName == "Elevation")
            {
                UpdateShadow();
            }
        }

        private void UpdateShadow()
        {

            var materialButton = (Shared.MaterialButton)Element;

            // Update shadow to match better material design standards of elevation
            Layer.ShadowRadius = materialButton.Elevation;
            Layer.ShadowColor = UIColor.Gray.CGColor;
            Layer.ShadowOffset = new CGSize(2, 2);
            Layer.ShadowOpacity = 0.80f;
            Layer.ShadowPath = UIBezierPath.FromRect(Layer.Bounds).CGPath;
            Layer.MasksToBounds = false;

        }
    }
}

Notice how we use the UpdateShadow method to use the Elevation property to set the ShadowRadius of our UIButton's Layer.

It’s important to also make the UpdateShadow call in the OnElementPropertyChanged so that we can dynamically change the Elevation property in our Xamarin.Forms control and see it reflected in the underlying UIButton.

Now let’s do it on Android:

MaterialButtonRenderer

[assembly: ExportRenderer(typeof(MaterialButton), typeof(MaterialButtonRenderer))]
namespace SuaveControls.MaterialButton.Droid
{
    public class MaterialButtonRenderer : Xamarin.Forms.Platform.Android.AppCompat.ButtonRenderer
    {
        ///
<summary>
        /// Set up the elevation from load
        /// </summary>

        /// <param name="e"></param>
        protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Button> e)
        {
            base.OnElementChanged(e);
            if (e.NewElement == null)
                return;

            var materialButton = (Shared.MaterialButton)Element;

            // we need to reset the StateListAnimator to override the setting of Elevation on touch down and release.
            Control.StateListAnimator = new Android.Animation.StateListAnimator();

            // set the elevation manually
            ViewCompat.SetElevation(this, materialButton.Elevation);
            ViewCompat.SetElevation(Control, materialButton.Elevation);
        }

        public override void Draw(Canvas canvas)
        {
            var materialButton = (Shared.MaterialButton)Element;
            Control.Elevation = materialButton.Elevation;
            base.Draw(canvas);
        }

        ///
<summary>
        /// Update the elevation when updated from Xamarin.Forms
        /// </summary>

        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);
            if(e.PropertyName == "Elevation")
            {
                var materialButton = (Shared.MaterialButton)Element;
                ViewCompat.SetElevation(this, materialButton.Elevation);
                ViewCompat.SetElevation(Control, materialButton.Elevation);
                UpdateLayout();
            }
        }
    }
}

Just as mentioned in the iOS implementation, we need to make sure that we implement our changes in both the OnElementChanged method as well as the OnElementPropertyChanged event to ensure we are able to update our Elevation with MVVM.

Now we can use our control in our pages!

MainPage.xaml

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"              xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"              xmlns:local="clr-namespace:MaterialButtonExample"              xmlns:suave="clr-namespace:SuaveControls.MaterialButton.Shared;assembly=SuaveControls.MaterialButton.Shared"              x:Class="MaterialButtonExample.MainPage">

	<suave:MaterialButton x:Name="MyButton"                            BackgroundColor="#03A9F4"                            TextColor="White"                            Text="Click to raise elevation"                            Elevation="1"                            VerticalOptions="Center"                            HorizontalOptions="Center"                           WidthRequest="300"                           Clicked="MyButton_Clicked"/>

</ContentPage>

MainPage.xaml.cs

namespace MaterialButtonExample
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
        }

        private void MyButton_Clicked(object sender, EventArgs e)
        {
            MyButton.Elevation++;
        }
    }
}

In your iOS AppDelegate you’ll also need to call the Initialize method to ensure that the Custom renderer does not get excluded during linking:

AppDelegate.cs

namespace MaterialButtonExample.iOS
{
    [Register("AppDelegate")]
    public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
    {

        public override bool FinishedLaunching(UIApplication app, NSDictionary options)
        {
            global::Xamarin.Forms.Forms.Init();
            MaterialButtonRenderer.Initialize();
            LoadApplication(new App());

            return base.FinishedLaunching(app, options);
        }
    }
}

Now you can see your results!

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.