Androidx导航视图-`setNavigationItemSelectedListener`不起作用

时间:2018-11-03 13:03:14

标签: java android navigation-drawer android-architecture-navigation

我在做什么?

我一直在尝试使用Androidx导航抽屉(<com.google.android.material.navigation.NavigationView>)。我已经阅读了文档Here,该文档指出,为了处理项目选择,我们可以使用setNavigationItemSelectedListener

注意:我也正在使用JetPack的导航组件。

以下是: 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>

这里是: 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();
        }
    }

}

情况:

一切正常,我在运行时得到了Drawer,也得到了Hamburger,可以很好地显示带有菜单项的NavigationView

以下是: 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>

问题:

在点击菜单项时,它不会响应我的点击事件,也就是onNavigationItemSelected。如您所见,我的MainActivity.java不会出现Toast,开关内的任何菜单ID都不会起作用。

我一直在尝试许多示例和不同的方法来完成此操作。

有什么方法可以使菜单项响应我的选择事件?

如果您需要更多详细信息,请在下面做评论。

非常感谢您的帮助。

6 个答案:

答案 0 :(得分:4)

我想通了。

以防万一有人需要,我将其发布在这里。

代替此:

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);

我更改为:

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;
    }
});

它奏效了,可能是我们需要在附加onNavigationSelector之前配置所有内容。

答案 1 :(得分:4)

如果有人仍在寻找答案,那么如何兼得两者:NavigationController既可以处理NavigationView项目,又可以在NavigationView内部进行一些特定的操作。

通常在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>

首先为“ share_app” 菜单项定义 onClick 方法“ shareApp” 。然后在您的活动中创建如下所示的方法:

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..."))
}

不要忘记在活动(或任何需要的地方)的onCreate(savedInstanceState:Bundle?)方法重写乐趣中将工具栏,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)

}

答案 2 :(得分:1)

您可能还不了解切换订单的全部副作用。

NavigationUI.setupWithNavController(navigationView, navController); // Line 1
navigationView.setNavigationItemSelectedListener({...}) // Line 2

NavigationUI内部在NavigationView.OnNavigationItemSelectedListener处将NavigationView附加到Line1。您正在Line 2中用自定义监听器覆盖该监听器。

这意味着navController不起作用,您必须在自定义侦听器中手动处理所有导航操作。因此,完整的解决方案可能类似于以下方面:

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;
    }
});

注意: 您可能仍想在附加自定义侦听器之前先调用setupWithNavController,因为它除了附加导航项单击侦听器外,还执行其他操作。

答案 3 :(得分:0)

尝试一下,我希望这是一个完美的解决方案。只需编写以下代码即可导航到您的片段。

@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;

}

答案 4 :(得分:0)

MainActivity应该实现OnNavigationItemSelectedListener,您的代码应类似于

public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener{
...
}

答案 5 :(得分:0)

正确的顺序

navView.setupWithNavController(navController)
navView.setNavigationItemSelectedListener {
    Log.e(TAG, "onCreate: ", )
        true
}

如果不先执行 navView.setupWithNavControllerNavView.setNavigationItemSelectedListener 不会生效。