【问题标题】:Adding spacing between BottomNavigationItem's icon & label在 BottomNavigationItem\ 的图标和标签之间添加间距
【发布时间】:2022-11-10 19:17:38
【问题描述】:

我正在尝试像这样构建我的底部导航:

@Composable
fun BottomNavBar(navController: NavController) {
    Column(
        Modifier.background(colorResource(id = R.color.pastel_orange_white))
    ) {
        BottomNavigation(
            modifier = Modifier
                .defaultMinSize(minHeight = 70.dp),
            backgroundColor = colorResource(id = R.color.bottom_nav_dark)
        ) {
            val navItems = arrayOf(
                BottomNavItem(
                    stringResource(id = R.string.title_home),
                    R.drawable.ic_home,
                    Screen.Home.route
                ),
                BottomNavItem(
                    stringResource(id = R.string.subjects_title),
                    R.drawable.ic_subject,
                    Screen.Subjects.route
                ),
                BottomNavItem(
                    stringResource(id = R.string.grades_title),
                    R.drawable.ic_grade,
                    Screen.Grades.route
                ),
                BottomNavItem(
                    "H/W",
                    R.drawable.ic_assignments,
                    Screen.Assignments.route
                )
            )
            // observe the backstack
            val navBackStackEntry by navController.currentBackStackEntryAsState()
            // observe current route to change the icon
            // color,label color when navigated
            val currentRoute = navBackStackEntry?.destination?.route
            navItems.forEach { navItem ->
                BottomNavigationItem(
                    selected = currentRoute == navItem.route,
                    onClick = {
                        navController.navigate(navItem.route)
                    },
                    icon = {
                        Box(
                            Modifier
                                .width(70.dp)
                                .height(30.dp)
                                .background(
                                    colorResource(id = if (currentRoute == navItem.route) R.color.bottom_nav_light else R.color.bottom_nav_dark),
                                    RoundedCornerShape(32.dp)
                                ),
                            contentAlignment = Alignment.Center
                        ) {
                            Icon(
                                painter = painterResource(id = navItem.icon),
                                contentDescription = navItem.label,
                                tint = colorResource(id = R.color.black)
                            )
                        }
                    },
                    label = {
                        Text(text = navItem.label, fontSize = 14.sp)
                    },
                    alwaysShowLabel = true,
                    selectedContentColor = colorResource(id = R.color.black),
                    unselectedContentColor = colorResource(id = R.color.black)
                )
            }
        }
    }
}

我需要在标签和图标部分之间添加一些额外的空间,因为我正在对所选项目应用小背景颜色。我尝试了填充、列排列等,但没有找到真正影响间距的东西。任何指针?

【问题讨论】:

    标签: android kotlin android-jetpack-compose


    【解决方案1】:

    我不认为你可以使用BottomNavigationItem 来做到这一点。如您所见here,Compose 的材料设计库遵循材料设计规范。

    但是您不需要使用BottomNavigationItem 来显示BottomAppBar 中的项目。您可以使用任何可组合的,如下所示:

    Column(
        horizontalAlignment = Alignment.CenterHorizontally,
        modifier = Modifier
            .weight(1f)
            .clickable {
                navController.navigate(navItem.route)
            }) {
        val color =
            if (currentRoute == navItem.route) 
                LocalContentColor.current 
            else 
                LocalContentColor.current.copy(alpha = ContentAlpha.medium)
        Icon(
            painter = painterResource(id = navItem.icon), 
            navItem.label, 
            tint = color
        )
        // Set the space that you want...
        Spacer(modifier = Modifier.height(4.dp))
        Text(text = navItem.label, color = color, fontSize = 12.sp)
    }
    

    但是,正如我上面提到的,该库遵循 Material Design 规范,它将BottomAppBar 的高度定义为 56dp。因此,如果您想要更自定义的东西,您需要自己处理(例如,使用Row)。

    【讨论】:

      【解决方案2】:

      我设法在图标和标签之间添加了填充。事实上,当我最初尝试这个时,我将填充应用于文本/标签而不是图标,但如果我们将填充应用于图标,则可以应用该间距。只需将Modifier.padding(bottom = YOURDP) 添加到您的图标即可。

      我认为这是可能的,因为在分析 Material Design 代码以应用带有 Icon 的标签后,它会应用相对于 Icon 的标签(您可以在下面的方法中看到),考虑到现有空间,所以如果我们增加空间图标占据,它将使标签更低。

      /**
       * Places the provided [labelPlaceable] and [iconPlaceable] in the correct position, depending on
       * [iconPositionAnimationProgress].
       *
       * When [iconPositionAnimationProgress] is 0, [iconPlaceable] will be placed in the center, as with
       * [placeIcon], and [labelPlaceable] will not be shown.
       *
       * When [iconPositionAnimationProgress] is 1, [iconPlaceable] will be placed near the top of item,
       * and [labelPlaceable] will be placed at the bottom of the item, according to the spec.
       *
       * When [iconPositionAnimationProgress] is animating between these values, [iconPlaceable] will be
       * placed at an interpolated position between its centered position and final resting position.
       *
       * @param labelPlaceable text label placeable inside this item
       * @param iconPlaceable icon placeable inside this item
       * @param constraints constraints of the item
       * @param iconPositionAnimationProgress the progress of the icon position animation, where 0
       * represents centered icon and no label, and 1 represents top aligned icon with label.
       * Values between 0 and 1 interpolate the icon position so we can smoothly move the icon.
       */
      private fun MeasureScope.placeLabelAndIcon(
          labelPlaceable: Placeable,
          iconPlaceable: Placeable,
          constraints: Constraints,
          /*@FloatRange(from = 0.0, to = 1.0)*/
          iconPositionAnimationProgress: Float
      ): MeasureResult {
          val height = constraints.maxHeight
      
          // TODO: consider multiple lines of text here, not really supported by spec but we should
          // have a better strategy than overlapping the icon and label
          val baseline = labelPlaceable[LastBaseline]
      
          val baselineOffset = CombinedItemTextBaseline.roundToPx()
      
          // Label should be [baselineOffset] from the bottom
          val labelY = height - baseline - baselineOffset
      
          val unselectedIconY = (height - iconPlaceable.height) / 2
      
          // Icon should be [baselineOffset] from the text baseline, which is itself
          // [baselineOffset] from the bottom
          val selectedIconY = height - (baselineOffset * 2) - iconPlaceable.height
      
          val containerWidth = max(labelPlaceable.width, iconPlaceable.width)
      
          val labelX = (containerWidth - labelPlaceable.width) / 2
          val iconX = (containerWidth - iconPlaceable.width) / 2
      
          // How far the icon needs to move between unselected and selected states
          val iconDistance = unselectedIconY - selectedIconY
      
          // When selected the icon is above the unselected position, so we will animate moving
          // downwards from the selected state, so when progress is 1, the total distance is 0, and we
          // are at the selected state.
          val offset = (iconDistance * (1 - iconPositionAnimationProgress)).roundToInt()
      
          return layout(containerWidth, height) {
              if (iconPositionAnimationProgress != 0f) {
                  labelPlaceable.placeRelative(labelX, labelY + offset)
              }
              iconPlaceable.placeRelative(iconX, selectedIconY + offset)
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-09-06
        • 2021-05-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多