我正在将新的Jetpack Android导航与抽屉布局结合使用。当在抽屉XML中使用相同的ID并结合导航图中的片段时,一切都按预期工作。我设置了所有内容:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val navController = findNavController(R.id.navigation_host_fragment)
setupActionBarWithNavController(navController, find(R.id.drawer_layout))
val navigationView = findViewById<NavigationView>(R.id.nav_view)
navigationView.setupWithNavController(findNavController(R.id.navigation_host_fragment))
}
我现在还想触发自定义操作/代码,而不是在单击抽屉菜单中的项目时执行片段事务。我有一个菜单,单击“注销”时想注销用户:
我用静态编程语言编写了那个扩展函数来解决这个问题:
fun NavigationView.setSafeNavigationItemSelectedListener(vararg listener: Pair<Int, () -> Unit>) =
listener.forEach { (itemId, act) ->
menu.findItem(itemId)?.setOnMenuItemClickListener { act(); true }
}
您可以按如下方式使用:
val navigationView = findViewById<NavigationView>(R.id.nav_view)
navigationView.setSafeNavigationItemSelectedListener(
R.id.shareIntent to {
shareIntent()
drawerLayout.closeDrawer(GravityCompat.START)
},
R.id.mySchedulesIntent to {
val i = Intent(this, MySchedulesActivity::class.java)
startActivity(i)
drawerLayout.closeDrawer(GravityCompat.START)
},
R.id.importantDetailsIntent to {
displayImportantDetailsDialog()
drawerLayout.closeDrawer(GravityCompat.START)
},
R.id.infoIntent to {
val i = Intent(this, InfoActivity::class.java)
startActivity(i)
drawerLayout.closeDrawer(GravityCompat.START)
},
R.id.settingsIntent to {
val i = Intent(this, SettingsActivity::class.java)
startActivity(i)
drawerLayout.closeDrawer(GravityCompat.START)
},
)
我也找到了解决办法。
首先,您需要创建自定义导航UI。
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.navigation.NavigationView;
import java.lang.ref.WeakReference;
import androidx.annotation.IdRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.navigation.NavController;
import androidx.navigation.NavDestination;
import androidx.navigation.ui.NavigationUI;
public class CustomNavigationUI {
public static void setupWithNavController(@NonNull final NavigationView navigationView,
@NonNull final NavController navController,
@Nullable final NavigationView.OnNavigationItemSelectedListener customListener) {
navigationView.setNavigationItemSelectedListener(
item -> {
boolean handled = NavigationUI.onNavDestinationSelected(item, navController);
if (handled) {
ViewParent parent = navigationView.getParent();
if (parent instanceof DrawerLayout) {
((DrawerLayout) parent).closeDrawer(navigationView);
} else {
BottomSheetBehavior bottomSheetBehavior =
findBottomSheetBehavior(navigationView);
if (bottomSheetBehavior != null) {
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
}
}
} else {
if (customListener != null) {
customListener.onNavigationItemSelected(item);
}
}
return handled;
});
final WeakReference<NavigationView> weakReference = new WeakReference<>(navigationView);
navController.addOnDestinationChangedListener(
new NavController.OnDestinationChangedListener() {
@Override
public void onDestinationChanged(@NonNull NavController controller,
@NonNull NavDestination destination, @Nullable Bundle arguments) {
NavigationView view = weakReference.get();
if (view == null) {
navController.removeOnDestinationChangedListener(this);
return;
}
Menu menu = view.getMenu();
for (int h = 0, size = menu.size(); h < size; h++) {
MenuItem item = menu.getItem(h);
item.setChecked(matchDestination(destination, item.getItemId()));
}
}
});
}
static BottomSheetBehavior findBottomSheetBehavior(@NonNull View view) {
ViewGroup.LayoutParams params = view.getLayoutParams();
if (!(params instanceof CoordinatorLayout.LayoutParams)) {
ViewParent parent = view.getParent();
if (parent instanceof View) {
return findBottomSheetBehavior((View) parent);
}
return null;
}
CoordinatorLayout.Behavior behavior = ((CoordinatorLayout.LayoutParams) params)
.getBehavior();
if (!(behavior instanceof BottomSheetBehavior)) {
// We hit a CoordinatorLayout, but the View doesn't have the BottomSheetBehavior
return null;
}
return (BottomSheetBehavior) behavior;
}
@SuppressWarnings("WeakerAccess") /* synthetic access */
static boolean matchDestination(@NonNull NavDestination destination,
@IdRes int destId) {
NavDestination currentDestination = destination;
while (currentDestination.getId() != destId && currentDestination.getParent() != null) {
currentDestination = currentDestination.getParent();
}
return currentDestination.getId() == destId;
}
}
其次,在活动中调用这个CustomNavigationUI而不是NavigationUI
/* NavigationUI.setupWithNavController(binding.navigationView, navController); */
CustomNavigationUI.setupWithNavController(binding.navigationView, navController, item -> {
switch (item.getItemId()){
case R.id.sign_out:
//todo sign out
break;
}
return true;
});
这就是全部!
我找到了一个解决方案:
val navigationView = findViewById<NavigationView>(R.id.nav_view)
val logoutItem = navigationView.menu.findItem(R.id.nav_logout)
logoutItem.setOnMenuItemClickListener {
toast("Log me out")
true
}
有什么方法可以确保抽屉菜单保持在片段内容的顶部吗? 我用虚拟数据创建了一个小测试应用程序。10个片段,带有相应的编号按钮和文本视图。问题在于片段元素似乎比导航抽屉具有更高的优先级。 如屏幕截图所示,一旦我试图打开“0片段”,它就会选择注册点击导航抽屉后面的按钮。按下任何其他内容项都可以,但只要它们下面没有其他可交互的项。我该怎么做才能让导航抽屉正确地位于其后面内容的顶部?
抽屉打开正常并正确显示,但当我单击列表中的项目时什么都没有发生。这是我从谷歌教程(UDACITY)中获取的代码。 我希望它能帮助你。 我做的一切都和教程视频完全一样。
我有一个类似Android Studios的应用程序导航抽屉活动: 我的活动使用Android架构导航组件 到目前为止,一切正常。返回时问题开始: 让我们想象我从“家”——片段甲——导航 Android Studio示例正确运行:C- 我的实现没有:它只是弹出后台C- 我该怎么弥补? 缩小主布局: 导航图: 与我的主要活动onCreate相关的所有导航:
当前状态:带有NavigationHeader和NavigationMenu项的NavigationDrawer。项目数量很大,因此需要滚动才能访问底部的项目。 要求:向下滚动到底部时,NavigationHeader应保持固定 这是我的活动\u主布局文件 这是我的导航\u标题\u主布局文件 另外,我是android开发新手。如果需要,请请求更多资源
我在我的应用程序中使用了可以在android工作室添加的抽屉菜单,我在导航抽屉中添加了一些菜单条目(参见代码块)。如果我按下第一个项目(nav_home)或第二个,导航抽屉会突出显示当前按下的项目。 如果我按下项目“nav_information”按钮或其他项目,则会打开新的(单击的)片段,并且看不到突出显示(主页或第二个项目仍突出显示) 很快,只有第一个项目在选定的项目上显示突出显示。 这是我处
有人能告诉我如何创建活动到这个主要活动,导航抽屉将看到在所有他们?我需要使用这个特定的MainActivity代码。我不需要使用碎片,只要3个简单的活动将添加到这个抽屉。 NavDrawer布局: