【问题标题】:How to remove DropdownMenu's default vertical padding when clicking the first item?单击第一项时如何删除 DropdownMenu 的默认垂直填充?
【发布时间】:2022-11-18 15:59:38
【问题描述】:

我正在尝试实现一个简单的 DropdownMenu。 一切正常,但是当我单击第一个项目时,涟漪效应不会完全覆盖顶部的 DropDownMenu,最后一个项目也会发生同样的情况。

这是正在发生的事情的图像:

这是我的代码:


  MaterialTheme(shapes=MaterialTheme.shapes.copy(medium = RoundedCornerShape(16.dp))) {

                DropdownMenu(
                    expanded = expanded,
                    onDismissRequest = { expanded = false },

                ) {
                    DropdownMenuItem(onClick = {
                        Toast.makeText(
                            context,
                            "Refresh Clicked",
                            Toast.LENGTH_SHORT
                        ).show()
                    }
                    ,


                    ) {
                        Text("Refresh")
                    }
                    DropdownMenuItem(onClick = {
                        Toast.makeText(
                            context,
                            "Setting Clicked",
                            Toast.LENGTH_SHORT
                        ).show()
                    }) {
                        Text("Settings")
                    }
                    Divider()
                    DropdownMenuItem(onClick = {
                        Toast.makeText(
                            context,
                            "Details Clicked",
                            Toast.LENGTH_SHORT
                        ).show()
                    }) {
                        Text("Details")
                    }


                }

【问题讨论】:

    标签: android kotlin drop-down-menu android-jetpack-compose


    【解决方案1】:

    不幸的是,目前还无法执行此消息。 它隐藏在代码深处并被硬编码:

    Column(
            modifier = modifier
                .padding(vertical = DropdownMenuVerticalPadding)
                .width(IntrinsicSize.Max)
                .verticalScroll(rememberScrollState()),
            content = content
        )
    

    另外,看看: https://github.com/JetBrains/compose-jb/issues/1831

    【讨论】:

      【解决方案2】:

      将文件复制到项目并调用 DropdownMenuNoPaddingVeitical

      // Menu open/close animation.
      const val InTransitionDuration = 120
      const val OutTransitionDuration = 75
      private val MenuElevation = 8.dp
      private val MenuVerticalMargin = 48.dp
      
              @Composable
          fun DropdownMenuNoPaddingVeitical(
              expanded: Boolean,
              onDismissRequest: () -> Unit,
              modifier: Modifier = Modifier,
              offset: DpOffset = DpOffset(0.dp, 0.dp),
              properties: PopupProperties = PopupProperties(focusable = true),
              content: @Composable ColumnScope.() -> Unit
          ) {
              val expandedStates = remember { MutableTransitionState(false) }
              expandedStates.targetState = expanded
          
              if (expandedStates.currentState || expandedStates.targetState) {
                  val transformOriginState = remember { mutableStateOf(TransformOrigin.Center) }
                  val density = LocalDensity.current
                  val popupPositionProvider = DropdownMenuPositionProvider(
                      offset,
                      density
                  ) { parentBounds, menuBounds ->
                      transformOriginState.value = calculateTransformOrigin(parentBounds, menuBounds)
                  }
          
                  Popup(
                      onDismissRequest = onDismissRequest,
                      popupPositionProvider = popupPositionProvider,
                      properties = properties
                  ) {
                      DropdownMenuContent(
                          expandedStates = expandedStates,
                          transformOriginState = transformOriginState,
                          modifier = modifier,
                          content = content
                      )
                  }
              }
          }
          
          @Composable
          fun DropdownMenuContent(
              expandedStates: MutableTransitionState<Boolean>,
              transformOriginState: MutableState<TransformOrigin>,
              modifier: Modifier = Modifier,
              content: @Composable ColumnScope.() -> Unit
          ) {
              // Menu open/close animation.
              val transition = updateTransition(expandedStates, "DropDownMenu")
          
              val scale by transition.animateFloat(
                  transitionSpec = {
                      if (false isTransitioningTo true) {
                          // Dismissed to expanded
                          tween(
                              durationMillis = InTransitionDuration,
                              easing = LinearOutSlowInEasing
                          )
                      } else {
                          // Expanded to dismissed.
                          tween(
                              durationMillis = 1,
                              delayMillis = OutTransitionDuration - 1
                          )
                      }
                  }, label = ""
              ) {
                  if (it) {
                      // Menu is expanded.
                      1f
                  } else {
                      // Menu is dismissed.
                      0.8f
                  }
              }
          
              val alpha by transition.animateFloat(
                  transitionSpec = {
                      if (false isTransitioningTo true) {
                          // Dismissed to expanded
                          tween(durationMillis = 30)
                      } else {
                          // Expanded to dismissed.
                          tween(durationMillis = OutTransitionDuration)
                      }
                  }, label = ""
              ) {
                  if (it) {
                      // Menu is expanded.
                      1f
                  } else {
                      // Menu is dismissed.
                      0f
                  }
              }
              Card(
                  modifier = Modifier.graphicsLayer {
                      scaleX = scale
                      scaleY = scale
                      this.alpha = alpha
                      transformOrigin = transformOriginState.value
                  },
                  elevation = MenuElevation
              ) {
                  Column(
                      modifier = modifier
                          .width(IntrinsicSize.Max)
                          .verticalScroll(rememberScrollState()),
                      content = content
                  )
              }
          }
          
          
          private val MenuVerticalMargin = 48.dp
          
          data class DropdownMenuPositionProvider(
              val contentOffset: DpOffset,
              val density: Density,
              val onPositionCalculated: (IntRect, IntRect) -> Unit = { _, _ -> }
          ) : PopupPositionProvider {
              override fun calculatePosition(
                  anchorBounds: IntRect,
                  windowSize: IntSize,
                  layoutDirection: LayoutDirection,
                  popupContentSize: IntSize
              ): IntOffset {
                  // The min margin above and below the menu, relative to the screen.
                  val verticalMargin = with(density) { MenuVerticalMargin.roundToPx() }
                  // The content offset specified using the dropdown offset parameter.
                  val contentOffsetX = with(density) { contentOffset.x.roundToPx() }
                  val contentOffsetY = with(density) { contentOffset.y.roundToPx() }
          
                  // Compute horizontal position.
                  val toRight = anchorBounds.left + contentOffsetX
                  val toLeft = anchorBounds.right - contentOffsetX - popupContentSize.width
                  val toDisplayRight = windowSize.width - popupContentSize.width
                  val toDisplayLeft = 0
                  val x = if (layoutDirection == LayoutDirection.Ltr) {
                      sequenceOf(
                          toRight,
                          toLeft,
                          // If the anchor gets outside of the window on the left, we want to position
                          // toDisplayLeft for proximity to the anchor. Otherwise, toDisplayRight.
                          if (anchorBounds.left >= 0) toDisplayRight else toDisplayLeft
                      )
                  } else {
                      sequenceOf(
                          toLeft,
                          toRight,
                          // If the anchor gets outside of the window on the right, we want to position
                          // toDisplayRight for proximity to the anchor. Otherwise, toDisplayLeft.
                          if (anchorBounds.right <= windowSize.width) toDisplayLeft else toDisplayRight
                      )
                  }.firstOrNull {
                      it >= 0 && it + popupContentSize.width <= windowSize.width
                  } ?: toLeft
          
                  // Compute vertical position.
                  val toBottom = maxOf(anchorBounds.bottom + contentOffsetY, verticalMargin)
                  val toTop = anchorBounds.top - contentOffsetY - popupContentSize.height
                  val toCenter = anchorBounds.top - popupContentSize.height / 2
                  val toDisplayBottom = windowSize.height - popupContentSize.height - verticalMargin
                  val y = sequenceOf(toBottom, toTop, toCenter, toDisplayBottom).firstOrNull {
                      it >= verticalMargin &&
                              it + popupContentSize.height <= windowSize.height - verticalMargin
                  } ?: toTop
          
                  onPositionCalculated(
                      anchorBounds,
                      IntRect(x, y, x + popupContentSize.width, y + popupContentSize.height)
                  )
                  return IntOffset(x, y)
              }
          }
          
          fun calculateTransformOrigin(
              parentBounds: IntRect,
              menuBounds: IntRect
          ): TransformOrigin {
              val pivotX = when {
                  menuBounds.left >= parentBounds.right -> 0f
                  menuBounds.right <= parentBounds.left -> 1f
                  menuBounds.width == 0 -> 0f
                  else -> {
                      val intersectionCenter =
                          (
                                  kotlin.math.max(parentBounds.left, menuBounds.left) +
                                          kotlin.math.min(parentBounds.right, menuBounds.right)
                                  ) / 2
                      (intersectionCenter - menuBounds.left).toFloat() / menuBounds.width
                  }
              }
              val pivotY = when {
                  menuBounds.top >= parentBounds.bottom -> 0f
                  menuBounds.bottom <= parentBounds.top -> 1f
                  menuBounds.height == 0 -> 0f
                  else -> {
                      val intersectionCenter =
                          (
                                  kotlin.math.max(parentBounds.top, menuBounds.top) +
                                          kotlin.math.min(parentBounds.bottom, menuBounds.bottom)
                                  ) / 2
                      (intersectionCenter - menuBounds.top).toFloat() / menuBounds.height
                  }
              }
              return TransformOrigin(pivotX, pivotY)
          }
      

      【讨论】:

      • InTransitionDuration 、OutTransitionDuration 和 MenuElevation 的值是多少?这些有错误。
      • 可能我复制的时候忘记了,我再更新
      猜你喜欢
      • 2017-04-23
      • 2020-09-12
      • 2017-12-23
      • 1970-01-01
      • 2018-10-17
      • 2023-02-08
      • 2018-02-26
      • 2020-06-11
      • 2019-12-20
      相关资源
      最近更新 更多