How to change the color of searchbar search icon and cancel button color in xamarin forms - xamarin.forms

How to change the color of searchbar icon from xaml, I want to change the cancel and search icon color of a search bar in xamarin forms application.How to implement this. Please help on this

As adamm said, you can modify the "cancel button color" via CancelButtonColor.
Similarly, if you want to implement a custom SearchBar in iOS, you can also create a custom renderer for it.
For UISearchBar, you can modify the color of the icon via SearchTextField.LeftView.TintColor.
[assembly: ExportRenderer(typeof(MySearchBar), typeof(MySearchBarRenderer))]
namespace searchbar.iOS
{
public class MySearchBarRenderer : SearchBarRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<SearchBar> e)
{
base.OnElementChanged(e);
if (Control != null)
{
Control.BackgroundColor = UIColor.Yellow;
UISearchBar searchbar = Control as UISearchBar;
searchbar.SearchTextField.LeftView.TintColor = UIColor.Orange;
// UPDATE
var clearButton = searchbar.SearchTextField.ValueForKey((Foundation.NSString)"clearButton") as UIButton;
//clearButton.SetTitleColor(UIColor.Blue, UIControlState.Normal);
//clearButton.TintColor = UIColor.Orange;
clearButton.SetImage(UIImage.FromBundle("CloseIcon.png"), UIControlState.Normal);
}
}
}
}

Cancel button color can be change by setting CancelButtonColor:
<SearchBar Placeholder="Search items..."
CancelButtonColor="Orange"
PlaceholderColor="Orange"
TextColor="Orange"
TextTransform="Lowercase"
HorizontalTextAlignment="Center"
FontSize="Medium"
FontAttributes="Italic" />
For the icon color you need to use custom renderers.
For example, on Android you can create a new file (something like SearchBar.Droid.cs) and add this in it:
using Android.Content;
using Android.Widget;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(Xamarin.Forms.SearchBar), typeof(MyApp.Renderers.SearchBarIconColorCustomRenderer))]
namespace MyApp.Renderers
{
public class SearchBarIconColorCustomRenderer : SearchBarRenderer
{
public SearchBarIconColorCustomRenderer(Context context) : base(context) { }
protected override void OnElementChanged(ElementChangedEventArgs<SearchBar> e)
{
base.OnElementChanged(e);
var icon = Control?.FindViewById(Context.Resources.GetIdentifier("android:id/search_mag_icon", null, null));
(icon as ImageView)?.SetColorFilter(Color.Orange.ToAndroid());
}
}
}
Edit:
For iOS, try something like this (I didn't test it):
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ExportRenderer(typeof(Xamarin.Forms.SearchBar), typeof(MyApp.iOS.Renderers.iOSSearchBarIconColorCustomRenderer))]
namespace MyApp.iOS.Renderers
{
public class iOSSearchBarIconColorCustomRenderer : SearchBarRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<SearchBar> e)
{
base.OnElementChanged(e);
if (Control != null)
{
var searchbar = (UISearchBar)Control;
searchbar.TintColor = UIColor.Orange;
}
}
}
}

Related

Xamarin Forms overriding Android switch property using Effects

I would like to override the On/Off text of a switch using an Effect rather than a custom renderer.
In Android, I have the following code:
protected override void OnAttached()
{
try
{
if (Control is Android.Widget.Switch control)
{
control.TextOn = "Yes";
control.TextOff = "No";
}
}
OnAttached executes as expected but 'Control' is not an Android.Widget.Switch control but of a related type, e.g. 'android.support.v7.widget.SwitchCompat'. How can I make the code recognize that it should update the text in this case?
Do you want to achieve the result like following effect?
You can achieve it like following code.
using Android.Runtime;
using Android.Support.V7.Widget;
using Android.Views;
using Android.Widget;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ResolutionGroupName("MyCompany")]
[assembly: ExportEffect(typeof(SwitchDemo.Droid.ClickEffect), nameof(SwitchDemo.Droid.ClickEffect))]
namespace SwitchDemo.Droid
{
public class ClickEffect : PlatformEffect
{
protected override void OnAttached()
{
// throw new NotImplementedException();
if (Control is SwitchCompat control)
{
control.ShowText = true;
control.TextOn = "Yes";
control.TextOff = "No";
}
}
protected override void OnDetached()
{
//throw new NotImplementedException();
}
}
}
Here is PCL code.
ClickEffect.cs
public class ClickEffect: RoutingEffect
{
public ClickEffect() : base($"MyCompany.{nameof(ClickEffect)}")
{
}
}
Use it in xaml.
<Switch>
<Switch.Effects>
<local:ClickEffect/>
</Switch.Effects>
</Switch>

Xamarin.Forms Editor Control on iOS needs something to mark where numeric entry should be

On Android, when using an Editor control straight out of the box it is clear where the text/numeric data should be entered:
On iOS it is not so obvious and I find myself having to guess where to press to bring the control in to focus:
The code shared across the controls:
<Editor Grid.Row="1" Grid.Column="1"
Text="SomeTextHere"
VerticalOptions="Center"
Keyboard="Numeric"
HorizontalOptions="CenterAndExpand"
WidthRequest="68"
MinimumWidthRequest="68"
/>
I'm not averse to writing a custom control if I have to, but is there an easier way?
Please note that I don't want to use placeholder text.
You can use CustomRenderer to implement it.
Solution1
You can set the border of the Editor in iOS .
using Foundation;
using UIKit;
using CoreGraphics;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using xxx.iOS;
[assembly:ExportRenderer(typeof(Editor),typeof(MyEditorRenderer))]
namespace xxx.iOS
{
public class MyEditorRenderer:EditorRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
{
base.OnElementChanged(e);
if(Control!=null)
{
Control.Layer.MasksToBounds = true;
Control.Layer.BorderWidth = 1.0f;
Control.Layer.BorderColor = UIColor.Black.CGColor;
}
}
}
}
Solution2
If you do want to it display like in Android (only an under line)
using Foundation;
using UIKit;
using CoreGraphics;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using xxx.iOS;
[assembly:ExportRenderer(typeof(Editor),typeof(MyEditorRenderer))]
namespace xxx.iOS
{
public class MyEditorRenderer:EditorRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
{
base.OnElementChanged(e);
if(Control!=null)
{
UIView lineView = new UIView() {
Frame = new CGRect(0,Element.HeightRequest-1,Element.WidthRequest, 1),
BackgroundColor = UIColor.Black,
};
Control.AddSubview(lineView);
}
}
}
}
And you need to set the HeightRequest and WidthRequest in Xaml .

Rounded corner for Entry - Xamarin forms UWP

Is there anything possible to customize the radius of Entry to having a slightly rounded corner?
You can use Custom Renderer in xamarin.forms
in iOS
//...
using App11;
using App11.iOS;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ExportRenderer(typeof(MyEntry), typeof(MyiOSEntry))]
namespace App11.iOS
{
public class MyiOSEntry:EntryRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (Control != null)
{
Control.Layer.MasksToBounds = true;
Control.Layer.CornerRadius = 10; //set the rounded corner
Control.Layer.BorderColor = UIColor.Red.CGColor;
Control.Layer.BorderWidth = 3;
}
}
}
}
in Android
creat a xml file in the folder Resource->drawable edit_text_style.xml
<?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="#ffffff" />
<corners
android:radius="10dp" />
<stroke
android:width="2dp"
android:color="#3bbdfa" />
</shape>
</item>
in Custom Renderer
using Android.Support.V4.Content.Res;
using App11;
using App11.Droid;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(MyEntry), typeof(MyAndriodEntry))]
namespace App11.Droid
{
public class MyAndriodEntry:EntryRenderer
{
public MyAndriodEntry(Context context):base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if(Control!=null)
{
Control.SetBackground(ResourcesCompat.GetDrawable(Resources, Resource.Drawable.edit_text_style, null) );
}
}
}
}
in UWP
create a folder named Styles and add a new item as type Resource Dictionary and name it Dictionary1.xaml
in Dictionary1.xaml put this code for a rounded Textbox .
in Custom Renderer
using App11;
using App11.UWP;
using Windows.UI.Xaml.Controls;
using Xamarin.Forms;
using Xamarin.Forms.Platform.UWP;
[assembly: ExportRenderer(typeof(MyEntry), typeof(MyUWPEntry))]
namespace App11.UWP
{
public class MyUWPEntry:EntryRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if(Control!=null)
{
Control.Style = (Windows.UI.Xaml.Style)App11.UWP.App.Current.Resources["StyleRoundedTextBox"];
}
}
}
}
how do I changed this style and how do I create this code ?
It's simple , in msdn.com search for "objectName" default style in uwp then you will find default style for the object you need . change it in the way you want and add it to application resources directly or link it (like what I did here) then load your style in CustomRenderer
for more detail about UWP yo can refer here
in Forms
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
namespace App11
{
public class MyEntry : Entry
{
public MyEntry()
{
}
}
}
in xxx.cs file
Content = new StackLayout
{
Children = {
new MyEntry {Text = "In Shared Code",}
},
VerticalOptions = LayoutOptions.CenterAndExpand,
HorizontalOptions = LayoutOptions.CenterAndExpand,
};
For Windows app you can customize an entry using a renderer.
public class CustomEntryRenderer : ViewRenderer<CustomEntry, TextBox>
{
protected override void OnElementChanged(ElementChangedEventArgs<CustomEntry> e)
{
base.OnElementChanged(e);
var textBox = new TextBox();
textBox.BorderThickness = new Windows.UI.Xaml.Thickness(1);
textBox.BorderBrush = new SolidColorBrush(GetSolidColorBrush("#444444").Color);
textBox.CornerRadius = new Windows.UI.Xaml.CornerRadius(10);
this.SetNativeControl(textBox);
}
public SolidColorBrush GetSolidColorBrush(string hex)
{
hex = hex.Replace("#", string.Empty);
byte r = (byte)(Convert.ToUInt32(hex.Substring(0, 2), 16));
byte g = (byte)(Convert.ToUInt32(hex.Substring(2, 2), 16));
byte b = (byte)(Convert.ToUInt32(hex.Substring(4, 2), 16));
SolidColorBrush myBrush = new SolidColorBrush(Windows.UI.Color.FromArgb(255, r, g, b));
return myBrush;
}
}
Holy shmoley it's not that hard.
Unless I'm missing something, just wrap it in a Frame that has IsClippedToBounds set to true and then put a corner radius on the frame.
Maybe there's some reason that's not a good solution, I guess, but it's one I use a lot.

Custom Layout under Editor / Entry

I have an Entry/Editor in Xamarin.Forms, and I want a layout to appear underneath it, as long as it is focused.
The layout consists of a Grid with multiple Buttons in it.
I have added the Grid underneath the Editor in my Layout and toggle its visibility based on the IsFocused property of the Editor.
Sadly, when I press one of the Grids buttons, the Editor loses focus and thus the Layout will go invisibile.
EDIT:
Another very important point is, that the Grid can overlap other controls, currently this is happening, since im adding both the Editor and the Grid into another Grid as the last children.
I might have to workaround this as well, maybe just put this Grid into an android relative layout and add this layout to the native EditText?
I want it to remain visible after clicking one of the buttons. How should I approach this scenario?
I would write EditorRenderer for each platform and there add all buttons, it should fix Focus problem (as you never lost focus :))
Implementation example:
using System;
using Xamarin.Forms;
namespace Common
{
public class CustomEditor : Editor
{
public Action<string> ButtonXCallback { get; set; }
}
}
IOS:
using Common.iOS;
using Common;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ExportRenderer(typeof (CustomEditor), typeof (CustomEditorRenderer))]
namespace Common.iOS
{
public class CustomEditorRenderer : EditorRenderer
{
private UIButton ButtonX { get; set; }
protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
{
base.OnElementChanged(e);
var element = Element as CustomEditor;
if (Control != null && element != null)
{
if (ButtonX == null)
{
ButtonX = new UIButton();
ButtonX.SetImage(UIImage.FromBundle("ico_x.png"), UIControlState.Normal);
ButtonX.TouchUpInside += (sender, f) => {
var text = Control.Text;
if (element.ButtonXCallback != null)
element.ButtonXCallback.Invoke(text);
};
Control.AddSubview(ButtonX);
}
}
}
}
}
Droid:
using System;
using Android.Content;
using Android.Graphics;
using Android.Graphics.Drawables;
using Android.Graphics.Drawables.Shapes;
using Common.Droid;
using Common;
using Android.Text;
using Android.Widget;
using Android.Runtime;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using Android.Views;
[assembly: ExportRenderer(typeof (CustomEditor), typeof (CustomEditorRenderer))]
namespace Common.Droid
{
public class CustomEditorRenderer : EditorRenderer
{
private ImageButton ButtonX { get; set; }
protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
{
base.OnElementChanged(e);
if (Control == null)
return;
if (Element == null)
return;
var element = (CustomEditor) Element;
if (element == null)
return;
if (ButtonX == null)
{
ButtonX = new ImageButton(Context);
ButtonX.SetImageResource(Resource.Drawable.ico_x);
ButtonX.SetBackgroundColor(Android.Graphics.Color.Transparent);
ButtonX.Click += (sender, f) =>
{
var text = Control.Text;
if (element.ButtonXCallback != null)
element.ButtonXCallback.Invoke(text);
};
AddView(ButtonX);
}
}
}
}

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