As per requests after my last post on creating a more Material looking Xamarin.Forms Frame on iOS, I’ll start talking about bringing a more material design feel to other controls in iOS. This time we’ll look at getting a more material Button control, first to be usable without Xamarin.Forms, then in a custom renderer that we can use everywhere and apply to all our Buttons.
Keep in mind, this does not hit upon all the pieces of a Material Design Button that you might see in Android. For example, it does not show a ripple on tap, and does not raise the elevation on tap. Those topics will come in a different blog post!
Let’s get down to it with a custom UIButton that applies a material-ish shadow to our button.
MaterialButton.cs
public class MaterialButton : UIButton
{
public override void Draw(CGRect rect)
{
base.Draw(rect);
// don't do it on transparent bg buttons
if (BackgroundColor.CGColor.Alpha == 0)
return;
// Update shadow to match better material design standards of elevation
Layer.ShadowRadius = 2.0f;
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;
}
}
You can see that we basically just apply a specific shadow to our base Layer of the control.
Now, let’s interpret this into a custom renderer for Xamarin.Forms:
MaterialButtonRenderer.cs
[assembly: ExportRenderer(typeof(Button), typeof(MaterialButtonRenderer))]
namespace YOUR_IOS_NAMESPACE
{
public class MaterialButtonRenderer : ButtonRenderer
{
public override void Draw(CGRect rect)
{
base.Draw(rect);
// don't do it on transparent bg buttons
if (Element.BackgroundColor.A == 0)
return;
// Update shadow to match better material design standards of elevation
Layer.ShadowRadius = 2.0f;
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;
}
}
}
This will apply the shadow to any regular Button Element. If you want to create a whole new Element that will allow you to use it in specific places, you could either create an Effect, or you can create a new class that subclasses Xamarin.Forms.Button, and then update the renderer to fit that class:
MaterialButton.xaml.cs
public partial class MaterialButton : Button
{
// we don't need to do anything special here since we do all the custom work in the iOS Renderer
}
and of course our updated renderer
MaterialButtonRenderer.cs
[assembly: ExportRenderer(typeof(MaterialButton), typeof(MaterialButtonRenderer))]
namespace YOUR_IOS_NAMESPACE
{
public class MaterialButtonRenderer : ButtonRenderer
{
public override void Draw(CGRect rect)
{
base.Draw(rect);
// don't do it on transparent bg buttons
if (Element.BackgroundColor.A == 0)
return;
// Update shadow to match better material design standards of elevation
Layer.ShadowRadius = 2.0f;
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;
}
}
}
Now your control should go from this:

To this:

Make sure to stay tuned for more Material Design styled controls brought to iOS, and adding some advanced features like rippled clicks and elevation changes/settings.
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.
3 thoughts on “Xamarin.Tips – Creating a Material Design Button in iOS”