16 October 2015

Borders on Xamarin Forms user interface elements

This is one of those blog posts, born out of utter frustration because looking for this yielded no usable results - while you would expect a lot of people would be wanting to do, as it's quite elementary IMHO. Maybe it's just my inexperience with Xamarin Forms, but for the life of me I could not find how to place borders around panel-like structures like a grid. Sure, there is Frame, but that places a meager 1 pixel hardly visible line around it.

Suppose I had this code

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamBorders.MainPage" BackgroundColor="White">
  <ContentView Padding = "20" VerticalOptions="Start" >
    <Label Text="I want a border here!" 
           FontSize="20" TextColor="Black" 
           HorizontalOptions="Center"></Label>
  </ContentView>
</ContentPage>

Result in in the UI below (on the Visual Studio Android Emulator) image

How on Earth do you get something like this?

image

Turns out you need a couple of ContentViews inside each other like a bunch of Matryoshka dolls - one with the border color as background color, and inside that a slightly smaller ContentView with the same background color as the page. Like this:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamBorders.MainPage" 
  BackgroundColor="{StaticResource BackgroundColor}">
  <ContentPage.Resources>
    <ResourceDictionary x:Name="AppDictionary">

      <Color x:Key="BackgroundColor">#FFFFFF</Color>
      <Color x:Key="BorderColor">#E1E1E1</Color>

      <Style x:Key="InternalViewStyle" TargetType="ContentView">
        <Setter Property="BackgroundColor" 
Value="{StaticResource BackgroundColor}"/> <Setter Property="VerticalOptions" Value="Fill"/> <Setter Property="Padding" Value="10,10,10,10"></Setter> </Style> <Style x:Key="BorderStyle" TargetType="ContentView"> <Setter Property="BackgroundColor" Value="{StaticResource BorderColor}"/> <Setter Property="Padding" Value="3,1,1,3"></Setter> </Style> </ResourceDictionary> </ContentPage.Resources> <ContentView Padding="20" VerticalOptions="Start" > <ContentView Style="{StaticResource BorderStyle}" > <ContentView Style="{StaticResource InternalViewStyle}"> <Label Text="I want a border here!" FontSize="20" TextColor="Black" HorizontalOptions="Center"></Label> </ContentView> </ContentView> </ContentView> </ContentPage>

So we have the internal view that has the same background color as the page, as well as a padding of 10 on every side to make the border not too tight around the text. Then the 'border contentview' around that has a padding 0 3,1,1,3 so that it's slightly larger bottom and right as to create some kind of shadow effect. If you don't want that, just make the padding equal. I defined the settings a styles as to make them easily reusable (they are in a app-wide resource dictionary in the app I am now developing).

Why it has to be this way - no idea, but I hope it will save some other Xamarin Forms newbie the frustration I experienced this afternoon. Maybe there are better alternatives - I really welcome comments. But this works

Sample project can be found here.

2 comments:

Joost van Schaik said...

You are welcome :)

Salvador said...

Just for anyone who find it nowadays (2018): you can now achieve this simpler and maybe better with the control Frame: https://developer.xamarin.com/api/type/Xamarin.Forms.Frame/

Thanks Joost for the post! That was helpful.