Android:导航组件不能同时使用:<navigation> 和 NavigationItemSelectedListener
Android: Navigation Component not working with both: <navigation> and NavigationItemSelectedListener
我做了什么:
我创建了导航抽屉Activity,更新了导航抽屉Activity的新格式,作为每个新的 Android 架构我用 Navigation Component 结构得到它。
下面的NavigationView
代码NavController
和NavigationUI
是点击任何导航项时的打开片段。
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
中删除了最后两个 <fragment>
标签
我尝试添加下面的 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'
您可以创建一个 switch 语句,对于其他 4 个片段,您应该 return 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,您可以实现默认行为。 (注意:默认行为只是返回到第一个片段,然后在其关闭后返回 activity)
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" />
我找到了一个相当简单的解决方案,它的工作相对轻松。
我用 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
只有当原始的没有碎片时才会被调用。
我得到的解决方案如下:
// 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;
}
});
希望对你有帮助,谢谢。
我做了什么:
我创建了导航抽屉Activity,更新了导航抽屉Activity的新格式,作为每个新的 Android 架构我用 Navigation Component 结构得到它。
下面的NavigationView
代码NavController
和NavigationUI
是点击任何导航项时的打开片段。
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
<fragment>
标签
我尝试添加下面的 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'
您可以创建一个 switch 语句,对于其他 4 个片段,您应该 return 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,您可以实现默认行为。 (注意:默认行为只是返回到第一个片段,然后在其关闭后返回 activity)
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" />
我找到了一个相当简单的解决方案,它的工作相对轻松。
我用 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
只有当原始的没有碎片时才会被调用。
我得到的解决方案如下:
// 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;
}
});
希望对你有帮助,谢谢。