【问题标题】:Android Compose - custom linearGradient with angle like GradientDrawableAndroid Compose - 具有类似 GradientDrawable 的角度的自定义线性渐变
【发布时间】:2021-05-19 07:21:13
【问题描述】:

如何使用角度参数自定义 Brush.linearGradient(),例如 O、45、90、135... 或其他任何角度?

谢谢。

【问题讨论】:

    标签: android linear-gradients android-jetpack-compose


    【解决方案1】:

    为 LinearGradient 设置任意角度似乎是个好主意,但这需要做太多工作...

    而设置角度如0、45、90、135..比较简单。使用Brush.linearGradient(...)的方法,可以结合参数startend来制作。

    首先看到这个函数

            @Stable
            fun linearGradient(
                colors: List<Color>,
                start: Offset = Offset.Zero,
                end: Offset = Offset.Infinite,
                tileMode: TileMode = TileMode.Clamp
            )
    

    从默认参数值(开始,结束),我们可以得出默认角度是 135。如何?

    start = Offset.Zero == Offset(0f, Float.POSITIVE_INFINITY)
    end = Offset.Infinite == Offset(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY)
    
    
    

    在笛卡尔坐标中从头到尾,我们可以看到方向是右下,所以角度是135。所以,我们可以得出结论

    angle 0
    start = Offset(0f,0f)
    end = Offset(Float.INFINITY,0f)
    
    angle 45 
    start = Offset(0f, Float.POSITIVE_INFINITY)
    end = Offset(Float.POSITIVE_INFINITY, 0f)
    
    angle 90 
    start = Offset(0f, Float.POSITIVE_INFINITY)
    end = Offset(0f,0f)
    ... 
    ``
    

    【讨论】:

    • 您的回答未涵盖问题的“或任何角度”部分。
    • @EmadRazavi 我已经制作了一个支持任何角度的通用解决方案,并写了一篇关于它的中篇文章(感谢第一个解决方案的想法)。如有需要请查看stackoverflow.com/a/71577996/6941949
    【解决方案2】:

    我已经制作了一个支持任何角度的通用解决方案,并为此写了一个medium article(感谢第一个解决方案的想法)。有需要就去看看

    【讨论】:

      【解决方案3】:

      以 45 度的间隔逆时针实施配给

      fun GradientOffset(angle: GradientAngle): GradientOffset {
          return when (angle) {
              GradientAngle.CW45 -> GradientOffset(
                  start = Offset.Zero,
                  end = Offset.Infinite
              )
              GradientAngle.CW90 -> GradientOffset(
                  start = Offset.Zero,
                  end = Offset(0f, Float.POSITIVE_INFINITY)
              )
              GradientAngle.CW135 -> GradientOffset(
                  start = Offset(Float.POSITIVE_INFINITY, 0f),
                  end = Offset(0f, Float.POSITIVE_INFINITY)
              )
              GradientAngle.CW180 -> GradientOffset(
                  start = Offset(Float.POSITIVE_INFINITY, 0f),
                  end = Offset.Zero,
              )
              GradientAngle.CW225 -> GradientOffset(
                  start = Offset.Infinite,
                  end = Offset.Zero
              )
              GradientAngle.CW270 -> GradientOffset(
                  start = Offset(0f, Float.POSITIVE_INFINITY),
                  end = Offset.Zero
              )
              GradientAngle.CW315 -> GradientOffset(
                  start = Offset(0f, Float.POSITIVE_INFINITY),
                  end = Offset(Float.POSITIVE_INFINITY, 0f)
              )
              else -> GradientOffset(
                  start = Offset.Zero,
                  end = Offset(Float.POSITIVE_INFINITY, 0f)
              )
          }
      }
      
      /**
       * Offset for [Brush.linearGradient] to rotate gradient depending on [start] and [end] offsets.
       */
      data class GradientOffset(val start: Offset, val end: Offset)
      
      enum class GradientAngle {
          CW0, CW45, CW90, CW135, CW180, CW225, CW270, CW315
      }
      

      使用枚举类定义逆时针旋转,得到GradientOffset,它返回Brush.linearGradientstartend偏移量

      @Composable
      fun GradientRotationDemo() {
      
          val canvasSize = 300.dp
          val canvasModifier = Modifier
              .size(canvasSize)
      
      
          // Offsets for gradients based on selected angle
          var gradientOffset by remember {
              mutableStateOf(GradientOffset(GradientAngle.CW0))
          }
      
          var angleSelection by remember { mutableStateOf(0f) }
          var angleText by remember { mutableStateOf("0 Degrees") }
      
      
          Column(
              modifier = Modifier
                  .fillMaxSize()
                  .background(backgroundColor)
                  .padding(8.dp)
          ) {
      
              Text(
                  text = angleText,
                  color = Blue400,
                  modifier = Modifier
                      .padding(8.dp),
                  fontSize = 18.sp,
                  fontWeight = FontWeight.Bold
              )
      
              Slider(
                  modifier = Modifier.height(50.dp),
                  value = angleSelection,
                  onValueChange = {
                      angleSelection = it
         
                      gradientOffset = when (angleSelection.roundToInt()) {
                          0 -> {
                              angleText = "0 Degrees"
                              GradientOffset(GradientAngle.CW0)
                          }
                          1 -> {
                              angleText = "45 Degrees"
                              GradientOffset(GradientAngle.CW45)
                          }
                          2 -> {
                              angleText = "90 Degrees"
                              GradientOffset(GradientAngle.CW90)
                          }
                          3 -> {
                              angleText = "135 Degrees"
                              GradientOffset(GradientAngle.CW135)
                          }
                          4 -> {
                              angleText = "180 Degrees"
                              GradientOffset(GradientAngle.CW180)
                          }
      
                          5 -> {
                              angleText = "225 Degrees"
                              GradientOffset(GradientAngle.CW225)
                          }
                          6 -> {
                              angleText = "270 Degrees"
                              GradientOffset(GradientAngle.CW270)
                          }
                          else -> {
                              angleText = "315 Degrees"
                              GradientOffset(GradientAngle.CW315)
                          }
      
                      }
                  },
                  steps = 6,
                  valueRange = 0f..7f
              )
      
              Column(
                  Modifier
                      .fillMaxSize()
                      .verticalScroll(rememberScrollState()),
                  horizontalAlignment = Alignment.CenterHorizontally
              ) {
      
      
                  CanvasWithTitle(
                      modifier = canvasModifier,
                      text = "Gradient"
                  ) {
                      val redGreenGradient = Brush.linearGradient(
                          colors = listOf(Color.Red, Color.Green, Color.Blue),
                      )
                      drawRect(redGreenGradient)
                  }
      
                  CanvasWithTitle(
                      modifier = canvasModifier,
                      text = "Gradient Angle"
                  ) {
                      val redGreenGradient = Brush.linearGradient(
                          colors = listOf(Color.Red, Color.Green, Color.Blue),
                          start = gradientOffset.start,
                          end = gradientOffset.end
                      )
                      drawRect(redGreenGradient)
                  }
              }
          }
      }
      

      CanvasWithTitle 没有什么特别之处,但为了方便测试,我也添加了它

      private fun CanvasWithTitle(
          modifier: Modifier = Modifier,
          text: String,
          onDraw: DrawScope.() -> Unit
      ) {
          Column(
              modifier = Modifier
                  .wrapContentWidth()
          ) {
      
              Text(
                  text = text,
                  color = Blue400,
                  modifier = Modifier
                      .padding(8.dp),
                  fontSize = 18.sp,
                  fontWeight = FontWeight.Bold
              )
      
              Canvas(modifier = modifier, onDraw = onDraw)
          }
      }
      

      顺便说一下,Brush.linearGradient 的初始旋转角度是逆时针 315 度,或者顺时针 45 度

      结果,顶部是默认渐变,底部是通过获取开始和结束偏移量来应用旋转功能的渐变

      要以任何角度旋转,您需要创建一个函数来获取 Composable 的宽度和高度并使用 2d 旋转

      xNew = x*cos(angle) - y*sin(angle)
      yNew = x*sin(angle) + y*cos(angle)
      

      但不确定如何转换回轴以在旋转 45 度的函数中具有相同的值。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-12-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多