Adding Scope Buttons to a SearchBar in Xamarin.Forms with a Custom Renderer on iOS

February 02, 2016

When you’re designing a cross-platform mobile app, there are some great features of Xamarin.Forms. This blog post will explain how to create a custom renderer when you’re working with Xamarin.Forms. At Sparkhound, Xamarin is our cross-platform development platform of choice because it allows for maximum code sharing while having everything written in .NET.

Xamarin.Forms provides cross-platform support for search bars. However, Scope Buttons are an iOS specific feature, and are not available in Xamarin.Forms. We can add this functionality via a custom renderer on iOS. Custom renderers are a way to add device specific functionality to a generic cross-platform control.

First, we need to create a class that inherits from Xamarin.Forms.SearchBar. This is so that we can specify where we want the scope buttons to show and add additional functionality for the Scope Buttons to it.

public class CustomSearchBar : SearchBar
{
    public event ScopeChangedEventHandler ScopeChanged;
    public string SelectedScopeText {
        get {
            return SelectedButtonIndex >= 0 
                && SelectedButtonIndex < ScopeButtons.Length 
                ? ScopeButtons[SelectedButtonIndex] 
                : "";
        } }

    public int SelectedButtonIndex { get; set; }

    public string[] ScopeButtons {
        get {
            return new[] {
                Constants.Search.Store.Street,
                Constants.Search.Store.City,
                Constants.Search.Store.State,
                Constants.Search.Store.Zip };
        }
    } 

    public void RaiseScopeChanged()
    {
        if (ScopeChanged != null)
            ScopeChanged.Invoke(this, EventArgs.Empty);
    }
} 

public delegate void ScopeChangedEventHandler(
    object sender, EventArgs e);
}

In the above code, we have an event handler so that we know when the scope button’s selection changed. SelectedScopeText and SelectedButtonIndex lets us know which item is selected by the user. ScopeButtons is an array of strings that will be the text for the scope buttons. Using constants helps to match the text up late with little room for error. RaiseScopeChanged is just a wrapper that allows for the consumer to raise the event.

Now that we have our custom control, we need to create our iOS specific renderer.

[assembly: ExportRenderer(typeof(CustomSearchBar), 
                          typeof(CustomSearchBarRenderer))]
public class CustomSearchBarRenderer : SearchBarRenderer
{
    protected override void OnElementChanged(
        ElementChangedEventArgs<SearchBar> e)
    {
        base.OnElementChanged(e); 

        var element = Element as CustomSearchBar; 

        if (element != null)
        {
            Control.ShowsScopeBar = true;
            Control.ShowsCancelButton = true;
            Control.BackgroundColor = UIColor.White;
            Control.ScopeButtonTitles = element.ScopeButtons;
            Control.SelectedScopeButtonIndexChanged += 
            (sender, args) => {
                element.SelectedButtonIndex = (int)args.SelectedScope;
                element.RaiseScopeChanged();
            };

            Control.CancelButtonClicked += 
                    (sender, args) => Control.ResignFirstResponder();
        }
    }
}

First, we have the ExportRenderer attribute to let Xamarin.Forms know which control to augment. Then, we need to inherit from the Xamarin.Forms renderer for that control. One of the most common methods to override is the OnElementChanged. There are many that can be overriden dependent on what your needs are. The two properties to make note of are Element and Control. Element is our custom control and where we set the selected index and then let it know that the scope has changed. Control is the native iOS control, UISearchBar. This is where we have access to all of the platform specific functionality. It is now as simple as setting the property to show the scope bar, the array of strings for the labels, and hooking into the event when the selection changes.

Now, let’s go ahead and use our new CustomSearchBar on a Xamarin.Forms page.

var searchBar = new CustomSearchBar
{
    Placeholder = "Search",
    BackgroundColor = Color.White,
    HorizontalOptions = LayoutOptions.FillAndExpand,
    VerticalOptions = LayoutOptions.End,
    SearchCommand = ViewModel.SearchCommand
};
searchBar.ScopeChanged += OnScopeChanged;
searchBar.TextChanged += OnSearch;
searchBar.SearchButtonPressed += OnSearch;

In this snippet, we create the control, set the ICommand used for searching, a few other properties, and then tie into the events fired for the control – pretty much nothing out of the ordinary for implementing any Xamarin.Forms control.

The finished product will be a search bar with the scope buttons:

Searchbar

This is the normal pattern to follow when creating any Xamarin.Forms custom renderer. Also, remember that this is pretty different functionality that we are adding to iOS. If you are creating the app for other platforms, you will probably need to make accommodations on those platforms to offer a comparable experience.

Is this interesting, want to learn more, or are having the same discussions in your own department? Sparkhound's in-house developers work with Xamarin and many other technologies daily! Get in touch with us so we can discuss how we can help your business achieve its goals through leadership and technology.

Information and material in our blog posts are provided "as is" with no warranties either expressed or implied. Each post is an individual expression of our Sparkies. Should you identify any such content that is harmful, malicious, sensitive or unnecessary, please contact marketing@sparkhound.com.

Meet Sparkhound

Review our capabilities and services, meet the leadership team, see our valued partnerships, and read about the hardware we've earned.

Engage with us

Get in touch with any of our offices, or check out our open career positions and consider joining Sparkhound's dynamic team.