簡體   English   中英

如何在jetpack compose中創建水印文字效果

[英]How to create watermark text effect in jetpack compose

我想使用如下圖所示的文本在我的應用程序中創建水印效果。 我通過使用 canvas 和 bitmap 實現了這一點,還有其他可靠的方法嗎?

這是我的可組合 function

@Composable
fun WaterMark(
  modifier: Modifier = Modifier,
  content: (@Composable BoxScope.() -> Unit)? = null,
) {

  val watermarkText: String = "some mutable text"

  val paint = Paint(Paint.ANTI_ALIAS_FLAG)
  paint.textSize = LocalContext.current.dpToPx(24).toFloat()
  paint.color = PSCoreColours.psCoreColours.onSurface.hashCode()
  paint.textAlign = Paint.Align.LEFT
  paint.alpha = (255 * 0.25).toInt()
  val baseline: Float = -paint.ascent()
  val image: Bitmap = Bitmap.createBitmap(paint.measureText(watermarkText).toInt(),
    (baseline + paint.descent()).toInt(),
    Bitmap.Config.ARGB_8888)

  val canvas = android.graphics.Canvas(image)
  canvas.drawText(watermarkText, 0f, baseline, paint)
  val rotationMatrix: Matrix = Matrix().apply { postRotate(-45f) }

  val rotatedImage: Bitmap = Bitmap.createBitmap(image, 0, 0, image.width, image.height, rotationMatrix, true)

  val pattern: ImageBitmap = rotatedImage.asImageBitmap()

  Box {
    content?.let { it() }
    Canvas(
      modifier = modifier
    ) {
      val totalWidth = size.width / pattern.width
      val totalHeight = size.height / pattern.height
      var x = 0f
      var y = 0f
      for (i in 0..totalHeight.toInt()) {
        y = (i * pattern.height).toFloat()
        for (j in 0..totalWidth.toInt()) {
          x = (j * pattern.width).toFloat()
          drawImage(
            pattern,
            colorFilter = null,
            topLeft = Offset(x, y),
          )
        }
      }
    }
  }
}

您可以為此在撰寫中進行自定義布局

private const val SPACING = 100

@Composable
fun Watermark(
  content: @Composable BoxScope.() -> Unit,
) {
  Box {
    content()

    Layout(
      content = {
        // Repeating the placeables, 6 should do for now but we should be able to calculate this too
        repeat(6) { 
          Text(
            text = watermarkText,
            ..
          )
        }
      }
    ) { measurables, constraints ->
      // Measuring all the placables
      val placeables: List<Placeable> = measurables
        .map { measurable -> measurable.measure(constraints) }
        
      layout(constraints.maxWidth, constraints.maxHeight) {
        // Calculating the max width of a placable
        val maxWidth: Double = placeables.maxOf { it.width }.toDouble()

        // Calculating the max width of a tile given the text is rotated
        val tileSize: Int = (constraints.maxWidth / atan(maxWidth)).toInt()
        
        placeables
          .chunked(2)  // Placing 2 columns 
          .forEachIndexed { index, (first, second) ->
            val indexedTileSize: Int = index * tileSize
            first.placeRelativeWithLayer(-SPACING, indexedTileSize + SPACING) { rotationZ = -45f }
            second.placeRelativeWithLayer(tileSize, indexedTileSize) { rotationZ = -45f }
        }
      }
    }
  }
}

水印 function 在每次重組時創建PaintBitmap的實例。 你應該像在這個答案中那樣用記住來包裝它們。

但是,我認為,您可能會在沒有PaintBitmap的情況下using Modifier.drawWithContent{}drawText DrawScope並在DrawScope內使用translaterotate來完成您所做的完全 Compose 方式。

這是一個drawText 示例,用於了解如何創建和存儲TextLayoutResult記住。

另一個使用Modifier.drawWithContent示例

您也可以嘗試使用Modifier.drawWithCache在布局階段緩存 TextLayoutResult 而不是 Google Compose 開發人員建議在此處處理 Text 的組合階段

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM