Search interface with swipe tabs android - java

I need some help to implement search ability in different swipe tabs.
I have an Activity A which is also the main activity for my search interface (search bar at the top). This activity should pass the search string to respective fragments based on the tabs, All, Organizations, and persons.
I am not able to figure out how can I pass search string to the respective fragments. Does anyone have any suggestions or working code which i can refer to ?
Thanks
Please find the attached snapshot.

In your Activity, declare a public variable
public String search;
In the onCreateOptionsMenu() of your Activity, add
SearchView searchView = (SearchView) menu.findItem(R.id.menu_search)
.getActionView();
SearchView.OnQueryTextListener queryTextListener = new SearchView.OnQueryTextListener() {
public boolean onQueryTextChange(String newText) {
return true;
}
public boolean onQueryTextSubmit(String query) {
search = query;
}
};
searchView.setOnQueryTextListener(queryTextListener);
and in your Fragment, you can access the string as
String query = ((MyActivity)getActivity()).search;
Try this. This will work.

Related

Update Custom ListView Row on selected ContextMenu Action

I have a custom ListView including a custom row_layout.
After a longclick you get different options from the contextmenu. Depending on what option is chosen by the user I want to add an image/icon to the selected row in order to mark it.
I couldnt find an answer which covers exactly this use-case. I would appreciate a hint or some help or a tutorial for this case.
Thanks in advance.
Never mind I got to a solution by myself. I added a boolean variable to my ListItem - Class and the ImageView to the list_row_layout as well as a ImageView to my ViewHolder Class within the CustomAdapter class. So when a contextItem is clicked the boolean Attribute is set to true for the listItem which was clicked on.
Example Code:
#Override
public boolean onContextItemSelected(MenuItem item) {
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
int itemPosition = info.position;
switch (item.getItemId()) {
case R.id.contextItem1:
listViewItems.get(itemPosition).setMarkerAttribute(true);
listView.setAdapter(new MyCustomListAdapter(context, listViewItems));
return true;
case R.id.contextItem2:
//do sth
return true;
case R.id.contextItem3:
//do sth
return true;
default:
return super.onContextItemSelected(item);
}
}
Hope this was useful to somebody, because a lot of examples only cover removing an item ...

Filtering a list during search modifies original data source

I have just added a SearchView to my view containing a RecyclerView. It works great, but each time I set the filter, it is filtered against the previous filter. Also, when I close the search field, the full list of data does not reappear.
This is what I have in the adapter (I haven't listed onBindViewHolder or onCreateViewHolder, but they are there):
public class AttractionRowAdapter extends RecyclerView.Adapter<AttractionRowHolder> {
private List<Attraction> attractionsList;
private Context context;
public AttractionRowAdapter(Context context, List<Attraction> attractionsArrayList) {
this.attractionsList = attractionsArrayList;
this.context = context;
}
public void setFilter(List<Attraction> attractions) {
attractionsList.clear();
attractionsList.addAll(attractions);
notifyDataSetChanged();
}
public void clearAdaptor() {
attractionsList.clear();
notifyDataSetChanged();
}
This is what I have in the Activity with the RecyclerView:
#Override
public boolean onQueryTextChange(String newText) {
final List<Attraction> filteredModelList = filter(DataManager.attractionArrayList, newText);
attractionsAdapter.setFilter(filteredModelList);
return true;
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.action_search, menu);
final MenuItem item = menu.findItem(R.id.action_search);
final SearchView searchView = (SearchView) MenuItemCompat.getActionView(item);
searchView.setOnQueryTextListener(this);
MenuItemCompat.setOnActionExpandListener(item, new MenuItemCompat.OnActionExpandListener() {
#Override
public boolean onMenuItemActionCollapse(MenuItem item) {
attractionsAdapter.setFilter(DataManager.attractionArrayList);
return true;
}
#Override
public boolean onMenuItemActionExpand(MenuItem item) {
return true;
}
});
return super.onCreateOptionsMenu(menu);
}
And this is what is in the DataManager class:
static ArrayList<Attraction> attractionArrayList = new ArrayList<Attraction>();
I also have a function in there where I'm adding all of the attractions to attractionArrayList after they are loaded from a database.
The problem seems to be with the method setFilter as I have found that it is modifying DataManager.attractionsArrayList.
Anyone know why it is doing this, and how I can keep the full list intact, while filtering a copy of that list (like I have tried to do)?
You are doing this:
public void setFilter(List<Attraction> attractions) {
attractionsList.clear();
attractionsList.addAll(attractions);
}
so you are adding to attractionsList the references of the attractions...
If you latter modify any of those Attractions in that method or clase, those changes will be reflected too in the original list..
you "need" to change the algorithm and maybe use a secondary list, that can as helper help you to get a unmodifiable copy of the original list.
Collections class offer, because of that reason, alternatives to generate copies and unmodifiable copies of collections...
http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Collections.html

MenuItemCompat.getActionView(menuItem) returns null

I am trying to get the View of the MenuItem.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
View miView = MenuItemCompat.getActionView(item);
if (miView == null) {
Log.e(X, "mView is null");
}
}
but everytime miView is null.
Here's my onCreateOptionsMenu
#Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0, 0, 0, R.string.Foo);
return true;
}
I know that MenuItemCompat returns null because the created Menu is not a from support library, so the MenuItem can't be handled by the MenuItemCompat class, isn't?
1) I am looking for some method like onCreateOptionsMenuCompat, is there any method like that?
2) How can i get ActionView from MenuItemCompat class?
and What am i doing wrong ?
PS: my project's minSdkVersion is 9
To get an ActionView from a menu item, you will need to set an ActionView on it first. Normal menu items do not come with ActionViews. ActionViews are used when you need to do something extra in your menu (outside of a normal icon and/or text).
Why are you trying to get a View from the menu item? What are you trying to do with your menu item?

Is there a way to avoid having fullscreen SearchView/Keyboard on landscape?

I'm trying to avoid having fullscreen keyboard editing on landscape in order to access to the suggestions.
I already read a lot of threads explaining that I have to add EditorInfo flags like flagNoFullscreen and/or flagNoExtractUi.
I added them programmatically but not really helpful.
Is there a way to figure this out?
It took me a while to figure this one out, but it's actually quite simple.
Initially I created a custom class that extended the SearchView class, and used a onCreateInputConnection() override, however I couldn't get it working that way.
I eventually got it working in a much more simple way, with just two added lines of code.
You just need to call search.getImeOptions() to get the current configuration, and then "or" the result with EditorInfo.IME_FLAG_NO_EXTRACT_UI with a call to setImeOptions():
Java:
search.setImeOptions(options|EditorInfo.IME_FLAG_NO_EXTRACT_UI);
Kotlin:
search.setImeOptions(search.imeOptions or EditorInfo.IME_FLAG_NO_EXTRACT_UI)
If you don't "or" with the existing options, then you don't get the "Search" completion button in the lower right, you just get a "Done" button instead.
Here is the full onCreateOptionsMenu() override I used to test (I used a SearchView in the xml, but this solution should work for you even if you're not inflating your SearchView from xml):
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
SearchManager manager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
SearchView search = (SearchView) menu.findItem(R.id.action_search).getActionView();
SearchableInfo si = manager.getSearchableInfo(getComponentName());
//Here is where the magic happens:
int options = search.getImeOptions();
search.setImeOptions(options|EditorInfo.IME_FLAG_NO_EXTRACT_UI);
//!!!!!!!!!!!
search.setSearchableInfo(si);
search.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
return false;
}
#Override
public boolean onQueryTextChange(String query) {
return true;
}
});
return true;
}
Here is the xml I used for the SearchView in menu_main.xml:
<item android:id="#+id/action_search"
android:title="Search"
android:icon="#android:drawable/ic_menu_search"
app:showAsAction="always"
app:actionViewClass="android.support.v7.widget.SearchView"
/>
Result without the call to setImeOptions():
Result with the call to setImeOptions():
Another alternative to the code is to add the property in the searchView xml, it is useful for APIs less than 16:
<SearchView
android:imeOptions="flagNoExtractUi" />
Same idea as above written but without SearchView, only using searchable XML
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
...
android:imeOptions="actionSearch|flagNoExtractUi"
...
</searchable>

Is there a difference between `listView.invalidate()` and `adapter.notifyDataHasChanged()`?

I have a list of items.
I want to delete an item in a long push.
I saw this post and it worked for me.
just out of curiosity i wonder why other solution didn't work for me:
sol 1
I register the list to context menu:
registerForContextMenu(listView);
and then:
#Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenu.ContextMenuInfo menuInfo) {
if (v.getId()==R.id.comments_list) {
MenuInflater inflater = getActivity().getMenuInflater();
inflater.inflate(R.menu.phone_list_contextual_menu, menu);
}
}
#Override
public boolean onContextItemSelected(MenuItem item) {
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
switch(item.getItemId()) {
case R.id.edit: {
return true;
}
case R.id.delete: {
comments.remove(info.id);
listView.invalidate();
return true;
}
default: {
return super.onContextItemSelected(item);
}
}
}
Is there a difference between
listView.invalidate() and adapter.notifyDataHasChanged() ? beside the subject of the call?
what am I missing in order for the remove to work?
sol 2
listView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
int position = (int) v.getTag();
comments.remove(position);
listView.invalidate();
return true;
}
});
instead of
listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener(){
#Override
public boolean onItemLongClick(AdapterView<?> av, View v, int pos, long id) {
comments.remove(pos);
//listView.invalidate();
arrayAdapter.notifyDataSetChanged();
return true;
}
});
I understand setOnItemLongClickListener is more suitable for my need than setOnLongClickListener but yet
why didn't this worked for me?
Is there a difference between
listView.invalidate() and adapter.notifyDataHasChanged() ? beside the subject of the call?
To my understanding adapter.notifyDataHasChanged() will do what listView.invalidate() plus more. That means it will also include change in number of items, and possibly inform other observers of data change. Relevant code is here:
http://androidxref.com/5.0.0_r2/xref/frameworks/base/core/java/android/widget/AdapterView.java#798
this is for notifyDataHasChanged(), as you can see mItemCount is udpated with new value. This means if you add more items to your arrayadapter, then invalidate, or better invalidateViews will not show them, at least at the end of list. One thing I have noticed is that above code has no invalidate call - maybe its called by some other methods.
Below is source code for invalidateViews (which is I think more proper than Invalidate):
http://androidxref.com/5.0.0_r2/xref/frameworks/base/core/java/android/widget/AbsListView.java#5078
It has no code to update count of item.
If you search source code for android sources, you will find only few cases when invalidateViews is called, some of those places are optimization hacks.
The difference is that invalidate causes all your views in the list to be scrapped and redrawn. Note I said views so that is what you are actually seeing on the screen (for example you can have 3 views on screen but 20 items in your list)
notifyDataHasChanged on the other hand tells the adapter that the contents have changed and the adapter needs to re-run its methods on the content to refresh the list.
You almost always want to use notifyDataHasChanged but it depends on exactly what you are trying to accomplish.
Hope that helps.

Categories

Resources