I am using navigation component in my app. I am trying to navigate to the Fragment on click of an action bar icon, but it is not working.
Below is my code:
action_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:title=""
android:id="#+id/cart_notif"
android:icon="#drawable/ic_order"
app:showAsAction="always"
android:actionLayout="#layout/notification_badge"/>
</menu>
nav_host.xml
<fragment
android:id="#+id/cartFragment"
android:name="BottomFragments.CartFragment"
android:label="Cart"
tools:layout="#layout/fragment_cart">
<action
android:id="#+id/action_cartFragment_to_cakeFragment"
app:destination="#id/cakeFragment"
app:enterAnim="#anim/nav_default_enter_anim"
app:popUpTo="#id/cakeFragment"
app:popUpToInclusive="true" />
</fragment>
MainActivity.java
#Override
public boolean onOptionsItemSelected(#NonNull MenuItem item) {
if(item.getItemId() == R.id.cart_notif){
NavController navController = Navigation.findNavController(MainActivity.this,R.id.fragment);
navController.navigate(R.id.cartFragment);
}
return super.onOptionsItemSelected(item);
}
#Override
public boolean onSupportNavigateUp() {
navController.navigateUp();
return super.onSupportNavigateUp();
}
This approach is not working - how can I navigate?
here I can see you are using onOptionsItemSelected for navigating from one screen to another. Instead you should use onNavigationItemSelected method.
See this answer for more details.
Related
I'm trying to animate the icons in my DrawerLayout using an AnimationDrawable. I created a new project selecting Navigation Drawer Activity as the main activity. I created an animation from a set of XML files and the animation runs in the previewer in Android Studio. I set the animation XML as the icon on the menu item and add a DrawerListener.onDrawerOpened(View V) that gets the menu item, gets its icon and calls start() as described here https://developer.android.com/guide/topics/graphics/drawable-animation. This seemed pretty straightforward to implement but also too simple which is why I wasn't too surprised when it didn't work. It just shows the first image in the series and never changes to the other images. If I run the app in the debugger I see that the icon is indeed an AnimationDrawable and that the icon's instance variables mAnimating and mRunning change from false to true when I call start() on it. Obviously there is something more I need to be doing but I don't know what. I did notice that the icon's mAnimationRunnable is set to null and I'm guessing this might have something to do with it.
Animation ld.xml
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false">
<item android:drawable="#drawable/ic_untitled_1" android:duration="500" />
<item android:drawable="#drawable/ic_untitled_2" android:duration="500" />
<item android:drawable="#drawable/ic_untitled_3" android:duration="500" />
<item android:drawable="#drawable/ic_untitled_4" android:duration="500" />
<item android:drawable="#drawable/ic_untitled_5" android:duration="500" />
<item android:drawable="#drawable/ic_untitled_6" android:duration="500" />
<item android:drawable="#drawable/ic_untitled_7" android:duration="500" />
<item android:drawable="#drawable/ic_untitled_8" android:duration="500" />
</animation-list>
Drawer activity_main_drawer.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:showIn="navigation_view">
<group android:checkableBehavior="single">
<item
android:id="#+id/nav_home"
android:icon="#drawable/ld"
android:title="#string/menu_home" />
<item
android:id="#+id/nav_settings"
android:icon="#drawable/ic_menu_gallery"
android:title="#string/menu_settings" />
<item
android:id="#+id/nav_timers"
android:icon="#drawable/ic_menu_slideshow"
android:title="#string/menu_timers" />
</group>
</menu>
Main layout activity_main.xml
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
android:id="#+id/app_bar_main"
layout="#layout/app_bar_main"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.google.android.material.navigation.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header_main"
app:menu="#menu/activity_main_drawer" />
</androidx.drawerlayout.widget.DrawerLayout>
Main activity onCreate MainActivity.java
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
com.company.databinding.ActivityMainBinding binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setSupportActionBar(binding.appBarMain.toolbar);
DrawerLayout drawer = binding.drawerLayout;
NavigationView navigationView = binding.navView;
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
mAppBarConfiguration = new AppBarConfiguration.Builder(R.id.nav_home, R.id.nav_settings, R.id.nav_timers).setOpenableLayout(drawer).build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);
NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
NavigationUI.setupWithNavController(navigationView, navController);
binding.drawerLayout.addDrawerListener(new DrawerLayout.DrawerListener() {
#Override
public void onDrawerSlide(#NonNull View drawerView, float slideOffset) {
}
#Override
public void onDrawerOpened(View drawerView) {
((AnimationDrawable)navigationView.getMenu().getItem(0).getIcon()).start();
}
#Override
public void onDrawerClosed(#NonNull View drawerView) {
((AnimationDrawable)navigationView.getMenu().getItem(0).getIcon()).stop();
}
#Override
public void onDrawerStateChanged(int newState) {
}
});
}
I haven't been able to make the AnimationDrawable start() as a menu icon but it does start if I display it in an ImageView in the navigation header. So I manually animated it myself. Here is my MenuIconAnimator class. I still use a DrawerListener and in onDrawerOpened(View drawerView) I create an instance of my animator class passing it the menu item and then I call start() on it. This swaps the menu icon based on the parameters setup in the animation XML. And then in onDrawerClosed(#NonNull View drawerView) I call the method stopThread() on the MenuIconAnimator and the thread stops.
Here are the relevant DrawerListener methods. menuIconAnimator is an instance variable on my activity class.
#Override
public void onDrawerOpened(View drawerView) {
menuIconAnimator = new MenuIconAnimator(navigationView.getMenu().getItem(0));
menuIconAnimator.start();
}
#Override
public void onDrawerClosed(#NonNull View drawerView) {
menuIconAnimator.stopThread();
}
Here is my MenuIconAnimator class.
package com.leridiandynamics.smartrecirculationcontrol2.ui;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
import android.view.MenuItem;
public class MenuIconAnimator extends Thread{
Boolean running=true;
MenuItem menuItem;
public MenuIconAnimator(MenuItem menuItem){
this.menuItem = menuItem;
}
public void stopThread(){
running = false;
}
public void run() {
// Get the icon that is set on the menuItem. This is an AnimationDrawable.
// Hold onto it while we manually animate each frame by setting the frame
// drawable as the menuItem icon.
AnimationDrawable animationDrawable = ((AnimationDrawable)menuItem.getIcon());
Handler mainHandler = new Handler(Looper.getMainLooper());
while (running) {
try {
// loop through each frame setting it as the icon on the menu item and then sleep
// the thread for the duration of the frame.
for (int i=0; i<animationDrawable.getNumberOfFrames();i++){
Drawable drawable = animationDrawable.getFrame(i);
mainHandler.post(() -> menuItem.setIcon(drawable));
sleep(animationDrawable.getDuration(i));
if (!running) break;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// restore the original animationDrawable on the menuItem so it is available the next time
// the MenuIconAnimator is called.
mainHandler.post(() -> menuItem.setIcon(animationDrawable));
}
}
UPDATE: It seems that if you have the animation running too quickly the menu is not very responsive to user input. Maybe that is why animation doesn't work on the menu items out of the box.
UPDATE 2: I have discovered that if the menu item's icon is changed while the user is tapping the menu item, the tap does not register. Finger touch, icon change, finger release...the menu item selection does not register.
UPDATE 3: This does not appear to be a viable solution to making AnimationDrawable work on a MenuItem. When the icon is changed the entire menu appears to redraw and any touch events are reset. I submitted an issue with Google regarding AnimationDrawable not animating on a MenuItem. https://issuetracker.google.com/issues/226640828 Will see if this gets addressed.
I do not know if I am doing this right.
I use a Navigation Drawer template in Android Studio and successfully browsing 3 menu option.
What I did is for all menu I added if else what the next fragment will be shown.
I feel like this kind of approach is kind of hard specially I need to add more menu.
Is their a better way for navigating fragments. Thanks in advance.
MainActivity.java
#Override
public boolean onNavigationItemSelected(MenuItem item) {
String title = getSupportActionBar().getTitle().toString();
switch (item.getItemId()) {
case R.id.nav_home:
if(title.equals(getString(R.string.title_status))) {
Navigation.findNavController(this, R.id.nav_host_fragment).navigate(R.id.action_status_to_home_fragment);
} else if(title.equals(getString(R.string.title_gallery))) {
Navigation.findNavController(this, R.id.nav_host_fragment).navigate(R.id.action_galley_to_home_fragment);
}
break;
case R.id.nav_status:
if(title.equals(getString(R.string.title_home))) {
Navigation.findNavController(this, R.id.nav_host_fragment).navigate(R.id.action_home_to_status_fragment);
} else if(title.equals(getString(R.string.title_gallery))) {
Navigation.findNavController(this, R.id.nav_host_fragment).navigate(R.id.action_galley_to_status_fragment);
}
break;
case R.id.nav_gallery:
if(title.equals(getString(R.string.title_home))) {
Navigation.findNavController(this, R.id.nav_host_fragment).navigate(R.id.action_home_to_gallery_fragment);
} else if(title.equals(getString(R.string.title_status))) {
Navigation.findNavController(this, R.id.nav_host_fragment).navigate(R.id.action_status_to_gallery_fragment);
}
break;
}
item.setChecked(true);
drawer.closeDrawers();
return true;
}
mobile_navigation.xml
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/mobile_navigation"
app:startDestination="#+id/nav_home">
<fragment
android:id="#+id/nav_home"
android:name="com.ddc.qvac.framents.HomeFragment"
android:label="#string/title_home"
tools:layout="#layout/fragment_home">
<action
android:id="#+id/action_home_to_status_fragment"
app:destination="#id/nav_status" />
<action
android:id="#+id/action_home_to_gallery_fragment"
app:destination="#id/nav_gallery" />
</fragment>
<fragment
android:id="#+id/nav_gallery"
android:name="com.ddc.qvac.framents.gallery.GalleryFragment"
android:label="#string/title_gallery"
tools:layout="#layout/fragment_gallery">
<action
android:id="#+id/action_galley_to_home_fragment"
app:destination="#id/nav_home" />
<action
android:id="#+id/action_galley_to_status_fragment"
app:destination="#id/nav_status" />
</fragment>
<fragment
android:id="#+id/nav_status"
android:name="com.ddc.qvac.framents.StatusFragment"
android:label="#string/title_status"
tools:layout="#layout/fragment_status">
<action
android:id="#+id/action_status_to_home_fragment"
app:destination="#id/nav_home" />
<action
android:id="#+id/action_status_to_gallery_fragment"
app:destination="#id/nav_gallery" />
</fragment>
</navigation>
use same id for:
id that defined in fragment tag in navigation xml file
id that defined in menu xml file
in your mobile_navigation.xml file you are using "#+id/nav_home" for home fragment. in your menu.xml file make id of home menu as "#+id/nav_home"
if both ids are same in menu file and navigation file, it will automatically navigate to the fragment. we don't need to do any boilerplate code.
I have create a menu in the action bar but I don't know how to use the items inside of it as a button.
That's my menu 'xml' code:
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:icon="#drawable/ic_add_circle_outline_black_24dp"
android:title=""
app:showAsAction="ifRoom">
<menu>
<item
android:id="#+id/deleteMenu"
android:title="Delete All" />
<item
android:id="#+id/exitMenu"
android:title="Exit" />
</menu>
</item>
<item
android:id="#+id/addMovieOffline"
android:title="Offline Mode" />
<item
android:id="#+id/addMovieOnline"
android:title="Online Mode" />
</menu>
That's what i have in java:
public class MyMainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_main);
}
// "Creating" my menu.
#Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.main_menu, menu);
return true;
}
}
How I use the items I just declare?
For example the "Exit" option
I think it is the most basic thing although I don't know how to reach the item as a button.. Or its already define it self as a button ?
I would like to get an example and explanation.
you are using menu item inside the item, which is not the correct way to group item in menu.
Try this xml to generate your menu
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<group android:id="#+id/my_menu" android:checkableBehavior="single">
<item
android:id="#+id/deleteMenu"
android:title="Delete All" />
<item
android:id="#+id/exitMenu"
android:title="Exit" />
</group >
<item
android:id="#+id/addMovieOffline"
android:title="Offline Mode" />
<item
android:id="#+id/addMovieOnline"
android:title="Online Mode" />
</menu>
For receiving events of the click on menu:
#override public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.item1:
// action needed
return true;
case R.id.item2:
// action needed
return true;
}
}
Use this
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.exitMenu:
//Your Logic
return true;
}
}
Use onOptionsItemSelected Method.
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId())
{
case R.id.exitMenu:
//code here
return true;
}
return(super.onOptionsItemSelected(item));
}
Use switch case to identify the ids of menu items.
I am developing a navigation drawer activity in android studio, in menu folder there is a settings item at the left corner. I want to remove it and add an image button over there in action bar. Can anyone tell me how to add that image button and how to perform click event on that button in main activity.
Check below image for reference -
I hope this helps, add this inside your menu.xml layout -
The showAsAction attribute allows you to define how the action is displayed. For example, the ifRoom attribute defines that the action is only displayed in the action bar if there is sufficient screen space available.
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="#+id/action_settings"
android:orderInCategory="100"
android:showAsAction="always"
android:icon="#drawable/ic_settings"
android:title="Settings">
</item>
</menu>
just try this.
no need to add imagebutton you just need to add
android:showAsAction="always"
and icon as
android:icon="#drawable/Your_icon"
do this in the menu.xml file, in item setting
Navigate to main_menu.xml in your menu folder under res and modify it as
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="#+id/image_button"
android:icon="#android:drawable/ic_menu_search"
android:title="Clickme"
app:showAsAction="always" />
</menu>
In your MainActivity
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item)
{
if(item.getItemId == R.id.image_button){
//do action on imagebutton click
return true;
}
return super.onOptionsItemSelected(item);
}
Previously my app name was being displayed hence I had to use getSupportActionBar().setDisplayShowTitleEnabled(false) to remove the text, but now in its place a blank action is displayed with three dots on the side showing the list items that I have defined.
I want Refresh and Back actions to be displayed directly into the action bar with their respective icons
eventdetails.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:app="schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/action_refresh"
app:showAsAction="always"
android:title="Refresh"
android:icon="#drawable/ic_action_refresh"
/>
<item
android:id="#+id/action_settings"
android:title="Settings"
app:showAsAction="ifRoom"
>
</item>
<item
android:id="#+id/action_back"
android:title="Back"
android:icon="#drawable/ic_action_back"
app:showAsAction="always"
/>
</menu>
EventDetails.java
public class EventDetails extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_event_details);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbarEventDetails);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayShowTitleEnabled(false);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater menuInflater = getMenuInflater();
menuInflater.inflate(R.menu.eventdetails, menu);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()){
case R.id.action_back:
Intent action_back = new Intent(EventDetails.this, EventView.class);
startActivity(action_back);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}
Your xmlns:app is not setup properly
change:
xmlns:app="schemas.android.com/apk/res-auto"
to
xmlns:app="http://schemas.android.com/apk/res-auto"