You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android中ImageView内水印文本的拖拽功能实现求助

Fixing Draggable Watermark Text on Android ImageView

Hey there! I totally get how frustrating it is to nail that drag-and-drop functionality after already getting the watermark to show up. Let's fix this step by step.

First, the core issue with your current code: your redrawImage() method draws the text at a fixed (0F, 0F) position every time. To make it draggable, we need to track the text's dynamic coordinates, handle touch events to update those coordinates, and redraw the watermark at the new spot efficiently.

The cleanest, most performant way to do this is to create a custom ImageView that handles both drawing the watermark and processing touch input. Here's how to implement it:

Step 1: Create a Custom WaterMarkImageView

This class extends ImageView, tracks the watermark's position and text, and builds in drag logic.

import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.MotionEvent
import android.widget.ImageView

class WaterMarkImageView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : ImageView(context, attrs, defStyleAttr) {

    // Watermark text (updates trigger redraw)
    var waterMarkText: String = ""
        set(value) {
            field = value
            invalidate()
        }

    // Track current watermark position
    private var waterMarkX = 0f
    private var waterMarkY = 0f

    // Offset between touch point and watermark origin (prevents jump on drag start)
    private var touchOffsetX = 0f
    private var touchOffsetY = 0f

    // Pre-configured paint for watermark
    private val waterMarkPaint = Paint().apply {
        color = Color.BLACK
        alpha = 100
        textSize = 26f
        isAntiAlias = true
        isUnderlineText = true
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        // Draw watermark only if text exists
        if (waterMarkText.isNotEmpty()) {
            canvas.drawText(waterMarkText, waterMarkX, waterMarkY, waterMarkPaint)
        }
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                // Calculate the gap between touch point and watermark position
                touchOffsetX = event.x - waterMarkX
                touchOffsetY = event.y - waterMarkY
                return true // Claim ownership of this touch event
            }
            MotionEvent.ACTION_MOVE -> {
                // Update watermark position using the offset (keeps touch relative to text)
                waterMarkX = event.x - touchOffsetX
                waterMarkY = event.y - touchOffsetY
                invalidate() // Trigger redraw at new position
                return true
            }
        }
        return super.onTouchEvent(event)
    }
}

Step 2: Swap Your Layout's ImageView

Replace the standard ImageView in your layout XML with your custom view:

<com.yourpackage.WaterMarkImageView
    android:id="@+id/waterMarkImageView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:scaleType="fitCenter" />

Step 3: Sync EditText Input to the Custom View

Forget generating new Bitmaps every time — just update the custom view's text property when the EditText changes:

// In your Activity/Fragment
val waterMarkEditText = findViewById<EditText>(R.id.waterMarkEditText)
val waterMarkImageView = findViewById<WaterMarkImageView>(R.id.waterMarkImageView)

// Set your initial image
waterMarkImageView.setImageBitmap(src)

// Sync EditText input to the watermark
waterMarkEditText.addTextChangedListener(object : TextWatcher {
    override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
    override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
        waterMarkImageView.waterMarkText = s.toString()
    }
    override fun afterTextChanged(s: Editable?) {}
})

Optional: Keep Watermark Within Image Bounds

If you don't want users dragging the watermark outside the ImageView, add bounds checks in the ACTION_MOVE block:

MotionEvent.ACTION_MOVE -> {
    val newX = event.x - touchOffsetX
    val newY = event.y - touchOffsetY

    // Limit X to stay within view width (account for text length)
    waterMarkX = newX.coerceIn(0f, width.toFloat() - waterMarkPaint.measureText(waterMarkText))
    // Limit Y to stay within view height (account for text size)
    waterMarkY = newY.coerceIn(waterMarkPaint.textSize, height.toFloat())

    invalidate()
    return true
}

This setup is way smoother than your original Bitmap regeneration approach — no lag during drags, and instant text updates as the user types.

内容的提问来源于stack exchange,提问作者aman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 19:27:42