3
votes

https://www.linkedin.com/pulse/xamarin-forms-contentpage-searchbar-navigation-bar-vipin-mathews/

I tried to implement the above code but not succeed, Search Icon not coming in page,

After that I tried this Adding a Search Bar in the toolbar of a navigationpage in Prism , and its appears but once I changes the orientation or I logout or clicked on other page and come back again at this page its gone

I downloaded the code from git but not able to run that also.

<?xml version="1.0" encoding="utf-8" ?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto">
  <item android:id="@+id/action_search"
        android:title="Search"
        android:icon="@android:drawable/ic_menu_search"
        app:showAsAction="always|collapseActionView"
        app:actionViewClass="android.support.v7.widget.SearchView"/>
</menu>

But ic_menu_search file not there in drawable folder, Is that an issue?

2
Hey Avi, have you got solution. I am facing same problem here.Sanjay Gupta
Still no luck..Avi

2 Answers

0
votes

Just use the TitleView something like:

<NavigationPage.TitleView>
        <StackLayout HorizontalOptions="FillAndExpand" Orientation="Horizontal">
            <Label
                HorizontalOptions="FillAndExpand"
                Text="{StaticResource PageTitle}"
                TextColor="White"
                VerticalOptions="Center" />
            <SearchBar
                HorizontalOptions="End"
                Placeholder="Search"
                PlaceholderColor="{StaticResource GrayPlaceHolderColor}"
                TextColor="White"
                VerticalOptions="Center" />
        </StackLayout>
    </NavigationPage.TitleView>
0
votes

We can create a custom renderer in both the Xamarin.iOS and Xamarin.Android to accomplish it.

Here's a sample application for reference: https://github.com/brminnick/GitTrends

And here's a blog post that shows how to add a search bar to a Xamarin.Forms app for both Xamarin.iOS & Xamarin.Android: https://www.codetraveler.io/2019/08/10/adding-a-search-bar-to-xamarin-forms-navigationpage/

App.cs

Use a Xamarin.Forms Platform-Specific to use LargeTitles on the Xamarin.iOS app.

using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;

public class App : Xamarin.Forms.Application
{
    public App()
    {
        var navigationPage = new Xamarin.Forms.NavigationPage(new MyContentPage());

        navigationPage.On<iOS>().SetPrefersLargeTitles(true);

        MainPage = navigationPage;
    }
}

ISearchPage Interface

Create an Interface that can be used across the Xamarin.Forms, Xamarin.Android and Xamarin.iOS projects.

public interface ISearchPage
{
    void OnSearchBarTextChanged(in string text);
    event EventHandler<string> SearchBarTextChanged;
}

Xamarin.Forms Page

public class MyContentPage : ContentPage, ISearchPage
{
    public MyContentPage()
    {
        SearchBarTextChanged += HandleSearchBarTextChanged
    }

    public event EventHandler<string> SearchBarTextChanged;

    public void OnSearchBarTextChanged(in string text) => SearchBarTextChanged?.Invoke(this, text);

    void HandleSearchBarTextChanged(object sender, string searchBarText)
    {
        //Logic to handle updated search bar text
    }     
}

iOS Custom Renderer

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UIKit;
using MyNamespace;
using MyNamespace.iOS;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

[assembly: ExportRenderer(typeof(MyContentPage), typeof(SearchPageRenderer))]
namespace MyNamespace.iOS
{
    public class SearchPageRenderer : PageRenderer, IUISearchResultsUpdating
    {
        bool _isFirstAppearing = true;

        public override void WillMoveToParentViewController(UIViewController parent)
        {
            base.WillMoveToParentViewController(parent);

            var searchController = new UISearchController(searchResultsController: null)
            {
                SearchResultsUpdater = this,
                DimsBackgroundDuringPresentation = false,
                HidesNavigationBarDuringPresentation = false,
                HidesBottomBarWhenPushed = true
            };
            searchController.SearchBar.Placeholder = string.Empty;

            parent.NavigationItem.SearchController = searchController;

            DefinesPresentationContext = true;
        }

        public override void ViewDidAppear(bool animated)
        {
            base.ViewDidAppear(animated);

            //Work-around to ensure the SearchController appears when the page first appears https://stackoverflow.com/a/46313164/5953643
            if (_isFirstAppearing)
            {
                ParentViewController.NavigationItem.SearchController.Active = true;
                ParentViewController.NavigationItem.SearchController.Active = false;

                _isFirstAppearing = false;
            }
        }

        public void UpdateSearchResultsForSearchController(UISearchController searchController)
        {
            if (Element is ISearchPage searchPage)
                searchPage.OnSearchBarTextChanged(searchController.SearchBar.Text);
        }
    }
}

Xamarin.Android Menu XML

  1. In the Xamarin.Android project, in the Resources folder, create a new folder called menu (if one doesn't already exist).

    • Note: the folder, menu, has a lowercase 'm'
  2. In the Resources > menu folder, create a new file called MainMenu.xml.

enter image description here

  1. Open Resources > menu > MainMenu.xml

  2. In MainMenu.xml add the following code:

<?xml version="1.0" encoding="utf-8" ?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto">
  <item android:id="@+id/ActionSearch"
        android:title="Filter"
        android:icon="@android:drawable/ic_menu_search"
        app:showAsAction="always|collapseActionView"
        app:actionViewClass="android.support.v7.widget.SearchView"/>
</menu>

Xamarin.Android CustomRenderer

Uses the Plugin.CurrentActivity NuGet Package.

using Android.Content;
using Android.Runtime;
using Android.Support.V7.Widget;
using Android.Text;
using Android.Views.InputMethods;
using Plugin.CurrentActivity;
using MyNamespace;
using MyNamespace.Droid;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

[assembly: ExportRenderer(typeof(MyContentPage), typeof(SearchPageRenderer))]
namespace MyNamespace.Droid
{
    public class SearchPageRenderer : PageRenderer
    {
        public SearchPageRenderer(Context context) : base(context)
        {

        }

        protected override void OnAttachedToWindow()
        {
            base.OnAttachedToWindow();

            if (Application.Current.MainPage is NavigationPage navigationPage)
                navigationPage.Popped += HandleNavigationPagePopped;

            if (Element is ISearchPage && Element is Page page && page.Parent is NavigationPage navigationPage && navigationPage.CurrentPage is ISearchPage)
                AddSearchToToolbar(page);
        }

        protected override void Dispose(bool disposing)
        {
            if (GetToolbar() is Toolbar toolBar)
                toolBar.Menu?.RemoveItem(Resource.Menu.MainMenu);

            base.Dispose(disposing);
        }

        void AddSearchToToolbar(in Page page)
        {
            if (GetToolbar() is Toolbar toolBar
                && toolBar.Menu?.FindItem(Resource.Id.ActionSearch)?.ActionView?.JavaCast<SearchView>().GetType() != typeof(SearchView))
            {
                toolBar.Title = page.Title;
                toolBar.InflateMenu(Resource.Menu.MainMenu);

                if (toolBar.Menu?.FindItem(Resource.Id.ActionSearch)?.ActionView?.JavaCast<SearchView>() is SearchView searchView)
                {
                    searchView.QueryTextChange += HandleQueryTextChange;
                    searchView.ImeOptions = (int)ImeAction.Search;
                    searchView.InputType = (int)InputTypes.TextVariationFilter;
                    searchView.MaxWidth = int.MaxValue; //Set to full width - http://stackoverflow.com/questions/31456102/searchview-doesnt-expand-full-width
                }
            }
        }

        void HandleQueryTextChange(object sender, SearchView.QueryTextChangeEventArgs e)
        {
            if (Element is ISearchPage searchPage)
                searchPage.OnSearchBarTextChanged(e.NewText);

        }

        void HandleNavigationPagePopped(object sender, NavigationEventArgs e)
        {
            if (sender is NavigationPage navigationPage
                && navigationPage.CurrentPage is ISearchPage)
            {
                AddSearchToToolbar(navigationPage.CurrentPage);
            }
        }

        Toolbar GetToolbar() => CrossCurrentActivity.Current.Activity.FindViewById<Toolbar>(Resource.Id.toolbar);
    }
}

Sample App

Here's a sample app for reference: https://github.com/brminnick/GitTrends

And a blog post that shows how to add a search bar for both Xamarin.iOS and Xamarin.Android: https://www.codetraveler.io/2019/08/10/adding-a-search-bar-to-xamarin-forms-navigationpage/

iOS Gif