Buttons are still the traditional elements through which the user interacts with software features.
With the mobile environment development context (dimensions, touch screen, gestures…) buttons became graphical parts that have to indicate a metaphor of the feature they give access to.
So, no surprise, many developers ask how to customize buttons to achieve this: using colors, images, symbols… etc.
The Xamarin Forms Button object
Like many other buttons, Xamarin forms button is far from able to satisfy this metaphoric aspects needed by modern mobile developers.
It represents a simple (rather poor) set of properties and leaves the developer out of intuitively finding a modern choice. You just have: Border, Font, Text…
It exposes a property Image… prowess?J… Not so fast, this property is simply defined as: Gets or sets the optional image source to display next to the text in the Button. (Faire enough!)
What is a Button?
After struggling sometime to find a way for 'customizing' buttons, we can just stop and ask ourselves this question. Yes, let us forget object libraries and just ask: What is a button?
As far as I know, it is a surface containing some graphic shapes… and, when clicked executes a command.
When tapped, the button produces a visual effect to mimic the reaction of a real life button.
Well, that now seems easy to build.
It can simply be a ContentView on which we may put whatever graphic elements we need (multiline texts, images… etc.). When clicked it plays an animation to mimic the press effect, and it then executes the command of our choice.
For this control to be reusable, we may expose properties needed for setting the graphic content and for handling the Click event as the developer may need.
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="iButton.iButtonCtrl" BackgroundColor="Gray">
<Frame x:Name="buttonFrame" HasShadow="False" OutlineColor="Black" />
</ContentView>
In the code behind, we expose the Content of our buttonFrame to be set with any ContentView we may find useful to use:
public ContentView ButtonContent
{
get { return this.buttonFrame.Content; }
set { this.buttonFrame.Content = value; }
}
We define a Tap gesture recognizer to play the press graphical effect and raise a Clicked event to be handled by our control user.
public event ClickedHandler ControlClicked;
ICommand _tapCommand;
public ICommand WidgetTapped
{
get
{
if(_tapCommand == null)
{
_tapCommand = new Command(async(obj) =>
{
// play a press animation
await Blink(this, 300);
// someone subscribed to our event?: notify him
if (ControlClicked != null)
ControlClicked.Invoke(this, new EventArgs());
});
}
return _tapCommand;
}
}
We can now create buttons the way we like or find useful… example:
First we include a reference to the button namespace:
xmlns:ctrls="clr-namespace:iButton;assembly=iButton"
Then we can go ahead and create our buttons:
<StackLayoutSpacing="20"HorizontalOptions="FillAndExpand"Padding="10" >
<ctrls:iButtonCtrlx:Name="ibutton1"BackgroundColor="#ffff9800" />
<ctrls:iButtonCtrlx:Name="ibutton2" />
<ctrls:iButtonCtrlx:Name="ibutton3"BackgroundColor="#ffcac8ff"/>
</StackLayout>
We insert the ContentViews we need for each button:
this.ibutton1.ButtonContent = new iButtonView1();
this.ibutton2.ButtonContent = new iButtonView2();
this.ibutton3.ButtonContent = new iButtonView3();
// we subscribe to the Click event
ibutton1.ControlClicked += Ibutton1_ControlClicked;
Final professional touch: xaml markup extensions!
In order for people using this control to be able to use our button properties inside xaml files, we need to declare a bindable property that gives access to our: ButtonContent.
The sample code contains such final touches!