BottomNavigationView与Navigation使用遇见的一个小坑

BottomNavigationView与Navigation使用遇见的一个小坑

2023年7月13日发(作者:)

BottomNavigationView与Navigation使⽤遇见的⼀个⼩坑BottomNavigationView 与 Navigation使⽤遇见的⼀个⼩坑先说结论吧,只是⼀个⼩问题,⾃⼰记录⼀下。如果⼤家是BottomNavigationView与NavController结合使⽤实现fragment的切换,发现⽆法切换,记得检查⼀下你创建的menu⽂件与navigation⽂件中的id是否是⼀⼀对应。最近在开发⼀个项⽬,因为项⽬的UI⽐较少相对也⽐较简单,考虑⽤⼀单Activity的实现⽅式,使⽤Jetpack的Navigation进⾏页⾯导航,主界⾯的tab实现使⽤⾕歌的BottomNavigationView控件。因为之前写过Demo,所以以为可以信⼿拈来。创建主界⾯的布局,Menu⽂件,以及navigation⽂件主界⾯布局 Menu

navigation MainActivityclass MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { te(savedInstanceState) setContentView(ty_main) initNavigation() } private fun initNavigation() { val navController = findNavController(_host_fragment) nav_ithNavController(navController) adjustNavigationIconSize(nav_view) }}⼤致的代码结构如上,我以为这样就可以实现切换了,之前的demo差不多也是这么个创建流程和使⽤⽅式,可是,tab终未能如约的切换。最开始我以为是我⾃⼰哪⾥写错了,上⽹搜了⼀圈各种教程,发现写的都⼤差不差,也没发现什么明显的错误,后来debug了⼀下,发现在切换的时候抛出了异常:lArgumentException: Navigation action/destination [package]:id/navigation_video cannot befound from the current destination Destination( [package]:id/cruiseFragment) label=CruiseFragment class=[package].Fragment然后发现抛出异常的地⽅在NavigationUI的onNavDestinationSelected⽅法中public static boolean onNavDestinationSelected(@NonNull MenuItem item, @NonNull NavController navController) { r builder = new r() .setLaunchSingleTop(true) .setEnterAnim(_default_enter_anim) .setExitAnim(_default_exit_anim) .setPopEnterAnim(_default_pop_enter_anim) .setPopExitAnim(_default_pop_exit_anim); if ((er() & RY_SECONDARY) == 0) { UpTo(findStartDestination(ph()).getId(), false); } NavOptions options = (); try { //TODO provide proper API instead of using Exceptions as Control-Flow. //具体报错在这⼀⾏

te(mId(), null, options); return true; } catch (IllegalArgumentException e) { return false; } }继续跟踪在NavController⾥⾯public void navigate(@IdRes int resId, @Nullable Bundle args, @Nullable NavOptions navOptions, @Nullable navigatorExtras) { NavDestination currentNode = y() mGraph : t().getDestination(); if (currentNode == null) { throw new IllegalStateException("no current navigation node"); } @IdRes int destId = resId; final NavAction navAction = ion(resId); Bundle combinedArgs = null; if (navAction != null) { if (navOptions == null) { navOptions = Options(); } destId = tinationId(); Bundle navActionArgs = aultArguments(); if (navActionArgs != null) { combinedArgs = new Bundle(); (navActionArgs); } } if (args != null) { if (combinedArgs == null) { combinedArgs = new Bundle(); } (args); } if (destId == 0 && navOptions != null && UpTo() != -1) { popBackStack(UpTo(), pToInclusive()); return; } if (destId == 0) { throw new IllegalArgumentException("Destination id == 0 can only be used" + " in conjunction with a valid o"); } NavDestination node = findDestination(destId); if (node == null) { final String dest = playName(mContext, destId); if (navAction != null) { throw new IllegalArgumentException("Navigation destination " + dest + " referenced from action " + playName(mContext, resId) + " cannot be found from the current destination " + currentNode); } else { throw new IllegalArgumentException("Navigation action/destination " + dest + " cannot be found from the current destination " + currentNode); } } navigate(node, combinedArgs, navOptions, navigatorExtras); }看到这⾥,⼤家应该明⽩,在NavController⾥⾯,NavDestination会根据destId查找下⼀个跳转的dest,⽽这个destId就是传进来的menuItem的Id。我们在主界⾯的布局⽂件中⽤来展⽰Fragment的宿主控件是"tFragment"这⾥有个属性 app:navGraph,具体查看这个NavHostFragment的源码,我们会发现它会基于这个navGraph指向的xml⽂件进⾏⼀个导航图表的创建,因为在navigation的每⼀个fragment中我们都设置了⼀个id,可以想象的是创建的这个导航图,肯定与这个id相关,那么navController调⽤navigate的时候如果传⼊⼀个导航图中不存在的id,肯定是⽆法找到合适的路由进⾏跳转的,所以这⾥,我们要保证Menu中的每⼀个Item的Id与中的每⼀个fragment的Id保持⼀致。最终修改的menu与navigation的⽂件如下Menu

naviagtion 当然,这⾥的id我个⼈觉得其实可以在values中创建⼀个ids的⽂件,创建对应的Id,然后在这两个布局⽂件中直接@id指向即可。

发布者:admin,转转请注明出处:http://www.yc00.com/news/1689216573a222353.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信