display ViewController from Native forms - xamarin.forms

I need to display native controller IOS from Xamarin.forms I have tried this
UIWindow window = UIApplication.SharedApplication.KeyWindow;
UIViewController vc = window.RootViewController;
RGLDocReader.Shared.ShowScanner(vc, HandleRGLDocumentReaderCompletion);
this
How to create navigation in a Xamarin.iOS app?
followed this
https://learn.microsoft.com/en-us/xamarin/ios/app-fundamentals/ios-code-only?tabs=macos
the tutorial works fine, however I need to use view controller in the method as that is specified and once I pass view controller I get null

Actually , it is not a good design to navigate to a native controller in Forms . But if you do want to implement it , you could use DependencyService .
in Forms
Create the interface
public interface IOpenNativeView
{
void OpenNativeView();
}
in iOS project
using xxx.iOS;
using Foundation;
using UIKit;
using Xamarin.Forms;
[assembly: Dependency(typeof(OpenNativeView))]
namespace xxx.iOS
{
public class OpenNativeView : IOpenNativeView
{
void IOpenNativeView.OpenNativeView()
{
var CurrentViewController = topViewControllerWithRootViewController(UIApplication.SharedApplication.Delegate.GetWindow().RootViewController);
CurrentViewController.NavigationController.PushViewController(YourViewController,true);
}
UIViewController topViewControllerWithRootViewController(UIViewController rootViewController)
{
if (rootViewController is UITabBarController)
{
UITabBarController tabBarController = (UITabBarController)rootViewController;
return topViewControllerWithRootViewController(tabBarController.SelectedViewController);
}
else if (rootViewController is UINavigationController)
{
UINavigationController navigationController = (UINavigationController)rootViewController;
return topViewControllerWithRootViewController(navigationController.VisibleViewController);
}
else if (rootViewController.PresentedViewController != null)
{
UIViewController presentedViewController = rootViewController.PresentedViewController;
return topViewControllerWithRootViewController(presentedViewController);
}
else
{
return rootViewController;
}
}
}
}
Now in the ContentPage you can invoke the following line when you want to open the ViewController
DependencyService.Get<IOpenNativeView>().OpenNativeView();

Related

Change loading indicator Offset in Xamarin.Forms RefreshView

On Xamarin.Forms (iOS Android), I need to change the loading-indicator position on the RefreshView. I need to add offset, so the indicator is visible if you have a bar overlapping the ScrollView-RefreshView combo and trigger pullOnRefresh.
Loading-indicator in the top edge
EDIT: thanks to Junior Jiang - MSFT- Android solution
I also implement a solution for xamarin.iOS
[assembly: ExportRenderer(typeof(RefreshView), typeof(CustomRefreshViewRenderer))]
namespace CustomRefresh.iOS {
public class CustomRefreshViewRenderer : RefreshViewRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<RefreshView> e)
{
base.OnElementChanged(e);
foreach (var nativeView in Subviews)
updateRefreshSettings(nativeView);
}
void updateRefreshSettings(UIView view) {
if (view is UIScrollView)
{
var scrollView = view as UIScrollView;
if (scrollView.RefreshControl != null)
{
var bounds = scrollView.RefreshControl.Bounds;
scrollView.RefreshControl.Bounds = new CGRect(bounds.X, -(100), bounds.Width, bounds.Height);
}
}
//add more scrollable view types
}
}
}
You can custom a RefreshViewRenderer to achieve that .
In Android , there is a MOriginalOffsetTop to modify the offset of loading indicator . In addition , also can use SetProgressViewOffset to set the start and end position of indicator .
Code as follow :
using Android.Content;
using RefreshViewDemo.Droid;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(RefreshView), typeof(CustomRefreshViewRenderer))]
namespace RefreshViewDemo.Droid
{
public class CustomRefreshViewRenderer : RefreshViewRenderer
{
public CustomRefreshViewRenderer(Context context) : base(context)
{
MOriginalOffsetTop = 100;
// SetProgressViewOffset(true, 100, 101);
}
}
}
In iOS , the loading indicator belong to UIRefreshControl of UIScrollView , there is no direct way to change it's offset . Unless override all content view in Renderer then can achieve that . You can refer this Xamarin.Forms/Xamarin.Forms.Platform.iOS/Renderers/RefreshViewRenderer.cs to know what the RefreshView is made of .
====================Update=====================
Shared code is based on this official sample :https://learn.microsoft.com/en-us/samples/xamarin/xamarin-forms-samples/userinterface-refreshviewdemo/
For Android , just need to create a CustomRefreshViewRenderer class in android solution .
The effect of SetProgressViewOffset(true, 100, 101) , it seems like the indicator not moving :

Xamarin Forms - Change Statusbar Color crossplatform

I have a xamarin forms application and I have been able to change the navigationbar color. How can I change the statusbar color crossplatform? In the image below you can see the green navigationpagebar background color. Above that it's blue, I want to change the color of that. How can I achieve this crossplatform in xamarin forms?
You could use DependencyService .
in share project , define the interface
public interface IStatusBarColor
{
void SetColoredStatusBar(string color);
}
in Android
Firstly , install the plugin CurrentActivity from nuegt , check https://github.com/jamesmontemagno/CurrentActivityPlugin
using Android.OS;
using Android.Views;
using App24.Droid;
using App24;
using Xamarin.Forms;
using Plugin.CurrentActivity;
[assembly: Dependency(typeof(SetStatusBarColorImplemention))]
namespace App24.Droid
{
public class SetStatusBarColorImplemention : IStatusBarColor
{
public SetStatusBarColorImplemention()
{
}
public void SetColoredStatusBar(string color)
{
if (Build.VERSION.SdkInt >= BuildVersionCodes.M)
{
Device.BeginInvokeOnMainThread(() =>
{
var currentWindow = GetCurrentWindow();
currentWindow.DecorView.SystemUiVisibility = 0;
currentWindow.SetStatusBarColor(Android.Graphics.Color.ParseColor(color));
});
}
}
Window GetCurrentWindow()
{
var window = CrossCurrentActivity.Current.Activity.Window;
window.ClearFlags(WindowManagerFlags.TranslucentStatus);
window.AddFlags(WindowManagerFlags.DrawsSystemBarBackgrounds);
return window;
}
}
}
in iOS
using App24;
using App24.iOS;
using Foundation;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using ObjCRuntime;
using CoreGraphics;
[assembly: Dependency(typeof(SetStatusBarColorImplemention))]
namespace App24.iOS
{
public class SetStatusBarColorImplemention : IStatusBarColor
{
public void SetColoredStatusBar(string hexColor)
{
if(UIDevice.CurrentDevice.CheckSystemVersion(13, 0))
{
UIWindow window = UIApplication.SharedApplication.KeyWindow;
UIView view = new UIView(window.WindowScene.StatusBarManager.StatusBarFrame);
window.AddSubview(view);
Device.BeginInvokeOnMainThread(() =>
{
if (view.RespondsToSelector(new Selector("setBackgroundColor:")))
{
view.BackgroundColor = Color.FromHex(hexColor).ToUIColor();
}
UIApplication.SharedApplication.SetStatusBarStyle(UIStatusBarStyle.LightContent, false);
topViewControllerWithRootViewController(UIApplication.SharedApplication.KeyWindow.RootViewController).SetNeedsStatusBarAppearanceUpdate();
});
}
else
{
Device.BeginInvokeOnMainThread(() =>
{
UIView statusBar = UIApplication.SharedApplication.ValueForKey(new NSString("statusBar")) as UIView;
if (statusBar.RespondsToSelector(new Selector("setBackgroundColor:")))
{
statusBar.BackgroundColor = Color.FromHex(hexColor).ToUIColor();
}
UIApplication.SharedApplication.SetStatusBarStyle(UIStatusBarStyle.LightContent, false);
topViewControllerWithRootViewController(UIApplication.SharedApplication.KeyWindow.RootViewController).SetNeedsStatusBarAppearanceUpdate();
});
}
}
UIViewController topViewControllerWithRootViewController(UIViewController rootViewController)
{
if (rootViewController is UITabBarController)
{
UITabBarController tabBarController = (UITabBarController)rootViewController;
return topViewControllerWithRootViewController(tabBarController.SelectedViewController);
}
else if (rootViewController is UINavigationController)
{
UINavigationController navigationController = (UINavigationController)rootViewController;
return topViewControllerWithRootViewController(navigationController.VisibleViewController);
}
else if (rootViewController.PresentedViewController != null)
{
UIViewController presentedViewController = rootViewController.PresentedViewController;
return topViewControllerWithRootViewController(presentedViewController);
}
else
{
return rootViewController;
}
}
}
}
Now invoked the line as you want .
DependencyService.Get<IStatusBarColor>().SetColoredStatusBar("#00ff00"); // set the color of bar as green
To my knowledge you need to set the statusbar color on every platform separatly.
There are alot of questions like this here on StackOverflow and Google that can help you with that.
For Android:
check your styles.xml in Resources -> values
look for something like <item name="android:statusBarColor">#000000</item> to set the color
For iOS:
in your AppDelegate.cs look for the FinishedLaunsching-Method.
You can change the Style with UIApplication.SharedApplication.SetStatusBarStyle(UIStatusBarStyle.DarkContent, false);

Xamarin.Forms change the color of the buttons and border color in alertDialog

I have AlertDialog. Bu default the alertDialog is like this:
I want to change the color of OK button and add border color. Is there a solution for this customization .
This is my code:
await Application.Current.MainPage.DisplayAlert("Alert!", " This is DisplayAlert", "OK");
You could use [DependencyService] to call native AlerDialog and change it in specific platforms,here is a simple sample that change the color of the action button .
in Forms ,create the interface:
public interface IPopUp
{
void Popup(string title, string message,Color titleColor,Color messageColor,Color OKButtonColor ,EventHandler handler);
}
in iOS
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using App10.iOS;
using Foundation;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using App10;
[assembly: Dependency(typeof(PopupImplemention))]
namespace App10.iOS
{
public class PopupImplemention : IPopUp
{
public void Popup(string title, string message, Color titleColor, Color messageColor, Color OKButtonColor, EventHandler handler)
{
UIAlertController alertController = UIAlertController.Create(title,message,UIAlertControllerStyle.Alert);
var firstAttributes = new UIStringAttributes
{
ForegroundColor =titleColor.ToUIColor(),
};
var secondAttributes = new UIStringAttributes
{
ForegroundColor =messageColor.ToUIColor(),
};
alertController.SetValueForKey(new NSAttributedString(title, firstAttributes), new NSString("attributedTitle"));
alertController.SetValueForKey(new NSAttributedString(message, secondAttributes), new NSString("attributedMessage"));
UIAlertAction cancelAction = UIAlertAction.Create("Cancel",UIAlertActionStyle.Cancel,null);
UIAlertAction okAction = UIAlertAction.Create("OK", UIAlertActionStyle.Default,(sender)=> { handler?.Invoke(sender, new EventArgs()) ; });
okAction.SetValueForKey(OKButtonColor.ToUIColor(), new NSString("_titleTextColor"));
alertController.AddAction(cancelAction);
alertController.AddAction(okAction);
var currentViewController = topViewControllerWithRootViewController(UIApplication.SharedApplication.Delegate.GetWindow().RootViewController);
currentViewController.PresentViewController(alertController,true,null);
}
UIViewController topViewControllerWithRootViewController(UIViewController rootViewController)
{
if (rootViewController is UITabBarController)
{
UITabBarController tabBarController = (UITabBarController)rootViewController;
return topViewControllerWithRootViewController(tabBarController.SelectedViewController);
}
else if (rootViewController is UINavigationController)
{
UINavigationController navigationController = (UINavigationController)rootViewController;
return topViewControllerWithRootViewController(navigationController.VisibleViewController);
}
else if (rootViewController.PresentedViewController != null)
{
UIViewController presentedViewController = rootViewController.PresentedViewController;
return topViewControllerWithRootViewController(presentedViewController);
}
else
{
return rootViewController;
}
}
}
}
in Android
in MainActivity
public static MainActivity Intance;
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
Intance = this;
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
}
using Xamarin.Forms;
using xxx;
using xxx.Droid;
using Android;
using System;
using Xamarin.Forms.Platform.Android;
using Android.Support.V7.App;
using Android.Text;
[assembly: Dependency(typeof(PopupImplemention))]
namespace xxx.Droid
{
public class PopupImplemention : IPopUp
{
public void Popup(string title, string message, Color titleColor, Color messageColor, EventHandler handler)
{
// because html.string could not support format string , so you need to set the color directly in the string with a static value
Android.Support.V7.App.AlertDialog.Builder alert = new Android.Support.V7.App.AlertDialog.Builder(MainActivity.Intance);
alert.SetTitle(title);
alert.SetMessage(message);
alert.SetPositiveButton(Html.FromHtml("<font color='#0000ff'>OK</font>"), (senderAlert, args) =>
{
handler?.Invoke(senderAlert, args);
});
Android.Support.V7.App.AlertDialog dialog = alert.Create();
dialog.Show();
}
}
}
And call it in forms
DependencyService.Get<IPopUp>().Popup("Title","xxxxxxxxxxxx",Color.Red,Color.Blue,Color.Green,(sen,args)=> {
// handle the logic when clikc the OK button
});
You can use cross platform libraries like this one: https://github.com/aritchie/userdialogs
You will need to create a styles.xml and configure it for Android that way. There is currently no way to customize that native control through any of the Xamarin.Forms API's as far as I am aware.
Example:
<style name="AppCompatAlertDialogStyle" parent="Theme.AppCompat.Dialog.Alert">
<item name="colorAccent">#c7ac56</item>
<item name="android:textColor">#c7ac56</item>
<item name="android:background">#5c8487</item>
</style>
Here is a good tutorial on an example on how to do this: http://gmariotti.blogspot.com/2015/04/a-material-styled-alertdialog.html
If you are using Xamarin Android you probably could also hook into the AlertDialog.Builder and set the proprieties pro grammatically: https://developer.android.com/reference/android/app/AlertDialog.Builder

How to Check For Dark Mode in Xamarin.Forms

Now that iOS 13 and Android Q allow the user to enable Dark Mode at the operating system level, how can I check for it in Xamarin.Forms?
I've created this in my Xamarin.Forms project, but I'm not sure how to retrieve the values from Xamarin.iOS and Xamarin.Android.
IEnvironment.cs
using System.Threading.Tasks;
namespace MyNamespace
{
public interface IEnvironment
{
Theme GetOperatingSystemTheme();
Task<Theme> GetOperatingSystemThemeAsync();
}
public enum Theme { Light, Dark }
}
App.cs
using Xamarin.Forms;
namespace MyNamespace
{
public App : Application
{
// ...
protected override async void OnStart()
{
base.OnStart();
Theme theme = DependencyService.Get<IEnvironment>().GetOperatingSystemTheme();
SetTheme(theme);
}
protected override async void OnResume()
{
base.OnResume();
Theme theme = DependencyService.Get<IEnvironment>().GetOperatingSystemTheme();
SetTheme(theme);
}
void SetTheme(Theme theme)
{
//Handle Light Theme & Dark Theme
}
}
}
UPDATE as of April 2020:
It is no longer necessary to use platform-specific services to check for light/dark mode in Xamarin.Forms.
We can now get the current theme directly via:
OSAppTheme currentTheme = Application.Current.RequestedTheme;
where the RequestedTheme property returns an OSAppTheme enumeration member: Unspecified, Dark, or Light.
For more info: see documentation and the updated Xamarin.Forms Application.cs code.
We can use the Xamarin.Forms dependency service to access the platform-specific code from iOS and Android.
I've gone into more depth here in this blog post:
https://codetraveler.io/2019/09/10/check-for-dark-mode-in-xamarin-forms/
Xamarin.Forms Code
IEnvironment
using System.Threading.Tasks;
namespace MyNamespace
{
public interface IEnvironment
{
Theme GetOperatingSystemTheme();
Task<Theme> GetOperatingSystemThemeAsync();
}
public enum Theme { Light, Dark }
}
App.cs
using Xamarin.Forms;
namespace MyNamespace
{
public App : Application
{
// ...
protected override async void OnStart()
{
base.OnStart();
Theme theme = DependencyService.Get<IEnvironment>().GetOperatingSystemTheme();
SetTheme(theme);
}
protected override async void OnResume()
{
base.OnResume();
Theme theme = DependencyService.Get<IEnvironment>().GetOperatingSystemTheme();
SetTheme(theme);
}
void SetTheme(Theme theme)
{
//Handle Light Theme & Dark Theme
}
}
}
Xamarin.iOS
using System;
using UIKit;
using Xamarin.Forms;
using MyNamespace;
using MyNamespace.iOS;
[assembly: Dependency(typeof(Environment_iOS))]
namespace MyNamespace.iOS
{
public class Environment_iOS : IEnvironment
{
public Theme GetOperatingSystemTheme()
{
//Ensure the current device is running 12.0 or higher, because `TraitCollection.UserInterfaceStyle` was introduced in iOS 12.0
if (UIDevice.CurrentDevice.CheckSystemVersion(12, 0))
{
var currentUIViewController = GetVisibleViewController();
var userInterfaceStyle = currentUIViewController.TraitCollection.UserInterfaceStyle;
switch (userInterfaceStyle)
{
case UIUserInterfaceStyle.Light:
return Theme.Light;
case UIUserInterfaceStyle.Dark:
return Theme.Dark;
default:
throw new NotSupportedException($"UIUserInterfaceStyle {userInterfaceStyle} not supported");
}
}
else
{
return Theme.Light;
}
}
// UIApplication.SharedApplication can only be referenced by the Main Thread, so we'll use Device.InvokeOnMainThreadAsync which was introduced in Xamarin.Forms v4.2.0
public async Task<Theme> GetOperatingSystemThemeAsync() =>
Device.InvokeOnMainThreadAsync(GetOperatingSystemTheme);
static UIViewController GetVisibleViewController()
{
UIViewController viewController = null;
var window = UIApplication.SharedApplication.KeyWindow;
if (window.WindowLevel == UIWindowLevel.Normal)
viewController = window.RootViewController;
if (viewController is null)
{
window = UIApplication.SharedApplication
.Windows
.OrderByDescending(w => w.WindowLevel)
.FirstOrDefault(w => w.RootViewController != null && w.WindowLevel == UIWindowLevel.Normal);
if (window is null)
throw new InvalidOperationException("Could not find current view controller.");
viewController = window.RootViewController;
}
while (viewController.PresentedViewController != null)
viewController = viewController.PresentedViewController;
return viewController;
}
}
}
Xamarin.Android
using System;
using System.Threading.Tasks;
using Android.Content.Res;
using Plugin.CurrentActivity;
using Xamarin.Forms;
using MyNamespace;
using MyNamespace.Android;
[assembly: Dependency(typeof(Environment_Android))]
namespace MyNamespace.Android
{
public class Environment_Android : IEnvironment
{
public Task<Theme> GetOperatingSystemThemeAsync() =>
Task.FromResult(GetOperatingSystemTheme());
public Theme GetOperatingSystemTheme()
{
//Ensure the device is running Android Froyo or higher because UIMode was added in Android Froyo, API 8.0
if(Build.VERSION.SdkInt >= BuildVersionCodes.Froyo)
{
var uiModeFlags = CrossCurrentActivity.Current.AppContext.Resources.Configuration.UiMode & UiMode.NightMask;
switch(uiModelFlags)
{
case UiMode.NightYes:
return Theme.Dark;
case UiMode.NightNo:
return Theme.Light;
default:
throw new NotSupportedException($"UiMode {uiModelFlags} not supported");
}
}
else
{
return Theme.Light;
}
}
}
}
For iOS:
if (UITraitCollection.CurrentTraitCollection.UserInterfaceStyle == UIUserInterfaceStyle.Dark)
{ ... }

How to add a SearchBar to the top of page like toolbaritems icon with Xamarin.Forms

I am using masterdetail page within this page i am using tabbed page now i want to show toolbar icon and search bar on the top of page.i am able to place toolbar icon but struggling with search bar.how to place it at the top its behavior should match with the search bar in whatsapp app and in youtube app
The WhatsApp search bar is just that, a SearchBar control which you can add to your XAML layout as follows:
<StackLayout>
<SearchBar Placeholder="Search" Text="{Binding Filter}" />
<ListView ItemSource="{Binding Items}">
...
</ListView>
</StackLayout>
Ensure you have a backing property for the filter. You can use the setter of this property to intercept people filtering the data and filter the Items property accordingly.
The YouTube search behaves a bit differently. The toolbar item pops a new screen modally where the search is handled similar to a UISearchController (on iOS). There is no Xamarin Forms drop-in control (that I'm aware of) that does this for you so you'll probably have to roll your own.
We can create a custom renderer on both 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
{
readonly UISearchController _searchController;
public SearchPageRenderer()
{
_searchController = new UISearchController(searchResultsController: null)
{
SearchResultsUpdater = this,
DimsBackgroundDuringPresentation = false,
HidesNavigationBarDuringPresentation = false,
HidesBottomBarWhenPushed = true
};
_searchController.SearchBar.Placeholder = string.Empty;
}
public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
if (ParentViewController.NavigationItem.SearchController is null)
{
ParentViewController.NavigationItem.SearchController = _searchController;
DefinesPresentationContext = true;
//Work-around to ensure the SearchController appears when the page first appears https://stackoverflow.com/a/46313164/5953643
ParentViewController.NavigationItem.SearchController.Active = true;
ParentViewController.NavigationItem.SearchController.Active = false;
}
}
public override void ViewWillDisappear(bool animated)
{
base.ViewWillDisappear(animated);
ParentViewController.NavigationItem.SearchController = null;
}
public void UpdateSearchResultsForSearchController(UISearchController searchController)
{
if (Element is ISearchPage searchPage)
searchPage.OnSearchBarTextChanged(searchController.SearchBar.Text);
}
}
}
Xamarin.Android Menu XML
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'
In the Resources > menu folder, create a new file called MainMenu.xml.
Open Resources > menu > MainMenu.xml
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 (Element is ISearchPage && Element is Page page && page.Parent is NavigationPage navigationPage)
{
//Workaround to re-add the SearchView when navigating back to an ISearchPage, because Xamarin.Forms automatically removes it
navigationPage.Popped += HandleNavigationPagePopped;
navigationPage.PoppedToRoot += HandleNavigationPagePopped;
}
}
//Adding the SearchBar in OnSizeChanged ensures the SearchBar is re-added after the device is rotated, because Xamarin.Forms automatically removes it
protected override void OnSizeChanged(int w, int h, int oldw, int oldh)
{
base.OnSizeChanged(w, h, oldw, oldh);
if (Element is ISearchPage && Element is Page page && page.Parent is NavigationPage navigationPage && navigationPage.CurrentPage is ISearchPage)
{
AddSearchToToolbar(page.Title);
}
}
protected override void Dispose(bool disposing)
{
if (GetToolbar() is Toolbar toolBar)
toolBar.Menu?.RemoveItem(Resource.Menu.MainMenu);
base.Dispose(disposing);
}
//Workaround to re-add the SearchView when navigating back to an ISearchPage, because Xamarin.Forms automatically removes it
void HandleNavigationPagePopped(object sender, NavigationEventArgs e)
{
if (sender is NavigationPage navigationPage
&& navigationPage.CurrentPage is ISearchPage)
{
AddSearchToToolbar(navigationPage.CurrentPage.Title);
}
}
void AddSearchToToolbar(string pageTitle)
{
if (GetToolbar() is Toolbar toolBar
&& toolBar.Menu?.FindItem(Resource.Id.ActionSearch)?.ActionView?.JavaCast<SearchView>().GetType() != typeof(SearchView))
{
toolBar.Title = pageTitle;
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);
}
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/
Used User Control for Navbar. and hide Navigarionbar using
NavigationPage.SetHasNavigationBar (this, false);
Check following link may be it's help you. and i think it's for your requirement.
http://blog.xhackers.co/xamarin-forms-contentpage-with-searchbar-in-the-navigation-bar/
Placing a SearchBar in the top/navigation bar
How to include view in NavigationBar of Xamarin Forms?
install or update Android support repository, google play service and Google USB driver
if you'r using shell app you can use Shell.TitleView instead of Navigation.TitleView as the following :
<Shell.TitleView>
<SearchBar x:Name="search" Margin="10,10,10,10"
HorizontalOptions="FillAndExpand"/>
</Shell.TitleView>

Resources