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”