【问题标题】:Android: Navigation Component not working with both: <navigation> and NavigationItemSelectedListenerAndroid:导航组件不能同时使用:<navigation> 和 NavigationItemSelectedListener
【发布时间】:2020-12-07 18:28:54
【问题描述】:

我做了什么:

我创建了 Navigation Drawer Activity,作为 Navigation Drawer Activity 的更新新格式,根据新的 Android 架构,我使用 Navigation Component 获得了它强>结构。

NavControllerNavigationUINavigationView 代码如下,它是当我点击任何导航项时打开的片段。

    DrawerLayout drawer = findViewById(R.id.drawer_layout);
    NavigationView navigationView = findViewById(R.id.nav_view);
    // 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_profile, R.id.nav_privacy_policy,
            R.id.nav_terms, R.id.nav_contact_us, R.id.nav_share, R.id.nav_send)
            .setDrawerLayout(drawer)
            .build();
    NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
    NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
    NavigationUI.setupWithNavController(navigationView, navController);

这是给nav_host_fragment的:

<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:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:navGraph="@navigation/mobile_navigation" />

使用这个navigation/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.sohamerp.marsremedies.fragment.HomeFragment"
        android:label="@string/menu_home"
        tools:layout="@layout/fragment_home" />

    <fragment
        android:id="@+id/nav_profile"
        android:name="com.sohamerp.marsremedies.fragment.ProfileFragment"
        android:label="@string/menu_my_profile"
        tools:layout="@layout/fragment_profile" />

    <fragment
        android:id="@+id/nav_privacy_policy"
        android:name="com.sohamerp.marsremedies.fragment.PrivacyPolicyFragment"
        android:label="@string/menu_privacy_policy"
        tools:layout="@layout/fragment_privacy_policy" />

    <fragment
        android:id="@+id/nav_terms"
        android:name="com.sohamerp.marsremedies.fragment.TermsConditionFragment"
        android:label="@string/menu_terms"
        tools:layout="@layout/fragment_terms_condition" />

    <fragment
        android:id="@+id/nav_contact_us"
        android:name="com.sohamerp.marsremedies.fragment.ContactUsFragment"
        android:label="@string/menu_contact_us"
        tools:layout="@layout/fragment_terms_condition" />

</navigation>

我遇到问题的地方:

Android Studio 为所有 6 个菜单创建了片段,但我不想在单击最后两项时打开片段。 因此,我从mobile_navigation.xml 中删除了最后两个&lt;fragment&gt; 标签

我已尝试在下面添加 setNavigationItemSelectedListener

    navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
        @Override
        public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
            if (menuItem.getItemId() == R.id.nav_share)
                Toast.makeText(NavigationMenuActivity.this, "Sharing...", Toast.LENGTH_SHORT).show();
            else if (menuItem.getItemId() == R.id.nav_send)
                Toast.makeText(NavigationMenuActivity.this, "Rating...", Toast.LENGTH_SHORT).show();
            return false;
        }
    });

当我点击最后两个菜单时 Toast 正在显示,但前 4 个菜单不起作用。

我该怎么做才能让它工作?

build.gradle 依赖:

implementation 'androidx.navigation:navigation-fragment:2.1.0'
implementation 'androidx.navigation:navigation-ui:2.1.0'
implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0'

【问题讨论】:

  • 你能发布什么版本的导航组件,即你使用的是androidx.navigation:navigation-fragment吗?
  • 看起来您可能需要使缓存无效并重新启动(干净构建)
  • @Quantum_VC 用 gradle 依赖编辑了我的问题。
  • @Quantum_VC 我希望你有我的问题,不需要它。
  • 你有解决这个问题的办法吗?

标签: android android-fragments navigation-drawer android-architecture-navigation android-navigationview


【解决方案1】:

您可以创建一个 switch 语句,对于其他 4 个片段,您应该返回 true

    switch(menuItem.getItemId) {
      case R.id.import:
          navController.navigate(R.id.nav_home)
          return true
      case R.id.nav_gallery:
          navController.navigate(R.id.nav_gallery)
          return true
      case R.id.nav_slideshow:
          navController.navigate(R.id.nav_slideshow)
          return true
      case R.id.nav_tools:
          navController.navigate(R.id.nav_tools)
          return true
      case R.id.nav_share:
                Toast.makeText(NavigationMenuActivity.this, "Sharing...", Toast.LENGTH_SHORT).show();
          return false;
  case R.id.nav_send: 
                Toast.makeText(NavigationMenuActivity.this, "Rating...",Toast.LENGTH_SHORT).show();
          return false;
      default:
          return false;
}
}

通过覆盖 onBackPressed,您可以实现默认行为。 (注意:默认行为只是返回到第一个片段,然后在其关闭活动之后)

public void onBackPressed() {

 if (navigationDrawer.isDrawerOpen(GravityCompat.START)) {
            navigationDrawer.closeDrawer(GravityCompat.START)
    } else {
          if (navController.currentDestination?.id == R.id.nav_home){
              finish()
          } else {
           navController.navigate(R.id.action_global_nav_home)
           drawerView.menu.findItem(R.id.menu_item_nav_home).isChecked = true
          }

并在 navigation/mobile_navigation.xml 添加一个全局操作:

 <action
        android:id="@+id/action_global_nav_home"
        app:destination="@id/nav_home" />

【讨论】:

  • 不工作。它的可点击但不改变片段。
  • 我已经编辑了答案,只是检查了id,也许它可以写成更简洁的方式,但这就是想法。
  • 是的,它起作用了,但是它附加了一堆片段,所以每当我按下后退按钮时,它都会打开之前打开的所有片段。 (Note: The default behavior is just back once to first fragment then after its closing activity. I want this behavior.)
  • 覆盖 onBackPressed 可以实现该行为。
  • super.onBackPressed(); 做同样的事情,它从堆栈中一个一个地删除片段,并在出现home 片段时最后完成
【解决方案2】:

我得到了如下解决方案:

    // Passing each menu ID as a set of Ids because each
    // menu should be considered as top-level destinations.
    mAppBarConfigurationLeft = new AppBarConfiguration.Builder(
            R.id.nav_home, R.id.nav_outstanding, R.id.nav_profile, R.id.nav_privacy_policy,
            R.id.nav_terms, R.id.nav_contact_us, R.id.nav_share, R.id.nav_send)
            .setOpenableLayout(binding.drawerLayout)
            .build();
    navControllerLeft = Navigation.findNavController(this, R.id.nav_host_fragment);
    NavigationUI.setupActionBarWithNavController(this, navControllerLeft, mAppBarConfigurationLeft);
    NavigationUI.setupWithNavController(binding.navView, navControllerLeft);

    setUpHeaderView();

    /**
     * Clear Mapping code if Salesman or Admin has logged in
     */
    binding.navView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
        @Override
        public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
            switch (menuItem.getItemId()) {
                case R.id.nav_home:
                    navControllerLeft.navigate(R.id.nav_home);
                    break;
                case R.id.nav_outstanding:
                    navControllerLeft.navigate(R.id.nav_outstanding);
                    break;
                case R.id.nav_profile:
                    navControllerLeft.navigate(R.id.nav_profile);
                    break;
                case R.id.nav_privacy_policy:
                    navControllerLeft.navigate(R.id.nav_privacy_policy);
                    break;
                case R.id.nav_terms:
                    navControllerLeft.navigate(R.id.nav_terms);
                    break;
                case R.id.nav_contact_us:
                    navControllerLeft.navigate(R.id.nav_contact_us);
                    break;
                case R.id.nav_share:
                    Intent sharingIntent = new Intent(Intent.ACTION_SEND);
                    sharingIntent.setType("text/plain");
                    sharingIntent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.app_name));
                    sharingIntent.putExtra(Intent.EXTRA_TEXT, "Here I am sharing Skites App. Download here: https://play.google.com/store/apps/details?id=" + getPackageName());
                    sharingIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    startActivity(Intent.createChooser(sharingIntent, getString(R.string.app_name)));
                    break;
                case R.id.nav_send:
                    try {
                        startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + getPackageName())));
                    } catch (ActivityNotFoundException e) {
                        Toast.makeText(NavigationMenuActivity.this, "No Application Found to Rate", Toast.LENGTH_SHORT).show();
                    }
                    break;
            }
            binding.drawerLayout.closeDrawer(GravityCompat.START, true);
            return false;
        }
    });

希望对你有帮助,谢谢。

【讨论】:

    【解决方案3】:

    我找到了一个相当简单的解决方案,它工作起来相对轻松。 我用 setNavigationItemSelectedListener 覆盖了 NavigationView 这是一个 Ktlin 示例:

    import android.content.Context
    import android.util.AttributeSet
    import android.view.MenuItem
    import com.google.android.material.navigation.NavigationView
    
    /**
     * Created by EdgarK on 01/08/2020.
     */
    class SKNavigationView@JvmOverloads constructor(
        context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
    ) : com.google.android.material.navigation.NavigationView(context, attrs, defStyleAttr),
        NavigationView.OnNavigationItemSelectedListener {
        private var originalListener : OnNavigationItemSelectedListener? = null
        var menuItemNotHandledListener : OnNavigationItemSelectedListener? = null;
    
        override fun setNavigationItemSelectedListener(listener: OnNavigationItemSelectedListener?) {
            originalListener = listener
            super.setNavigationItemSelectedListener(this)
        }
    
        override fun onNavigationItemSelected(item: MenuItem): Boolean {
            val handled = originalListener?.onNavigationItemSelected(item) ?: false
            return handled || menuItemNotHandledListener?.onNavigationItemSelected(item) ?: false
        }
    }
    

    然后你可以设置menuItemNotHandledListener,它只会在原始的没有片段的情况下被调用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-09-22
      • 2020-01-15
      • 1970-01-01
      • 2020-06-27
      • 1970-01-01
      • 2019-03-19
      相关资源
      最近更新 更多