Current menu item view is always null in navigation view - android

I'm using navigation view. And for some reason i can't get the view of menu item. It's always null. I tried viewobserver, findViewByid, but it didn't work. I need to get y coord of current menu item location while performing item selection event. Is this possible?
initializing drawer
activity.drawerIndicator.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (activity.drawerLayout.isDrawerVisible(GravityCompat.START)) {
activity.drawerLayout.closeDrawer(GravityCompat.START);
} else {
activity.drawerLayout.openDrawer(GravityCompat.START);
}
}
});
activity.drawerLayout.setDrawerListener(new DrawerLayout.DrawerListener() {
#Override
public void onDrawerSlide(View view, float v) {
}
#Override
public void onDrawerOpened(View view) {
activity.closeKeyboard();
}
#Override
public void onDrawerClosed(View view) {
// your refresh code can be called from here
//activity.closeKeyboard();
}
#Override
public void onDrawerStateChanged(int i) {
}
});
initializing navigation view
public void initNavigationView() {
activity.navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
// This method will trigger on item Click of navigation menu
#Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
//Closing drawer on item click
final int itemId=menuItem.getItemId();
final ViewTreeObserver viewTreeObserver =activity.navigationView.getViewTreeObserver();
viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
View menuButton = activity.findViewById(itemId);
// This could be called when the button is not there yet, so we must test for null
if (menuButton != null) {
// Found it! Do what you need with the button
int[] location = new int[2];
menuButton.getLocationInWindow(location);
SharedPreferencesController.getInstance(activity.getApplicationContext()).setTopPosition(location[1]);
// Now you can get rid of this listener
viewTreeObserver.removeGlobalOnLayoutListener(this);
}
}
});
activity.drawerLayout.closeDrawers();
switch (menuItem.getItemId()) {
case R.id.checkin:
if (!menuItem.isChecked())
menuItem.setChecked(true);
return goToCheckinItemMenu();
case R.id.boarding_passes:
return goToBoardingPassesItemMenu(menuItem);
case R.id.flight_status:
return goToFlightStatusItemMenu(menuItem);
case R.id.timetable:
return goToTimetableItemMenu(menuItem);
case R.id.promotion:
return goToPromotionItemMenu(menuItem);
//case R.id.reccomend_app:
// return goToReccomendAppItemMenu();
case R.id.about_app:
return goToAboutAppItemMenu(menuItem);
case R.id.contact_us:
return goToContactUsItemMenu(menuItem);
case R.id.settings:
return goToSettingsItemMenu(menuItem);
case R.id.data_protection:
return goToDataProtectionItemMenu(menuItem);
case R.id.checkin_info:
return goToCheckinInfoItemMenu(menuItem);
case R.id.panorama:
return goToPanoramaCLubItemMenu();
default:
Toast.makeText(activity.getApplicationContext(), "Somethings Wrong", Toast.LENGTH_SHORT).show();
return true;
}
}
}
);
}
As you see im trying to get the current location of menuItem on the screen using TreeObserver. I know that observer works after something happens, meaning its not working right after its called. But anyway the menuButton view is always null

Related

How to make bottom navigation selected automatically when moving from one fragment to another?

I'm trying to make action button to move from the home fragment to the promo fragment.
In the fragment home there is an action button that will move to the promo fragment. However, when the promo action button on the home fragment is clicked, the display will move to the promo fragment but the bottom navigation is still selected in the home fragment.
Screenshot Home Fragment
Screenshot Promo Fragment
This is my action button code in Home Fragment:
imagePromo.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
((MainActivity)getActivity()).selectFragment(2);
}
});
This is my selectfragment code in MainActivity:
public void selectFragment(int position){
viewPager.setCurrentItem(position, true);
viewPager.dispatchSetSelected(true);
}
This is my bottom navigation code in MainActivity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
view = findViewById(android.R.id.content);
viewPager = findViewById(R.id.viewpager);
viewPager.setAdapter(new MyAdapter(getSupportFragmentManager()));
viewPager.setOffscreenPageLimit(pager_number);
navigation = findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(item -> {
switch (item.getItemId()) {
case R.id.navigation_home:
viewPager.setCurrentItem(0);
return true;
case R.id.navigation_category:
viewPager.setCurrentItem(1);
return true;
case R.id.navigation_promo:
viewPager.setCurrentItem(2);
return true;
case R.id.navigation_wishlist:
viewPager.setCurrentItem(3);
return true;
}
return false;
});
}
I'm trying to use the code I found on github. Below is the code snippet:
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
if (prevMenuItem != null) {
prevMenuItem.setChecked(false);
} else {
navigation.getMenu().getItem(0).setChecked(false);
}
navigation.getMenu().getItem(position).setChecked(true);
prevMenuItem = navigation.getMenu().getItem(position);
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
I tried to apply it in MainActivity and it solved my problem above.
You can set it in your setOnClickListener to change the Fragment of the ViewPager and it's CurrentItem to get the icon changed aswell.
Button to_promo = view.findViewById(R.id.to_promo);
to_promo.setOnClickListener(view1 -> {
viewPager.setCurrentItem(2);
});

android.R.id.home is not working in BottomAppbar in My Activity

I am trying to create Navigation View in Bottom App bar in Activity but android.R.id.home doesn't work . I have set the BottomAppbar object as setSupportActionBar(mBottomAppBar) but doesn't work
mBottomAppBar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()){
case R.id.emp_menu_home:
setFragment(empHomeFragment);
break;
case R.id.emp_menu_notif:
setFragment(notificationsFragment);
break;
case R.id.emp_menu_Inbox:
setFragment(inboxFragment);
break;
case R.id.emp_menu_cv:
setFragment(cvFragment);
break;
case android.R.id.home:
Toast.makeText(Main2Activity.this, "Home is click", Toast.LENGTH_SHORT).show();
NaviDrawerFragment naviDrawerFragment=new NaviDrawerFragment();
naviDrawerFragment.show(getSupportFragmentManager(),naviDrawerFragment.getTag());
break;
default:
return false;
}
return true;
}
});
Try adding: setHasOptionsMenu(true); in your onCreate().
or
If you're using the new Toolbar and ActionbarDrawerToggle. You can assign clickHandler directly. For my activities that have this drawer toolbar I implemented an interface to enable drawer if at root,
#Override
public void enableDrawer(boolean enable) {
mDrawerToggle.setDrawerIndicatorEnabled(enable);
mDrawerToggle.setToolbarNavigationClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Pop fragment back stack or pass in a custom click handler from the fragment.
}
});
}

Android: why buttons event not working after press back button?

I have defined four buttons that onclick event shows a content, now after click when press
back button that shows same four buttons but click event not working.
I defined a field that if user saw content isLooked=true so when clicked on back button I setContentView(R.layout.index) and I will not allow to exit of current activity.
why not working events after click on back button?
private boolean isLooked = false;
#Override
public void onCreate(Bundle savedInstanceState) {
try {
super.onCreate(savedInstanceState);
setContentView(R.layout.index);
initialEvents();
} catch (Exception e) {
new com.example.csharp.Log.Error().Save(e);
}
}
private void initialEvents() {
View v = findViewById(R.id.btnChapter1);
v.setOnClickListener(this);
v = findViewById(R.id.btnChapter2);
v.setOnClickListener(this);
v = findViewById(R.id.btnChapter3);
v.setOnClickListener(this);
v = findViewById(R.id.btnChapter4);
v.setOnClickListener(this);
}
#Override
public void onBackPressed() {
if (isLooked) {
setContentView(R.layout.index);
isLooked = false;
} else {
super.onBackPressed();
}
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && isLooked) {
setContentView(R.layout.index);
isLooked = false;
return true;
} else {
return super.onKeyDown(keyCode, event);
}
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnChapter1:
setContentView(R.layout.chapter1_index);
isLooked = true;
break;
case R.id.btnChapter2:
setContentView(R.layout.chapter2_index);
isLooked = true;
break;
case R.id.btnChapter3:
setContentView(R.layout.chapter3_index);
isLooked = true;
break;
case R.id.btnChapter4:
setContentView(R.layout.chapter4_index);
isLooked = true;
break;
}
}
You are setting new content view when back pressed, this is create a new instance of objects for the layout set. But your on click listener is set for the view set in onCreate.
If you really want to set content on back pressed, then you have to findViewById again and set the listener.

contextual action mode in fragment - close if not focused?

i implemented a contextual action mode bar in a nested fragement. This fragment is part of a view pager and the view pager is also a fragment and part of a navigation drawer.
My Problem: I want to close the contextual action mode bar if the fragment is no more focused. So, if I swipe through the view pager the action mode bar should close. But if I use the onPause() method of the nested fragment, the method is not called directly. Often it waits until i swiped two or three times forward... Here are some pictures:
In the second picture you can see that the action mode bar is still there. So my question is:
In which method should I call my actionModeBar.finish() method, to close directly the action mode bar if i leave the fragment?
Maybe the code of the fragment helps you:
public class EditorFragment extends Fragment {
private static final String KEY_POSITION="position";
ListView listView;
private boolean isMultipleList = false;
private ActionMode acMode;
private int counterChecked = 0;
private ActionMode.Callback modeCallBack = new ActionMode.Callback() {
public boolean onPrepareActionMode(ActionMode mode, Menu menu){
return false;
}
public void onDestroyActionMode(ActionMode mode) {
listView.clearChoices();
for (int i = 0; i < listView.getChildCount(); i++)
listView.setItemChecked(i, false);
listView.post(new Runnable() {
#Override
public void run() {
listView.setChoiceMode(ListView.CHOICE_MODE_NONE);
}
});
isMultipleList = false;
counterChecked = 0;
mode = null;
}
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mode.setTitle("1 Aufgabe");
mode.getMenuInflater().inflate(R.menu.actionmode, menu);
return true;
}
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.actionmode_delete:
int choiceCount = listView.getCount();
SparseBooleanArray spBoolArray = listView.getCheckedItemPositions();
DBAufgaben db = new DBAufgaben(MainActivity.getMContext());
db.open();
for (int i = 0; i < choiceCount; i++) {
if(spBoolArray.get(i)){
db.deletContact(listView.getItemIdAtPosition(i));
}
}
Cursor cursor = db.getAllRecords();
AdapterEingang adapterE = new AdapterEingang(MainActivity.getMContext(), cursor, 0);
listView.setAdapter(adapterE);
db.close();
mode.finish();
break;
case R.id.actionmode_cancel:
mode.finish();
break;
}
return false;
}
};
//......//
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = null;
int position = getArguments().getInt(KEY_POSITION, -1);
switch(position){
case 0:
rootView = inflater.inflate(R.layout.pager_list, null);
listView = (ListView) rootView.findViewById(R.id.pager_list);
Context context = MainActivity.getMContext();
DBAufgaben db = new DBAufgaben(context);
db.open();
Cursor cursor = db.getAllRecords();
AdapterEingang adapterE = new AdapterEingang(context, cursor, 0);
listView.setAdapter(adapterE);
db.close();
listView.setOnItemLongClickListener(new OnItemLongClickListener(){
#Override
public boolean onItemLongClick(AdapterView<?> adapterView, View view,
int position, long id) {
if(!isMultipleList){
acMode = MainActivity.getInstance().startActionMode(modeCallBack);
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
listView.setItemChecked(position, true);
isMultipleList = true;
counterChecked++;
setNewTitle();
} else {
listView.setItemChecked(position, true);
counterChecked++;
setNewTitle();
}
return true;
}
});
listView.setOnItemClickListener(new OnItemClickListener(){
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position,
long id) {
Log.d(getTag(), "Datensatz: "+String.valueOf(id));
if(isMultipleList){
if(listView.isItemChecked(position)){
listView.setItemChecked(position, true);
counterChecked++;
setNewTitle();
} else {
listView.setItemChecked(position, false);
counterChecked--;
setNewTitle();
}
}
}
});
break;
default:
rootView = inflater.inflate(R.layout.frag_dummy, null);
TextView txt = (TextView) rootView.findViewById(R.id.dummy_txt);
txt.setText(String.valueOf(position));
break;
}
return(rootView);
}
public void setNewTitle(){
if(counterChecked == 1){
acMode.setTitle(counterChecked+" Aufgabe");
} else {
acMode.setTitle(counterChecked+" Aufgaben");
}
}
#Override
public void onPause(){
super.onPause();
if(isMultipleList){
acMode.finish();
}
}
}
ViewPagers keep multiple pages active at any one time (by default, the page before and page after the currently shown page), hence why onPause() is not called until you swipe two pages away.
Your best bet would be to use a ViewPager.OnPageChangeListener, and show and hide the ActionMode in onPageSelected(..) (i.e. if the page selected isn't the one with the ActionMode, hide the ActionMode). You'll likely have to implement this in the Activity which hosts your ViewPager.
Here's what worked for me --
Hold a static reference to the action mode in MyFragment:
public static ActionMode mActionMode;
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mActionMode = mode;
return true;
}
#Override
public void onDestroyActionMode(ActionMode mode) {
mActionMode = null;
}
Set ViewPager.OnPageChangeListener in MyViewPagerActivity.
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
....
#Override
public void onPageScrollStateChanged(int state) {
if(MyFragment.mActionMode != null) MyFragment.mActionMode.finish();
}
});
This worked for me:
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
if (!isVisibleToUser && this.listView != null) {
//HACK this is done in order to finish the contextual action bar
int choiceMode = this.listView.getChoiceMode();
this.listView.setChoiceMode(choiceMode);
}
}
I combined code from the OP with the override suggested by user pomber:
I save the ActionMode to a class field when the action mode is created.
I set the field back to null when the action mode is destroyed.
I override setUserVisibleHint in my fragment and call ActionMode#finish() if the fragment isn't visible in the view pager.
I also call ActionMode#finish() in the onPause() method of the fragment to close the fragment if the user navigates elsewhere.
Code:
#Nullable
ActionMode mActionMode = null;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Start out with a progress indicator.
setListShownNoAnimation(false);
setEmptyText(getText(R.string.no_forms_in_progress));
getListView().setChoiceMode(AbsListView.CHOICE_MODE_MULTIPLE_MODAL);
getListView().setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {
#Override
public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
// Here you can do something when items are selected/de-selected,
// such as update the title in the CAB
}
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.context_saved_item, menu);
inflater.inflate(R.menu.context_instance_list, menu);
mActionMode = mode;
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.action_delete:
confirmDelete(getListView().getCheckedItemIds());
return true;
case R.id.action_print:
print(getListView().getCheckedItemIds());
return true;
}
return false;
}
#Override
public void onDestroyActionMode(ActionMode mode) {
mActionMode = null;
}
});
}
#Override
public void onPause() {
super.onPause();
if (mActionMode != null) {
mActionMode.finish();
}
}
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (mActionMode != null && !isVisibleToUser) {
mActionMode.finish();
}
}
You can use the onDestroyOptionsMenu() method inside your Fragment:
public void onDestroyOptionsMenu() {
super.onDestroyOptionsMenu();
if (mActionMode != null) {
mActionMode.finish();
mActionMode = null;
}
}

Why does isItemChecked() return true when in ActionMode?

I've set up an ActionMode callback for use as the contextual ActionBar (CAB) within an ActionBarSherlock using project.
I'm trying to set up multiple select so that I can delete multiple items in a ListView.
I noticed while debugging, when the contextual ActionBar (CAB) is not open and I call isItemChecked() on a list item that I touch, it returns false as it should. But when the CAB IS open, items that I touch (that I haven't touched before) return true on calls to isItemChecked(). Then when I call delete on the array from getCheckedItemIds(), that array does not contain the items that were previously returning true for isItemChecked().
Has anyone seen this?
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.habit);
habitListView = (ListView)findViewById(R.id.habitsListView);
habitListView.setAdapter(mAdapter);
habitListView.setChoiceMode(AbsListView.CHOICE_MODE_MULTIPLE);
habitListView.setItemsCanFocus(false);
habitListView.setOnItemLongClickListener(new MyOnItemLongClickListener());
habitListView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (habitListView.isItemChecked(position)) { // for debugging, returns false here
// when CAB isnt up.
int h = 2;
}
// handle differently when CAB is on.
if (mMode != null) {
if (habitListView.isItemChecked(position)) { // returns true here when CAB is up
// but this is the first time I'm
// clicking the item
habitListView.setItemChecked(position, false);
// turn CAB off if this is the last to be unchecked
if (habitListView.getCheckedItemIds().length == 0) {
mMode.finish();
}
} else {
habitListView.setItemChecked(position, true);
}
} else {
// start detail/edit view activity
}
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getSupportMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.menu_create:
Habit test = new Habit("FLOSS", "GOOD", "", "");
mDbHelper.createHabitEntry(test);
mAdapter.changeCursor(mDbHelper.getAllEntries());
break;
}
return false;
}
private class MyOnItemLongClickListener implements OnItemLongClickListener {
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
habitListView.setItemChecked(position, true);
mMode = startActionMode(new MyActionModeCallback());
return true;
}
}
private class MyActionModeCallback implements ActionMode.Callback {
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
// TODO Auto-generated method stub
return false;
}
#Override
public void onDestroyActionMode(ActionMode mode) {
habitListView.setOnItemLongClickListener(new MyOnItemLongClickListener());
}
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mode.getMenuInflater().inflate(R.menu.main_long_click_context, menu);
habitListView.setOnItemLongClickListener(null);
return true;
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_delete:
long[] selected = habitListView.getCheckedItemIds();
if (selected.length > 0) {
for (long id : selected) {
mDbHelper.deleteEntry(id);
}
}
mAdapter.changeCursor(mDbHelper.getAllEntries());
mode.finish();
break;
}
return true;
}
};
So what has worked for me is to just use
habitListView.setOnItemClickListener(new OnItemClickListener(){
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
//handle differently when CAB is on.
if (mMode != null){
view.setSelected(!view.isSelected());
updateCABtitle();
//turn CAB off if this is the last to be unchecked
if (habitListView.getCheckedItemIds().length == 0){
mMode.finish();
}
} else {
//start detail/edit view activity
Intent intent = new Intent(getApplicationContext(), HabitDetailActivity.class);
startActivity(intent);
}
}
});
and
private class MyOnItemLongClickListener implements OnItemLongClickListener{
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view,
int position, long id) {
habitListView.setItemChecked(position, true);
mMode = startActionMode(new MyActionModeCallback());
updateCABtitle();
return true;
}
}
I don't really understand why setItemChecked() is not working for onItemClick() but seems to be for onItemLongClick(). It looks as though there is a default click handler that gets called in AbsListView.PerformItemClick() that must do some toggling of checked/unchecked or something.

Categories

Resources