Turning Entry’s Placeholder into Title in Xamarin Forms

I really hope that this title is not misleading. I’m not sure ‘turning’ is the right word, but I don’t know better word to describe what I want to discuss in this post. As we know together, in Android Native app, we can have Entry component whose placeholder will turn into title with a little ‘going up’ animation when user start interact with it. And because you can only have it in Android, not in other platform, Xamarin Forms doesn’t support it, at least not yet. Unfortunately, in my current project I’m already required to create such a thing. So, this is how I do the work around, not perfect yet but not too bad either.

Custom Entry with Title

The first thing I do is creating a custom content view with a stack layout in it. The stack layout contains an Entry and a Label that will serve as Entry’s title. Why stack layout, not Grid? It’s not just for simplicity’s sake. Remember the ‘going up’ animation I discuss earlier? I want to create an effect like that, not as good as the original, but I think it’s good enough. When you hide something in stack layout and something trigger it to appear, it will create a little animation, up or down depend on the position. It also works the other way around, when you hide something, you’ll get similar animation. So, this how I put the Entry and Label on the xaml file.

TitledEntryCode1

Pay the on the Entry. It has event handler for Focused and Unfocused event, that where we gonna do the trick. And the code below is how the code behind looks like.

public partial class TitledEntry : ContentView
{
    string placeholder = string.Empty;

    public TitledEntry()
    {
        InitializeComponent();

        if (EntryContent.Text == null || EntryContent.Text.Length == 0)
        {
            LabelTitle.IsVisible = false;
        }

        EntryContent.BindingContext = this;
        LabelTitle.BindingContext = this;
    }

    public static BindableProperty PlaceholderProperty =
        BindableProperty.Create(nameof(Placeholder), typeof(string), typeof(TitledEntry), null, BindingMode.TwoWay);

    public string Placeholder
    {
        get => (string)GetValue(PlaceholderProperty);
        set => SetValue(PlaceholderProperty, value);
    }

    void Handle_Focused(object sender, FocusEventArgs e)
    {
        LabelTitle.IsVisible = true;

        if (EntryContent.Text == null || EntryContent.Text.Length == 0)
        {
            placeholder = EntryContent.Placeholder;
            EntryContent.Placeholder = string.Empty;
        }

    }

    void Handle_Unfocused(object sender, FocusEventArgs e)
    {
        if (EntryContent.Text == null || EntryContent.Text.Length == 0)
        {
            EntryContent.Placeholder = placeholder;
            LabelTitle.IsVisible = false;
        }

    }
}

So all I do is just giving condition about Entry’s text length and stack layout will do the rest. If there’s one thing you need to remember is setting the binding context of the Entry and Label to current class like I do in the constructor or you won’t be able to bind them from view model.

Let’s use it

Now that we already have our custom entry ready, let see it in action. I create a view model contains 2 strings called Username and Email and I set a view model as the binding context for the class whose xaml file you can see below.

TitledEntryCode2

And if try to run the solution, you’ll have Entries like the real Android’s Entry.

 

Update : Making Enum as Bindable Property

Sample Code is available in my Github repo

 

Get rid of underline from Entry in Xamarin Android

Have you ever felt annoyed by the entry’s underline on Android? I know it’s there by default, and the designers in Google’s headquarter must have reason for it. But. sometime it just doesn’t suit the design of your app, so you just need to get rid of it. I once tried to do it, I searched on the internet, but all I found was how to do it in Android Studio. There’s bunch examples how to do it if you’re developing an Android app in Android Studio, all you have to do is just doing some simple search on internet. But, what if you’re developing a Cross Platform app with Xamarin? Nah, it will be bit more complicated.

Create Background for Entry

So, this is what I did with my project. I created an .axml file and I put it in drawable folder in Droid project. I will use this file to be the background of the entry. The shape of the entry will be a transparent rectangle. Why’s transparent? Because it’s Android’s default background color. Why’s rectangle? It’s just for simplicity and normality sake, you can make a circle instead, if you want. The following code is Background Entry code.

<?xml version="1.0" encoding="UTF-8" ?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item>
    <shape android:shape="rectangle">
      <solid android:color="#00ffffff"/>
    </shape>
  </item>
</selector>

Let’s discuss it a little bit. The shape is rectangle, no question about it. And the color is #00ffffff. As you know that #ffffff is Hex code for the color white. And the two zeroes in front of it is the degree of the transparency. The smaller the number, the more transparent the color. So, if you don’t want it to be too transparent, you can just add the number, like 20 or 70. But for this example I will use the ’00’ number.

Custom Renderer

Now after we have new background for our Entry, all we need to do just create custom renderer to apply the background. Here’s the code for the custom entry renderer.

public class CustomEntryRenderer : EntryRenderer
{
    protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
    {
        base.OnElementChanged(e);
        this.Control.Background = Forms.Context.GetDrawable(Resource.Drawable.BackgroundEntry);
        Control?.SetPadding(20, 20, 20, 20);
    }
}

This method has one weakness, we don’t actually remove the underline, we just cover it with a background. So, the underline is still there, you just can’t see it anymore. It makes an awkward appearance that the text user inputing will slightly closer to the top. It’s vertically above the middle. And it also look too close to the left edge. So, I set some padding to make sure the the text of the entry will be in right place.

Let’s try it out

Now that we have our Entry ready, let’s try it out. When you’re using an Entry in a project, usually when you’re creating some kind of a form, there will be many states of the entry. For example, one normal state of a blank entry, or a disable entry that require user to fill other field first, or an error state when user submit the form but left the requirement field empty. To try out that condition, I created a simple app to show different state of an entry. Here’s the xaml 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" Title="ColorfulEntry" xmlns:control="clr-namespace:Testing.CustomControls" x:Class="Testing.Views.ColorfulEntry">
	<ContentPage.Content>
         <StackLayout VerticalOptions="StartAndExpand" Padding="30,30,30,0">
            <control:CustomEntry Placeholder="This is normal Entry"/>
            <control:CustomEntry Placeholder="This entry is disabled" IsEnabled="false" BackgroundColor="Gray"/>
            <control:CustomEntry Placeholder="This field must be filled" BackgroundColor="Red"/>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

Entry1

Add Custom Back Button on Android

Ok, first of all, this post is actually a complementary post of my previous post, Changing Navigation Bar Color Dynamically. In that post we discussed about how to change the color of the navigation bar when we navigate to different menu. At the end of that post, I gave external reference about how to override back button. That overriding back button method solved almost all the problem we had about back button. Unless one thing. In Android, changing the navigation bar color give us a navigation bar without back button. We still could navigate with device back button, but normally an Android app will have back button on its navigation bar. So, in this post we will discuss how to add our own back button and we will override it, just like we did in previous post.

Accessing Toolbar from Page Renderer

To create custom back button and adding it to the page, obviously we gonna need custom renderer. But, there’s one little problem. In Android, the navigation bar is actually a toolbar and we can not access it freely from the renderer. We need to have access first to the activity, and then we access the toolbar. And in doing so, I got tremendous help from Xamarin Forum. We just to add this following codes to MainActivity.cs

<br>
private static MainActivity _this;<br>
public static View RootFindViewById&lt;T&gt;(int id) where T : View<br>
{<br>
    return _this.FindViewById&lt;T&gt;(id);<br>
}<br>
public MainActivity()<br>
{<br>
    _this = this;<br>
}<br>

Customize Android Logo

After we’ve done with the MainActivity, now we’ll create the page renderer. The page renderer will render the CoolContentPage that we discuss in the previous post. In this page renderer, we’ll customize the Android Logo. Android Logo is toolbar component that’s placed between back button and toolbar title. And with we having no back button in this case, android logo become most left placed component on the toolbar. And, fortunately, android logo is basically an ImageView, little bit different with the regular ImageView, but still, like an ImageView, we can set an image and adding listener to it. And this is exactly what we gonna do. First, add an Android back button image to Drawable folder, and then create CoolContentPage custom renderer with the following code.

<br>
public class CoolContentPageRenderer : PageRenderer<br>
{<br>
    protected override void OnElementChanged(ElementChangedEventArgs&lt;Page&gt; e)<br>
    {<br>
        base.OnElementChanged(e);<br>
        if (((CoolContentPage)Element).EnableBackButtonOverride)<br>
        {<br>
            SetCustomBackButton();<br>
        }<br>
    }<br>
    private void SetCustomBackButton()<br>
    {<br>
        //accessing toolbar from MainActivity<br>
        var toolbar = (Toolbar)MainActivity.RootFindViewById&lt;Toolbar&gt;(Resource.Id.toolbar);</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>        // set Android Logo's image<br>
        toolbar.SetLogo(Resource.Drawable.AndroidBackButton);</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>        for (int i = 0; i &lt; toolbar.ChildCount; i++)<br>
        {<br>
            var item = toolbar.GetChildAt(i);<br>
            //if Android Logo<br>
            if (item.GetType() == typeof(AppCompatImageView))<br>
            {<br>
                AppCompatImageView image = (AppCompatImageView)item;<br>
                image.Click += (sender, e) =&gt;<br>
                {<br>
                    if (((CoolContentPage)Element)?.CustomBackButtonAction != null)<br>
                    {<br>
                        ((CoolContentPage)Element)?.CustomBackButtonAction.Invoke();<br>
                    }<br>
                };<br>
            }<br>
        }<br>
    }<br>
}<br>

Navigation Handling

Now that’s all set, we just need to do little update to the content page. Just like I stated earlier, this post is complementary of my previous post, so I’ll give example from my previous post as well. In that post, we created breakfast page menu with overriding back button. And customizing android logo will have massive effect to breakfast page.

Let’s take one page for example. Let say we navigate to Sandwich Page, of course it gonna have customized android logo. And then we navigate to other page from Sandwich Page, that page will still have the android logo. Event hough we don’t inherit that CoolContentPage. Yes, once we set it, Android logo stays still. It will be a problem if the next page already has natural back button, so the page will have two back buttons. And even worse, the android logo back button won’t even follow the natural order of navigation stack. It will still execute the listener we set on page renderer.

To avoid such kind of problem, we need to update our breakfast page. Here’s the example how I did it.

<br>
public partial class BreakfastSandwich : CoolContentPage<br>
{<br>
    public BreakfastSandwich()<br>
    {<br>
        InitializeComponent();<br>
        if (EnableBackButtonOverride)<br>
        {<br>
            this.CustomBackButtonAction = () =&gt;<br>
            {<br>
                 var currentpage = Application.Current.MainPage.Navigation.NavigationStack.LastOrDefault();<br>
                 // if root page<br>
                 if(currentpage.GetType() ==typeof(BreakfastSandwich))<br>
                 {<br>
                    Application.Current.MainPage = new BreakfastPage();<br>
                 }<br>
                 else<br>
                 {<br>
                    Navigation.PopAsync();<br>
                 }<br>
            };<br>
        }<br>
    }<br>
}<br>

And for any pages that Breakfast Sandwich navigate into, we have to remove the natural back button, so we don’t have double back button on the toolbar.  We’ll only do it in Android, because Android Logo won’t have any effect on iOS platform. Here’s the example.

<br>
public partial class MoreSandwichPage : ContentPage<br>
{<br>
    public MoreSandwichPage()<br>
    {<br>
        InitializeComponent();<br>
        if (Device.RuntimePlatform == Device.Android)<br>
        {<br>
            NavigationPage.SetHasBackButton(this, false);<br>
        }<br>
    }<br>
}<br>

Note : For simplicity sake, I used raw icon I got from FlatIcon, in real project you should use customize back button icon that has space after the arrow, in order to make it look like real Android back button.

Credit:

  • Icon from FlatIcon, Left Arrow icon by Google
  • Override Navigation Back Button by Udara Alwis (blog)
  • Access Toolbar from Page Renderer by ChaseFlorell (Xamarin Forum)
  • Get Android Logo from Toolbar by Mike M. (StackOverflow)

Sample Code is Available in my Github repo