[英]Androidx Navigation View - `setNavigationItemSelectedListener` Doesn't Work
What am I doing?我在做什么?
I have been trying to work with Androidx Navigation Drawer( <com.google.android.material.navigation.NavigationView>
).我一直在尝试使用 Androidx Navigation Drawer(
<com.google.android.material.navigation.NavigationView>
)。 I've read the documentationHere , which says that for handling item selections we can use setNavigationItemSelectedListener
.我已经阅读了文档Here ,它说为了处理项目选择,我们可以使用
setNavigationItemSelectedListener
。
Note: I am using JetPack's Navigation Component as well.注意:我也在使用 JetPack 的导航组件。
Below is: main_activity.xml下面是: main_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<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"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/colorPrimary"
android:theme="@style/ThemeOverlay.AppCompat.Dark" />
<fragment
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph" />
</LinearLayout>
<com.google.android.material.navigation.NavigationView
android:id="@+id/navigationView"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:menu="@menu/drawer_menu" />
</androidx.drawerlayout.widget.DrawerLayout>
Here is: MainActivity.java这是: MainActivity.java
import android.os.Bundle;
import android.view.MenuItem;
import android.widget.Toast;
import com.google.android.material.navigation.NavigationView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import androidx.navigation.ui.NavigationUI;
public class MainActivity extends AppCompatActivity {
public Toolbar toolbar;
public DrawerLayout drawerLayout;
public NavController navController;
public NavigationView navigationView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setupNavigation();
}
// Setting Up One Time Navigation
private void setupNavigation() {
toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
drawerLayout = findViewById(R.id.drawer_layout);
navigationView = findViewById(R.id.navigationView);
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
Toast.makeText(MainActivity.this, "Hello", Toast.LENGTH_SHORT).show();
return false;
}
});
navController = Navigation.findNavController(this, R.id.nav_host_fragment);
NavigationUI.setupActionBarWithNavController(this, navController, drawerLayout);
NavigationUI.setupWithNavController(navigationView, navController);
}
@Override
public boolean onSupportNavigateUp() {
return NavigationUI.navigateUp(drawerLayout, Navigation.findNavController(this, R.id.nav_host_fragment));
}
@Override
public void onBackPressed() {
if (drawerLayout.isDrawerOpen(GravityCompat.START)) {
drawerLayout.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
}
Situation:情况:
Everything displays fine, I get the Drawer
at runtime, I also get the Hamburger
, It works fine to display the NavigationView
with the menu items.一切都显示得很好,我在运行时得到了
Drawer
,我也得到了Hamburger
,它可以很好地显示带有菜单项的NavigationView
。
Below is: drawer_menu.xml下面是: drawer_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:checkableBehavior="single">
<item
android:id="@+id/first"
android:icon="@mipmap/ic_launcher"
android:title="First" />
<item
android:id="@+id/second"
android:icon="@mipmap/ic_launcher"
android:title="Second" />
<item
android:id="@+id/third"
android:icon="@mipmap/ic_launcher"
android:title="Third" />
</group>
</menu>
Problem:问题:
On tapping the menu items, it does not respond to my click events, aka onNavigationItemSelected
.在点击菜单项时,它不会响应我的点击事件,也就是
onNavigationItemSelected
。 As you can see my MainActivity.java
, the Toast
does not appear neither any of the menu ids work inside switch.如您所见,我的
MainActivity.java
没有出现Toast
也没有任何菜单 ID 在 switch 内工作。
I've been trying many examples and different ways to get this done.我一直在尝试许多示例和不同的方法来完成这项工作。
Is there any way to make menu items respond to my select events?有没有办法让菜单项响应我的选择事件?
If you need any more details on this, please do comment below.如果您需要更多详细信息,请在下面发表评论。
Thank You so much for the Help.十分感谢你的帮助。
I Figured it out guys.我想通了伙计们。
Just in case if someone needs it, I'm posting it here.以防万一有人需要它,我把它张贴在这里。
Instead of this:取而代之的是:
navigationView = findViewById(R.id.navigationView);
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
Toast.makeText(MainActivity.this, "Hello", Toast.LENGTH_SHORT).show();
return false;
}
});
navController = Navigation.findNavController(this, R.id.nav_host_fragment);
NavigationUI.setupActionBarWithNavController(this, navController, drawerLayout);
NavigationUI.setupWithNavController(navigationView, navController);
I changed to:我改为:
navigationView = findViewById(R.id.navigationView);
navController = Navigation.findNavController(this, R.id.nav_host_fragment);
NavigationUI.setupActionBarWithNavController(this, navController, drawerLayout);
NavigationUI.setupWithNavController(navigationView, navController);
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
Toast.makeText(MainActivity.this, "Hello", Toast.LENGTH_SHORT).show();
return false;
}
});
And it worked, may be we need to configure everything before attaching the onNavigationSelector
.它起作用了,可能我们需要在附加
onNavigationSelector
之前配置所有内容。
You might not have understood the full side effect of switching the order.您可能不了解切换顺序的全部副作用。
NavigationUI.setupWithNavController(navigationView, navController); // Line 1
navigationView.setNavigationItemSelectedListener({...}) // Line 2
The NavigationUI
internally attaches NavigationView.OnNavigationItemSelectedListener
to the NavigationView
at Line1
. NavigationUI
内部将NavigationView.OnNavigationItemSelectedListener
附加到Line1
处的NavigationView
。 You are overriding that listener with your custom listener in Line 2
.您正在
Line 2
使用自定义侦听器覆盖该侦听器。
This means navController
won't work and you have to handle all of the navigation actions manually in your custom listener.这意味着
navController
将无法工作,您必须在自定义侦听器中手动处理所有导航操作。 So the full solution might be something along the lines of:所以完整的解决方案可能是这样的:
NavigationUI.setupWithNavController(navigationView, navController);
navigationView.setNavigationItemSelectedListener(
new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
// TODO: do stuff
Toast.makeText(MainActivity.this, "Hello", Toast.LENGTH_SHORT).show();
// You need this line to handle the navigation
boolean handled = NavigationUI.onNavDestinationSelected(menuItem, navController);
if (handled) {
ViewParent parent = navigationView.getParent();
if (parent instanceof DrawerLayout) {
((DrawerLayout) parent).closeDrawer(navigationView);
}
}
return handled;
}
});
Note: You still might want to call setupWithNavController
before attaching your custom listener because it does things other than attaching navigation item click listener.注意:您可能仍然希望在附加自定义侦听
setupWithNavController
之前调用setupWithNavController
,因为它除了附加导航项单击侦听器之外还执行其他操作。
In case that someone still looking for answer how to have both: NavigationController to handle NavigationView items, but also to have some specific action inside of the NavigationView.如果有人仍在寻找如何同时拥有的答案: NavigationController 来处理 NavigationView 项目,但还要在 NavigationView 内部进行一些特定的操作。
In menu.xml file setup menu items as usual:在 menu.xml 文件中设置菜单项照常:
<menu>
<item
android:id="@+id/fragment_settings"
android:icon="@drawable/ic_settings"
android:orderInCategory="3"
android:title="@string/settings" />
<item
android:id="@+id/share_app"
android:icon="@drawable/ic_share"
android:orderInCategory="4"
android:onClick="shareApp"
android:title="@string/share_to_friends" />
<item
android:id="@+id/fragment_about"
android:icon="@drawable/ic_info"
android:orderInCategory="5"
android:title="@string/about" />
</menu>
First define a onClick method "shareApp" for the "share_app" menu item.首先为“share_app”菜单项定义一个onClick方法“shareApp” 。 Then in your activity create method like this:
然后在您的活动中创建这样的方法:
fun shareApp(item:MenuItem) {
logD("share app clicked!")
val intent = Intent(Intent.ACTION_SEND).apply {
putExtra(Intent.EXTRA_TEXT, "some text to send...")
type = "text/*"
}
startActivity(Intent.createChooser(intent, "Share app..."))
}
Don't forget to attach a Toolbar, NavigationView and DrawerLayout to NavController in the override fun onCreate(savedInstanceState: Bundle?) method of activity (or where ever you want)不要忘记在覆盖 fun onCreate(savedInstanceState: Bundle?) 活动方法(或您想要的任何地方)中将 Toolbar、NavigationView 和 DrawerLayout 附加到 NavController
override fun onCreate(savedInstanceState: Bundle?) {
setTheme(R.style.AppTheme)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setupActionBarWithNavController(navController, drawer_layout)
setupWithNavController(nav_view, navController)
setupWithNavController(toolbar, navController, drawer_layout)
}
Try this, this one is perfect solution I hope.
试试这个,这是我希望的完美解决方案。 Simply write below code to navigate to your fragments.
只需编写以下代码即可导航到您的片段。
@Override
protected void onCreate(Bundle savedInstanceState) {
..........
..........
navigationView.setNavigationItemSelectedListener(this);
}
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
menuItem.setChecked(true);
drawerLayout.closeDrawers();
int id = menuItem.getItemId();
switch (id) {
case R.id.first:
navController.navigate(R.id.firstFragment);// **firstFragment** is the id that is written the file under **res/navigation/mobile_navigation.xml**
break;
case R.id.second:
navController.navigate(R.id.secondFragment);
break;
case R.id.third:
navController.navigate(R.id.thirdFragment);
break;
}
return true;
}
MainActivity should implement OnNavigationItemSelectedListener, your code should look like MainActivity 应该实现 OnNavigationItemSelectedListener,你的代码应该看起来像
public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener{
...
}
The correct order正确的顺序
navView.setupWithNavController(navController)
navView.setNavigationItemSelectedListener {
Log.e(TAG, "onCreate: ", )
true
}
If you don't execute navView.setupWithNavController
first, NavView.setNavigationItemSelectedListener
will not take effect.如果不先执行
navView.setupWithNavController
, NavView.setNavigationItemSelectedListener
不会生效。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.