after taking a look at the app by google called google keep, I was immediately curious on how exactly does the search of the app works.
Here is the image of the app:
Whenever you search something, the card that doesn't match would disappear. How exactly do they achieve this because I think that the card are basically custom views and the layout is a custom layout. My problem is that I don't know how to implements a search for custom view.
Note: I have taken a look at some internet example online for search view and I can only find the implementation of searches for listview which is not precisely what I want.
I had a similar problem, so I made my Custom views properties (e.g. name, tag, id, etc...) into a single String spaced by a single space " ".
Something like this inside my CustomView class:
public String toString() {
return (this.name + " " + this.tag + " " + this.coords + " " + this.id );
}
And then I filtered my Custom views through all current Custom views that were shown:
ArrayList<CustomView> filteredList = new ArrayList<>();
...
private void filter(String constraint) {
for(CustomView view : AllViews) {
if (!filteredList.contains(view))
if (view.toString().toLowerCase().contains(constraint.toLowerCase())) {
filteredList.add(view);
break;
}
}
}
// Do something to add the filteredList to your adapter
// and show the new list of CustomViews.
}
You can call filter(newText) method inside onQueryTextChange(String newText) from SearchView OnQueryTextListener().
This way, if whatever word you type in the SearchView is found anywhere in any CustomView, the correspondent CustomView will be visible, otherwise the view will "disappear".
Hope this helps.
Related
When I attempt to read from SQLite and use adapter.NotifyDataSetChanged. I don't see any changes in my recyclerView.
The main idea is to search in SQLite where the name contains a value from a textView.
Then to repopulate again my adapter.
I create an Instance
private List<InventoryPreviewClass> mItems;
private RecyclerView mRecyclerView;
adpInventoryPreview adapter;
Then inside onCreate() method
mItems = db.Query<InventoryPreviewClass>("select * from InventoryPreviewClass where CategoryID =" + CategoryID + ""); //Here i am reading from sqlite
mRecyclerView.HasFixedSize = true;
var layout = new GridLayoutManager(this, InventoryRowsPerLine, GridLayoutManager.Vertical, false);
mRecyclerView.SetLayoutManager(layout);
adapter = new adpInventoryPreview(mItems);
mRecyclerView.SetAdapter(adapter);
Until now the code works.
My recyclerView is populated with my items from sqlite.
Here is the method when a user types something in TextView
private void EtSearchAlwaysOn_TextChanged(object sender, Android.Text.TextChangedEventArgs e)
{
mItems = db.Query<InventoryPreviewClass>("select * from InventoryPreviewClass where InventoryItemName like '%" + etSearchAlwaysOn.Text.ToUpper() + "%'");
adapter.NotifyDataSetChanged();
}
When I am typing something nothing changes in my recyclerView.
Why is this happening?
The only way I found that this works is to reset my items inside my adapter for example:
mItems = db.Query<InventoryPreviewClass>("select * from InventoryPreviewClass where InventoryItemName like '%" + etSearchAlwaysOn.Text.ToUpper() + "%'");
adapter = new adpInventoryPreview(mItems);
mRecyclerView.SetAdapter(adapter);
Why is this happening? I don't think that the second method is right.
This is happening because you are assigning a new object to mItems
The first time you create the mItems list, you pass it onto your adapter, when the next time you are getting a response from your SQLite DB is creating a new instance of the list since you are assigning it to the object.
What you need to do is
Create a method in the adapter that accepts your items like adapter.updateItems(newItems)
The method should clear the list like items.clear() and then add the new items you passed it with items.addAll(newItems)
After that you can call notifyDataSetChanged() within the adapter itself and it will work.
In your, adapter it will look like this
public void updateItems(final List<InventoryPreviewClass> newItems) {
items.clear();
items.addAll(newItems);
notifyDataSetChanged();
}
and then you can call it like this
updatedList = db.Query<InventoryPreviewClass>("select * from InventoryPreviewClass where CategoryID =" + CategoryID + "");
adapter.updateItems(updatedList);
I think you missed the point that this is the typical case of pass by value and not pass by reference.
This is a byRef issue.
You pass memory pointer 1 to your adapter and tell it to monitor for changes.
Then you load a list and repoint your memory pointer to spot 2.
Then you tell adapter that it's monitored memory at pointer 1 has changed.
You have two options.
Modify the original list by comparing new results with old results, removing and adding as necessary
or Tell the adapter it has a new memory pointer that it is monitoring by changing the items inside the adapter. Making a method for swapItems(items) will work. Then call notifyDataSetChanged inside the adapter.
you have to set items in your adapter,
create a setter like this :
private List<InventoryPreviewClass> mItems;
.
.
.
public void setItems(List<InventoryPreviewClass> items)
{
mItems=items;
}
and then update your search method like this
private void EtSearchAlwaysOn_TextChanged(object sender,
Android.Text.TextChangedEventArgs e)
{
mItems = db.Query<InventoryPreviewClass>("select * from InventoryPreviewClass
where InventoryItemName like '%" + etSearchAlwaysOn.Text.ToUpper() + "%'");
adapter.setItems(mItems);
adapter.NotifyDataSetChanged();
}
Notify adapter after you set adapter.
mItems = db.Query<InventoryPreviewClass>("select * from InventoryPreviewClass where InventoryItemName like '%" + etSearchAlwaysOn.Text.ToUpper() + "%'");
adapter = new adpInventoryPreview(mItems);
mRecyclerView.SetAdapter(adapter);
adapter.notifyDataSetChanged();
I am currently making a form for film database, using Vaadin. My problem is the whole situation with deep linking. I want to have a url with an id of movie in it, to make possible to get to the form of concrete movie.
localhost:port/filmView/idOfSelectedMovie
I am currently using pushState but there are couple of problems.
1) When I add string "Film/" before Id, the first selection works fine, however with following selections the url just keeps adding this.
http://localhost:8081/Film/Film/Film/Film/Film/4
2) The second option I tried was using just an id. The effect was that the url just keeps the host with port, and gets rid of ViewName
http://localhost:8801/4
I had already tried to use replaceState and Urifragment methods, the effect wasn't better at all.
the function handling selection of movie on the list
this.itemsList.addSelectionListener(selectionEvent -> {
if (selectionEvent.getFirstSelectedItem().isPresent()) {
Film selectedFilm = selectionEvent.getFirstSelectedItem().get();
this.setupForm(selectedFilm);
Page.getCurrent().pushState("Film/" + selectedFilm.getFilmId());
}
});
What you have to do while navigating between views this: let's say you have a View with a list of films, from you can select a film. When you select a film from that list, you move to the film View
getUI().getNavigator().navigateTo(FilmView + "/" + filmId); //let's say id 88
in this way, you will navigate to http://localhost:8081/Film/88
now, in your FilmView you can get and use this id, something like:
public class FilmView extends VerticalLayout implements View{
#Override
public void enter(ViewChangeEvent event) {
String yourPassedId = event.getParameters();
//do stuff with your id, for example loading from DB
}
}
In this way, you can reach every film you want with hard link, like http://localhost:8081/Film/88
I am trying to get TalkBack to say what is in the text that is inside the host View, along with " is cool" afterwards.
To do this, I am setting an accessibility delegate on a linear layout, but the info parameter's text and contentDescription properties are always null. i.e. info.getText() and info.getContentDescription() are always returning null. I cannot seem to extract the text from the nested TextViews.
The host parameter is thus a linear layout, which contains another nested linear layout inside of it. This nested linear layout in turn contains more nested layouts and text views as their children. (I am targeting API 21+)
linearLayout.setAccessibilityDelegate(new View.AccessibilityDelegate()
{
#Override
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info)
{
super.onInitializeAccessibilityNodeInfo(host, info);
String newWordsToSay = info.getText() + " is cool"
//info.getText() CRASHES due to null pointer exception
info.setContentDescription(info.setText(newWordsToSay));
}
});
EDIT: On checking the host param, all of the expected nested TextViews are there, with their respective text fields. The problem is, I cannot seem to extract the text from them.
Any help would be appreciated.
It looks like you have to iterate over the children.
You can collect the children relevant for accessibility using View::addChildrenForAccessibility(ArrayList<View> list) method, it fills the passed list. Then you can concatenate their texts:
super.onInitializeAccessibilityNodeInfo(host, info);
ArrayList<View> childrenViews = new ArrayList<>();
host.addChildrenForAccessibility(childrenViews);
StringBuilder text = new StringBuilder();
for (View view : childrenViews) {
if (view instanceof TextView) {
text.append(((TextView)view).getText());
}
}
text.append(" is awesome");
info.setContentDescription(text.toString());
Is it possible to display the following data from sqlite database in a listview instead of a toast as shown in the code below ?
btnlist = (Button) findViewById(R.id.btnlist);
btnlist.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
handler = new Datahandler(getBaseContext());
String getName, getaddress, getDate, getTime, getSchoolName;
getName = "";
getaddress = "";
getDate = "";
getTime = "";
getSchoolName = "";
handler.open();
Cursor C = handler.returnData();// return actual data from
// database
if (C.moveToFirst()) {
do {
getName = C.getString(0);
getaddress = C.getString(1);
getDate = C.getString(2);
getTime = C.getString(3);
getSchoolName = C.getString(4);
} while (C.moveToNext());
}
handler.close();
Toast.makeText(
getBaseContext(),
" Name :" + getName + "Address :"
+ getaddress + "Date :" + getDate + "Time :"
+ getTime + "School :" + getSchoolNname,
Toast.LENGTH_LONG).show();
}
});
}
By list view I'm assuming you mean the first row to have the name, second row to have address, third to have date and so forth? If so I would suggest that you actually make 10 textviews, 5 for labels, and 5 for data. You can put them into a scroll view if you need scrolling. Once you have these text views call .setText(...) on the 5 ones with data to populate them with the data you have in the variables such as getName.
The reason I say to do this is to stay more consistent with typical Android design. Typically list views are used to show lists of data where each row shows different values for the same key such as your contacts. It looks like you will always have five data points so we don't need the overhead of a list view and a static set of text views will serve this purpose just fine.
yes of course its possible :)
You've already done the hard work of getting the data out of the database.
I've put together a super quick example for you. Obviously you'll need to fill in the gaps by reading about a bit and following a few tutorials. Here's a good start:
http://www.vogella.com/tutorials/AndroidListView/article.html
http://webdeveloperpadawan.blogspot.co.uk/2014/09/android-listview-with-differing-rows.html
What you need to do is create a custom object for your student details or whatever they are. Then instead of doing
String getName = C.getString(0)
you would do something like this:
List<Student> students;
Student student;
do{
student.setName(C.getString(0));
...
//Then you add that student into a List of students
students.add(student);
}
Then create a custom adapter which extends your list of students:
public class AdapterStudents extends ArrayAdapter<Student>{
//...
}
Then you create an instance of your adapter and finally just set that adapter to your listview.
As I say follow a few tutorials for more specifics but there's your basic plan of action :)
Good luck.
How can I retrieve the View at the position X in a ListView? I dont want to inflate a new one, just retrieve the cell visible in the screen for change some parameters programmatically
Since views in ListView are re-used/re-cycled. There is no direct way of getting a view reference from the ListView.
If you want to access a view you need to extend ArrayAdapter and then override getView. There you should call the super.getView and write your own custom code.
If we you really need to control more than try extending BaseAdapter or CursorAdapter.
Found a dirty solution:
You should be able of identify each row generated. For example adding a TextView with visibility=gone and writing a unique value there when generating (or recycling the row)
In the listactivity call to getListView.setSelection(position) to the desired cell
Survey the listview list for the row (until displayed)
lv=getListView();
for (int i=0;i <lv.getChildCount();i++){
if (((TextView)lv.findViewById(R.id.my_hidden_textview)).getText.equals(mykey)){
// view found
} else {
// schedule another survey "soon"
}
}
For the schedule you can use something like:
final int RETRY_DELAY=100;
new Handler(){
public void handleMessage(Message msg){
if (msg.what<0) return; //something went wrong and retries expired
lv=getListView();
for (int i=0;i <lv.getChildCount();i++){
if (((TextView)lv.findViewById(R.id.my_hidden_textview)).getText.equals(mykey)){
//result = lv.findViewById(R.id.my_hidden_textview);
} else {
this.sendEmptyMessageDelayed(msg.what-1,RETRY_DELAY);
}
}
}
}.sendEmptyMessageDelayed(10,RETRY_DELAY);
As I said is a very ugly solution but it works
I didn't clearly understand your problem. But to what I've understood I would suggest you use a frame layout within a linear layout. You can use another frame layout to do your manipulations.