android: How to update badge TextView from a class that extends RecyclerView - java

I am trying to update my badge based on click events of buttons inside a recycler view. this is my code:
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.navigation_drawer, menu);
item = menu.findItem(R.id.add);
badgeLayout = (RelativeLayout) MenuItemCompat.getActionView(item);
mCounter = (TextView) badgeLayout.findViewById(R.id.counter);
cartButton=(Button) badgeLayout.findViewById(R.id.button1);
cartButton.setTypeface(icon);
super.onCreateOptionsMenu(menu, inflater);
}
I want to update the value of mCounter which here:
This is the recyclerview code:
holder.cartBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mCounter.setText("2");// THIS DOES NOT WORK
}
});
PLEASE HELP ME!

You can perform this task in 4 ways :
Create public static variable and set its value to your badge TextView.
create BroadcastReceiver and call it when value changes.
Use EventBus reference
Create an interface

You should rather pass this event (or just the number You want to set) back to activity, invoke invalidateOptionsMenu(); and in the function onPrepareOptionsMenu(Menu menu) invoke the code You have in onCreateOptionsMenu(Menu menu, MenuInflater inflater)

Related

Android: Tabs and searchbars

I have two tabs and each tabs has its own searchbar.
I bind the searchbar in onCreateOptionsMenu. However, the searchbars only work if I leave the screen once and return to the screen (meaning it needs one more lifecycle for the searchbars to react). I confirmed that onCreateOptionsMenu is indeed called two times at the time of the creation of the ViewPagerFragment.
I bind them like this:
MenuItem searchItem = menu.findItem(R.id.search);
searchItem.setVisible(true);
SearchView searchView = (SearchView) searchItem.getActionView();
searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
...
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
...
return false;
}
});
I am guessing this bug is related to the tabs. How do implement a working searchbar with tabs (i.e. viewpager2)?
I call this on onCreateOptionsMenu:
public void onCreateOptionsMenu(#NonNull Menu menu, #NonNull MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
// Call the above...
}
The ViewPager hosting them looks like this:
private void init(View view) {
ViewPager2 viewPager2 = view.findViewById(R.id.view_pager_fragment_view_pager);
TabLayout tabLayout = view.findViewById(R.id.tab_layout_fragment_view_pager);
viewPager2.setUserInputEnabled(true);
viewPager2.setAdapter(new ViewPagerFragmentAdapter(ViewPagerFragment.this));
viewPager2.setOffscreenPageLimit(5);
new TabLayoutMediator
(tabLayout, viewPager2,
(tab, position) -> tab.setText(titles[position])).attach();
}
OP and I were communicating while we found a solution.
First each fragment was changed to
public class MergedItemsFragment extends Fragment implements SearchView.OnQueryTextListener {
/// ------------------------------
/// SearchView.OnQueryTextListener
#Override
public boolean onQueryTextSubmit(String query) {
// ...
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
// ...
return false;
}
/// --------
/// Fragment
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_merged_items, container, false);
}
#Override
public void onCreateOptionsMenu(#NonNull Menu menu, #NonNull MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
final MenuItem searchItem = menu.findItem(R.id.search);
final SearchView searchView = (SearchView) searchItem.getActionView();
searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);
searchView.setOnQueryTextListener(this);
}
}
SearchView was inflated by using a menu.xml file within the App's Activity.
SearchView.OnQueryTextListener was implemented by each Fragment that needed access to the SearchView
Since onCreateOptionsMenu() is invoked each time a Fragment is created, or subsequently comes into view (e.g. Swipe); the SearchView's OnQueryTextListener is updated to the corresponding Fragment
Lastly, there was a line in OP's main Fragment containing the ViewPager2, which was removed: viewPager2.setOffscreenPageLimit(5); that caused each Fragment provided by the FragmentStateAdapter to instantiate and mutate the SearchView's OnQueryTextListener each time a Fragment was created.
Removing the line made sure that only the Fragment that was in view was bound to the Toolbar's SearchView.
If any more code is desired, i'd be happy to post what I have, and if I come up with a solution using viewPager2.setOffscreenPageLimit(5); i.e. caching, i'll post that as well

I want to remove the optionMenu when there are no items in ListView (emptyView is shown)?

I have an app that adds items to an sqlite database and returns a cursor, this cursor is then used with a custom CursorAdapter called StoreCursorAdapter to show the items in a ListView.
There is a (delete all) button as an optionsMenuItem.
I want to hide this optionsMenuItem when no items are avaliable in the ListView.
InventoryActivty
EditorActivity
Sorry for the links I am a new user so they don't allow me to embed images yet. :-(
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_inventory);
//Declare the views
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
ListView list = (ListView) findViewById(R.id.list);
emptyView = findViewById(R.id.empty_view);
//Set the screen to be shown when there are no list items
list.setEmptyView(emptyView);
//StoreCursorAdapter is a custom CursorAdapter
mAdapter = new StoreCursorAdapter(this, null);
list.setAdapter(mAdapter);
}
#Override
protected void onStart() {
super.onStart();
invalidateOptionsMenu();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu options from the res/menu/menu_inventory.xml file.
// This adds menu items to the app bar.
getMenuInflater().inflate(R.menu.menu_inventory, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// User clicked on a menu option in the app bar overflow menu
showDeleteConfirmationDialog();
return super.onOptionsItemSelected(item);
}
I tried
1 - emptyView.visibilty() == View.INVISBLE
2 - list.getAdapter == null
but they didn't work
What statement will do the job?!
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
if (//what statement) {
MenuItem menuItem = menu.findItem(R.id.action_delete_all);
menuItem.setVisible(false);
}
return true;
}
Note:
OnStart() gets called after I get back from the EditorActivity
Note:
In my app I can delete individual items from another activity so adding invalidateOptionsMenu(); in the onOptionsItemSelected won't do the job.
the correct condition to put inside onPrepareOptionsMenu is:
menuItem.setVisible(!mAdapter.isEmpty());
that is the same comparison the ListView uses manages the empty view (minus null check) (https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/widget/AdapterView.java#747)
but I believe there's another issue here, is that the data is changing after the activity started, during showDeleteConfirmationDialog(). That means you have to call invalidateOptionsMenu() the moment the data is changed. There're two ways of doing it. One more robust and the other is faster to code:
faster to code (but not very good/clean):
add invalidateOptionsMenu() after the code that executes the DB operations.
more robust/clean
you'll use start/stop callbacks to listen to changes in the data. Something like the following:
#Override protected void onStart(){
super.onStart();
invalidateOptionsMenu();
mAdapter.registerDataSetObserver(dataObserver);
}
#Override protected void onStop(){
mAdapter.unregisterDataSetObserver(dataObserver);
super.onStop();
}
private final DataSetObserver dataObserver = new DataSetObserver(){
#Override public void onChanged(){
invalidateOptionsMenu();
}
#Override public void onInvalidated(){
invalidateOptionsMenu();
}
};
all code above was typed by heart, there're likely typos, but that's the idea and the typos you can fix later at your code.
if you dont have any menu item to show, why are u inflating one, if you dont inflate you wont.
#Override
public boolean onCreateOptionsMenu(Menu menu) {
return false;
}
Unless you need to dynamically remove the menu options based on the current state of the activity, this might help How do you remove an inflated menu/items from the new Lollipop Toolbar?

Android set menu items dynamically at startup

I need to change the title of a menu item in my action bar at startup based on a few variables which get created at the startup.
But for some reason I cant simply do that since the menu items take time to inflate maybe?
how do I get around this issue.
below is my attempt but it throws java.lang.IndexOutOfBoundsException
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.map_fragment_action_menu, menu);
mOptionsMenu = menu;
mOptionsMenu.getItem(R.id.map_fragment_action_layers_0).setTitle("my title");
}
P.S. I am using a fragment, I also tried to set the title in onCreateView() method but still doesn't work.
You need to use the method Menu#findItem() instead.
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.map_fragment_action_menu, menu);
mOptionsMenu = menu;
mOptionsMenu.findItem(R.id.map_fragment_action_layers_0).setTitle("my title");
}
Menu#getItem() expects an index and not the menu item's id. For e.g, if this menu item is the first item in the menu, you would use
mOptionsMenu.getItem(0).setTitle("my title");

Acessing the 'options' menu from a fragment? Android

I currently have an app which has 4 pages, these pages are being added using fragments by a pageViewer, so that I can swipe between them.
What I want, is to be able to access the 'options' menu (the one which has a 'settings' item in it by default) from each page, so that I can perform commands specifically for one page, such as a 'refresh' item, which refreshes the data in the current page.
Could anyone point me in the right direction?
Thanks!
Each Fragment can declare its own menu, which will be automatically merged with the current activity's menu.
class YourPage extends Fragment
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Signal that this fragment has proper actions
setHasOptionsMenu(true);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater)
{
super.onCreateOptionsMenu(menu, inflater);
// The menu will be added to the action bar
inflater.inflate(R.menu.fragment_page_menu, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId())
{
case R.id.action_refresh:
{
// Handle the action...
return true;
}
default:
return super.onOptionsItemSelected(item);
}
}
}
Here's a complete example that I made, and also a relevant tutorial.

Resetting Search Widget (SearchView) value

I've got 2 activites : the first, HomepageActiviy, have a search widget that search data using another activity, SearchActivity.
What I want to do is when I go back from SearchActiviy to HomepageActivity, the search widget go collapsed and with a empty text.
I've tried to do this following thing :
public class HomepageActivity extends Activity {
#TargetApi(11)
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.projectslist, menu);
if(Build.VERSION.SDK_INT >= 11) {
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
SearchView searchView = (SearchView) menu.findItem(R.id.homepage_search).getActionView();
ComponentName component = new ComponentName(this, SearchActivity.class);
searchView.setSearchableInfo(searchManager.getSearchableInfo(component));
searchView.setIconifiedByDefault(true);
searchView.setQuery("", false);
}
return super.onCreateOptionsMenu(menu);
}
[…]
#TargetApi(11)
#Override
protected void onRestart() {
super.onRestart();
if(Build.VERSION.SDK_INT >= 11)
invalidateOptionsMenu();
launchAsynchronousImageDownload();
}
}
If the widget is well displayed as collapsed, the text in the widget still remember searched text (after I re-open the widget).
How can I reset the text of the widget?
Thanks for any help! ;)
You might also try the following:
searchView.setQuery("", false);
searchView.clearFocus();
this is the magic
searchView.setQuery("", false); // clear the text
searchView.setIconified(true); // close the search editor and make search icon again
in the HomepageActivity insert the onSaveInstanceState function after oncreate function
this function will trigger everytime you open a new activity ,
before opening new activity it will reset the value of Search Widget
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
searchView.setQuery("", false);
searchView.setIconified(true);
}
This worked for me:
First, I declared the menu item variable at the top of the activity:
private MenuItem mSearchMenuItem;
I defined the variable in OnCreateOptionsMenu():
mSearchMenuItem = menu.findItem(R.id.action_search);
I declared invalidateOptionsMenu() in onResume():
#Override
protected void onResume() {
invalidateOptionsMenu();
super.onResume();
}
Lastly, I called collapseActionView() on the menu item in onPrepareOptionsMenu().
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
mSearchMenuItem.collapseActionView();
return super.onPrepareOptionsMenu(menu);
}
searchView.setQuery("", false);
searchView.setIconified(false);
I had this problem too and it worked if I put it in onPrepareOptionsMenu.
#Override
public boolean onPrepareOptionsMenu (Menu menu) {
SearchView searchView = (SearchView) menu.findItem(R.id.action_search).getActionView();
searchView.setQuery("", false);
// rest of code...
}
Kotlin
Here's a cleaner solution, it fixes the following:
Issue of showing filtered list after screen rotation.
Issue of showing filtered list when the user switches to other app and returns back.
Issue of search menu shifting to the left when the user returns back.
No need to iconify if you are invalidating, it's done automatically.
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
searchView.setQuery("", false)
(activity as YourActivity).invalidateOptionsMenu()
}
Make sure to change YourActivity to the Activity name in which you have your Fragment.
Just found an ugly way to make it work (read comments to see differences):
public class HomepageActivity extends Activity {
// Declaring SearchView as an instance object
private SearchView searchView;
#TargetApi(11)
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.projectslist, menu);
if(Build.VERSION.SDK_INT >= 11) {
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
// Using instance var instead of local var
searchView = (SearchView) menu.findItem(R.id.homepage_search).getActionView();
ComponentName component = new ComponentName(this, SearchActivity.class);
searchView.setSearchableInfo(searchManager.getSearchableInfo(component));
searchView.setIconifiedByDefault(true);
// Setting query is not anymore required
//searchView.setQuery("", false);
}
return super.onCreateOptionsMenu(menu);
}
[…]
#TargetApi(11)
#Override
protected void onRestart() {
super.onRestart();
// Do not need to recreate menu
/*if(Build.VERSION.SDK_INT >= 11)
invalidateOptionsMenu();*/
if(Build.VERSION.SDK_INT >= 11) {
// Calling twice: first empty text field, second iconify the view
searchView.setIconified(true);
searchView.setIconified(true);
}
launchAsynchronousImageDownload();
}
}
It's pretty ugly, I think, so if anybody as a better idea, just tell me :)

Categories