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

