How to add search bar in navigation bar - xamarin

I need to implement the search bar in navigation bar for android in xamarin.forms,while searching i found many examples for ios but not for android.How to achieve this for android through customrenderer?

Easy way to create a Search is to create class and make use of Filter options
like this
Search Bar Button on Top
<item android:id="#+id/action_search"
android:title="Search"
app:actionViewClass="androidx.appcompat.widget.SearchView"
app:showAsAction="always" />
Classes You May Require
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main_menu, menu);
MenuItem searchItem = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) searchItem.getActionView();
searchView.setOnQueryTextListener(this);
return true;
}
//getting text from user
#Override
public boolean onQueryTextChange(String newText) {
activity.getFilter().filter(newText);
return false;
}
//submitting Text
#Override
public boolean onQueryTextSubmit(String newText) {
activity.getFilter().filter(newText);
return false;
}
This is other Activity
public Filter getFilter() {
return filter;
}
private Filter filter = new Filter() {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
List<Pokemon> to_be_filtered = new ArrayList<>();
String filterPattern = constraint.toString().toLowerCase().trim();
//implement search
if(filterPattern.isEmpty()) {
to_be_filtered.addAll(fulllist);
}
else {
for (some this iterate over ) {
if (get_name_of_required
search.getName().toLowerCase().contains(filterPattern)) {
add_created_database_to_be_filtered.add(name of list variable);
}
}
}
In this you have to use inbuilt function called getfilter() it will handle Search bar.
Here I had used statements like to_be_filtered and add_created_database, You have to modify code according to database you are using.
I my case I am having 2 activities in which the first three class i.e. OnQuerySearch... , Submit text and Save text are in MainActivity and getFilter() is in another Activity
Thanks I hope you got your answer

Related

How to upper case entry and picker in xamarin forms?

Is there a way to force entry to uppercase and How can I uppercase the items inside the picker? If possible without using plugins
For the Entry, you can change the text to uppercase in TextChanged event.
For the Picker, you usually control the ItemsSource, you just need to uppercase every string in the ItemsSource.
public MainPage()
{
InitializeComponent();
IList<Item> dummyData= new List<Item>
{
new Item { Id = 0, Name = "Item 0" },
new Item { Id = 1, Name = "Item 1" },
new Item { Id = 2, Name = "Item 2" },
};
picker.ItemsSource = dummyData
.Select(i => i.Name.ToUpperInvariant())
.ToList();
entry.TextChanged += OnTextChanged;
}
private void OnTextChanged(object sender, TextChangedEventArgs e)
{
(sender as Entry).Text = e.NewTextValue.ToUpperInvariant();
}
If you're using MVVM, you can use a custom converter for Entry.Text and Picker.ItemsSource binding to change the value to uppercase.
If you want to force UpperCase in the Entry there are a few ways to do this but let's use Effects this time.
If you haven't heard about Effects you can quickly read what are they for here
First you will need to create the effect in the Xamarin.Forms Project.
For simplicity I will call it EntryAllCapitalEffect and the code looks like this:
namespace YourAwesomeNamespace
{
public class EntryAllCapitalEffect : RoutingEffect
{
public EntryAllCapitalEffect() : base("StackOverflow.EntryAllCapitalEffect")
{
}
}
}
Where StackOverflow is your company name and EntryAllCapitalEffect is the effect name.
Now we need to implement the effect in each one of the Platform Projects.
Let's start with Android:
Let's create a file into the Android Project with the name EntryAllCapitalEffect and add the code below as part of the implementation.
[assembly: ResolutionGroupName("StackOverflow")] //Remember your companyName ?
[assembly: ExportEffect(typeof(YourAwesomeNamespace.Droid.EntryAllCapitalEffect), "EntryAllCapitalEffect")]
namespace YourAwesomeNamespace.Droid
{
public class EntryAllCapitalEffect : PlatformEffect
{
protected override void OnAttached()
{
try
{
//Let's don't do anything if the control is not a EditText
if (!(Control is EditText editText))
{
return;
}
//Force the keyboard setup all Caps letters
// But the user can still change the Caps taping on Shift
editText.InputType = InputTypes.TextFlagCapCharacters;
// Update any lowercase into Uppercase
var filters = new List<IInputFilter>(editText.GetFilters());
filters.Add(new InputFilterAllCaps());
editText.SetFilters(filters.ToArray());
}
catch (Exception) { }
}
protected override void OnDetached()
{
}
}
}
Now let's continue with iOS
Same as of Android, let's create a file into the iOS Project with the name EntryAllCapitalEffect. Add the code below into the class.
[assembly: ResolutionGroupName("StackOverflow")] // Again your CompanyName
[assembly: ExportEffect(typeof(YourAwesomeNamespace.iOS.EntryAllCapitalEffect), "EntryAllCapitalEffect")]
namespace YourAwesomeNamespace.iOS
{
public class EntryAllCapitalEffect : PlatformEffect
{
protected override void OnAttached()
{
try
{
if (!(Control is UITextField uiTextField))
{
return;
}
//Force the keyboard setup all Caps letters
// But the user can still change the Caps taping on Shift
uiTextField.AutocapitalizationType = UITextAutocapitalizationType.AllCharacters;
//Delegate to replace any Lowercase entry into UpperCase
uiTextField.ShouldChangeCharacters = OnShouldChangeCharacters;
}
catch (Exception) { }
}
protected override void OnDetached()
{
}
private bool OnShouldChangeCharacters(UITextField textfield, NSRange range, string replacementString)
{
using (NSString original = new NSString(textfield.Text), newString = new NSString(replacementString.ToUpper()))
{
textfield.Text = original.Replace(range, newString);
}
return false;
}
}
}
Ok so now to use it just assign it to any Entry in the XAML like this:
<Entry HorizontalOptions="FillAndExpand" Placeholder="Enter Text here" >
<Entry.Effects>
<local:EntryAllCapitalEffect />
</Entry.Effects>
</Entry>
Remember to add the local alias in the XAML
xmlns:local="clr-namespace:YourAwesomeNamespace"
This will be the namespace where your Effect is found.
Note: Your CompanyName can be anything but it must match is all placed this is used.
Note 2: If you have other Effects you don't need to repeat the CompanyName Registration. This is done only once by platform.
Hope this helps.-
Here is on more solution based on #Roger Leblanc's answer
Create a behavior:
public class AllCapsBehavior : Behavior<Entry>
{
protected override void OnAttachedTo(Entry entry)
{
entry.TextChanged += OnEntryTextChanged;
base.OnAttachedTo(entry);
}
protected override void OnDetachingFrom(Entry entry)
{
entry.TextChanged -= OnEntryTextChanged;
base.OnDetachingFrom(entry);
}
private static void OnEntryTextChanged(object sender, TextChangedEventArgs args)
{
((Entry)sender).Text = args.NewTextValue.ToUpperInvariant();
}
}
Add namespace reference to view:
xmlns:behav="clr-namespace:yourproject.Resources.Behaviors"
Add behavior to Entry:
<Entry>
<Entry.Behaviors>
<behav:AllCapsBehavior/>
</Entry.Behaviors>
</Entry>

How to know if Unity UI button is being held down?

I am using Unity 5.2 UI. I am working on a game for iOS. I have a custom keyboard. I want to add the functionality to the del/backspace key so that when i hold the del key for more than 2 secs, it deletes the whole word instead of a single letter, which it deletes on single clicks. How do I achieve that?
Using the UGUI event you'd create a script like the following and attach it to your button:
using UnityEngine;
using UnityEngine.EventSystems;
public class LongPress : MonoBehaviour, IPointerDownHandler, IPointerUpHandler {
private bool isDown;
private float downTime;
public void OnPointerDown(PointerEventData eventData) {
this.isDown = true;
this.downTime = Time.realtimeSinceStartup;
}
public void OnPointerUp(PointerEventData eventData) {
this.isDown = false;
}
void Update() {
if (!this.isDown) return;
if (Time.realtimeSinceStartup - this.downTime > 2f) {
print("Handle Long Tap");
this.isDown = false;
}
}
}

Create a Layout Item for ListView in Xamarin Android

I have a problem and It's 10 days that I am working and can't solve it.I made a layout for each row for ListView.This Layout Contains a linearLayout that there is a TextView and a WebView inside it.Now I Need a C# Project that I can add a new Row to the ListView with new text and url whenever I want.For Example: button.click { ListView.add(Resource.Layout.Items, "Text","Url")}..I know this command is wrong. Just I wanted to clear the problem for you.
I khnow it's custom Row layout and I read manny examples at this site other sites and Xamarin site about that,adapters,... but I can't do it. :(
Please answer me correctly.
It is very important for me.
Thanks a lot.
You need to create an adapter that can work with you custom objects as items. It could look like the following sample:
public class MyAdapter : BaseAdapter<MyItem>
{
readonly LayoutInflater inflater;
List<MyItem> myItemList;
public MyAdapter(Context context)
{
inflater = LayoutInflater.FromContext(context);
myItemList = YOUR_DATASOURCE.GetMyItems();
}
public override MyItem this [int index]
{
get { return myItemList[index]; }
}
public override int Count
{
get { return myItemList.Count; }
}
public override long GetItemId(int position)
{
return position;
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
View view = convertView ?? inflater.Inflate(Resource.Layout.MyItemLayout, parent, false);
var item = myItemList[position];
var viewHolder = view.Tag as MyViewHolder;
if (viewHolder == null)
{
viewHolder = new MyViewHolder();
viewHolder.Web = view.FindViewById<WebView>(Resource.Id.MyItemLayout_Icon);
viewHolder.Name = view.FindViewById<TextView>(Resource.Id.MyItemLayout_Title);
view.Tag = viewHolder;
}
viewHolder.Web.Url = item.Url; //You need to check how you have to set the url for a WebView
viewHolder.Name.Text = item.Text;
return view;
}
public override void NotifyDataSetChanged()
{
myItemList = YOUR_DATASOURCE.GetMyItems();
base.NotifyDataSetChanged();
}
}
class MyViewHolder : Java.Lang.Object
{
public WebView Web { get; set; }
public TextView Name { get; set; }
}
You apply the adapter to your ListView with ListView.Adapter = new MyAdapter(Activity);. Each time you change an item in you button click event, you tricker (ListView.Adapter as MyAdapter).NotifyDataSetChanged(); which will force the adapter to reload and refresh the data.
YOUR_DATASOURCE represents the point in your code where you store the informations like the url or text of all your items. This could typically be a database or something similar. While GetMyItems() is a method for example to query your database.
Hope this clears things up.

JFace TreeView not launching when Input is a String

I'm trying launch a simple JFace Tree.
It's acting really strange however. When I setInput() to be a single String, the tree opens up completely blank. However, when I set input to be a String array, it works great.
This has nothing to do with the LabelProvider or ContentProvider since these behave the same no matter what (it's a really simple experimental program).
setInput() is officially allowed to take any Object. I am confused why it will not take a String, and knowing why may help me solve my other problems in life.
Setting a single String as input:
TreeViewer treeViewerLeft = new TreeViewer(shell, SWT.SINGLE);
treeViewerLeft.setLabelProvider(new TestLabelProvider());
treeViewerLeft.setContentProvider(new TestCompareContentProvider());
treeViewerLeft.expandAll();
treeViewerLeft.setInput(new String("Stooge"));
Setting an array of Strings:
TreeViewer treeViewerLeft = new TreeViewer(shell, SWT.SINGLE);
treeViewerLeft.setLabelProvider(new TestLabelProvider());
treeViewerLeft.setContentProvider(new TestCompareContentProvider());
treeViewerLeft.expandAll();
treeViewerLeft.setInput(new String[]{"Moe", "Larry", "Curly"});
The second works, and launches a tree using the following providers:
public class TestCompareContentProvider extends ArrayContentProvider implements ITreeContentProvider {
public static int children = 0;
public Object[] getChildren(Object parentElement) {
children++;
if (children > 20){
return null;
}
return new String[] {"Moe", "Larry", "Curly"};
}
public Object getParent(Object element) {
return "Parent";
}
public boolean hasChildren(Object element) {
if (children >20){
return false;
}
return true;
}
}
and
public class TestLabelProvider extends LabelProvider {
public String getText(Object element){
return "I'm something";
}
public Image getImage(Object element){
return null;
}
}
You've inherited getElements from the ArrayContentProvider and that only works with arrays. You should override this method.
I don't think you need to extend ArrayContentProvider at all.

Caliburn Micro Communication between ViewModels

hopefully you can help me. First of all, let me explain what my problem is.
I have two ViewModels. The first one has e.g. stored information in several textboxes.
For example
private static string _tbxCfgLogfile;
public string TbxCfgLogfile
{
get { return _tbxCfgLogfile; }
set
{
_tbxCfgLogfile = value;
NotifyOfPropertyChange(() => TbxCfgLogfile);
}
}
The other ViewModel has a Button where i want to save this data from the textboxes.
It does look like this
public bool CanBtnCfgSave
{
get
{
return (new PageConfigGeneralViewModel().TbxCfgLogfile.Length > 0 [...]);
}
}
public void BtnCfgSave()
{
new Functions.Config().SaveConfig();
}
How can i let "CanBtnCfgSave" know that the condition is met or not?
My first try was
private static string _tbxCfgLogfile;
public string TbxCfgLogfile
{
get { return _tbxCfgLogfile; }
set
{
_tbxCfgLogfile = value;
NotifyOfPropertyChange(() => TbxCfgLogfile);
NotifyOfPropertyChange(() => new ViewModels.OtherViewModel.CanBtnCfgSave);
}
}
It does not work. When i do remember right, i can get the data from each ViewModel, but i cannot set nor Notify them without any effort. Is that right? Do i have to use an "Event Aggregator" to accomplish my goal or is there an alternative easier way?
Not sure what you are doing in your viewmodels - why are you instantiating viewmodels in property accessors?
What is this line doing?
return (new PageConfigGeneralViewModel().TbxCfgLogfile.Length > 0 [...]);
I can't be sure from your setup as you haven't mentioned much about the architecture, but sincce you should have an instance of each viewmodel, there must be something conducting/managing the two (or one managing the other)
If you have one managing the other and you are implementing this via concrete references, you can just pick up the fields from the other viewmodel by accessing the properties directly, and hooking the PropertyChanged event of the child to notify the parent
class ParentViewModel : PropertyChangedBase
{
ChildViewModel childVM;
public ParentViewModel()
{
// Create child VM and hook up event...
childVM = new ChildViewModel();
childVM.PropertyChanged = ChildViewModel_PropertyChanged;
}
void ChildViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
// When any properties on the child VM change, update CanSave
NotifyOfPropertyChange(() => CanSave);
}
// Look at properties on the child VM
public bool CanSave { get { return childVM.SomeProperty != string.Empty; } }
public void Save() { // do stuff }
}
class ChildViewModel : PropertyChangedBase
{
private static string _someProperty;
public string SomeProperty
{
get { return _someProperty; }
set
{
_someProperty = value;
NotifyOfPropertyChange(() => SomeProperty);
}
}
}
Of course this is a very direct way to do it - you could just create a binding to CanSave on the child VM if that works, saving the need to create the CanSave property on the parent

Resources