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

Android Java实现ImageView拖拽调整、图片遮罩及JSON动态布局方案

解决方案:ImageView拖拽调整+遮罩合成(Java)

一、实现可拖拽的ImageView

自定义DraggableImageView,通过触摸事件监听实现拖拽功能,利用Matrix控制图片位置:

import android.content.Context;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ImageView;

public class DraggableImageView extends ImageView {

    private final Matrix matrix = new Matrix();
    private final Matrix savedMatrix = new Matrix();
    private final PointF startPoint = new PointF();
    private boolean isDragging = false;

    public DraggableImageView(Context context) {
        super(context);
        init();
    }

    public DraggableImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public DraggableImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        setScaleType(ScaleType.MATRIX);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                savedMatrix.set(matrix);
                startPoint.set(event.getX(), event.getY());
                isDragging = true;
                break;
            case MotionEvent.ACTION_MOVE:
                if (isDragging) {
                    float dx = event.getX() - startPoint.x;
                    float dy = event.getY() - startPoint.y;
                    matrix.set(savedMatrix);
                    matrix.postTranslate(dx, dy);
                    setImageMatrix(matrix);
                }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_POINTER_UP:
                isDragging = false;
                break;
        }
        return true;
    }

    // 获取当前图片的变换矩阵,用于后续合成
    public Matrix getCurrentMatrix() {
        return new Matrix(matrix);
    }
}

二、实现遮罩合成功能

编写工具类MaskUtils,将拖拽调整后的图片与遮罩图合成,使用PorterDuff.Mode.SRC_IN实现遮罩裁剪效果:

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;

public class MaskUtils {

    /**
     * 合成原图与遮罩图
     * @param sourceBitmap 拖拽调整后的原图
     * @param maskBitmap 遮罩图
     * @param matrix 原图的拖拽变换矩阵
     * @return 合成后的Bitmap
     */
    public static Bitmap applyMask(Bitmap sourceBitmap, Bitmap maskBitmap, Matrix matrix) {
        if (sourceBitmap == null || maskBitmap == null) return null;

        // 创建与原图尺寸一致的空白Bitmap
        Bitmap resultBitmap = Bitmap.createBitmap(sourceBitmap.getWidth(), sourceBitmap.getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(resultBitmap);

        // 绘制变换后的原图
        Paint paint = new Paint();
        canvas.drawBitmap(sourceBitmap, matrix, paint);

        // 设置遮罩合成模式
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        // 将遮罩图缩放到原图尺寸后绘制
        canvas.drawBitmap(maskBitmap, null, new Rect(0, 0, sourceBitmap.getWidth(), sourceBitmap.getHeight()), paint);

        paint.setXfermode(null);
        return resultBitmap;
    }
}

三、在Activity中整合使用

假设布局包含DraggableImageView(id: draggable_img)、遮罩ImageView(id: mask_img)和合成按钮(id: btn_apply_mask):

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import androidx.appcompat.app.AppCompatActivity;

public class StoryMakerActivity extends AppCompatActivity {

    private DraggableImageView draggableImageView;
    private ImageView maskImageView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_story_maker);

        draggableImageView = findViewById(R.id.draggable_img);
        maskImageView = findViewById(R.id.mask_img);

        // 示例:加载本地图片(实际替换为相册选择的图片)
        Bitmap sourceBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.source_img);
        draggableImageView.setImageBitmap(sourceBitmap);

        Bitmap maskBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.mask_img);
        maskImageView.setImageBitmap(maskBitmap);

        // 合成按钮点击事件
        findViewById(R.id.btn_apply_mask).setOnClickListener(v -> applyMaskAndShowResult());
    }

    private void applyMaskAndShowResult() {
        Bitmap sourceBitmap = ((BitmapDrawable) draggableImageView.getDrawable()).getBitmap();
        Bitmap maskBitmap = ((BitmapDrawable) maskImageView.getDrawable()).getBitmap();
        Matrix matrix = draggableImageView.getCurrentMatrix();

        Bitmap resultBitmap = MaskUtils.applyMask(sourceBitmap, maskBitmap, matrix);
        if (resultBitmap != null) {
            // 展示合成后的图片
            ImageView resultImg = findViewById(R.id.result_img);
            resultImg.setImageBitmap(resultBitmap);
        }
    }
}

关键说明

  • 拖拽功能通过Matrix.postTranslate实现,需将ImageView的缩放类型设为ScaleType.MATRIX以支持自定义变换
  • 遮罩合成使用PorterDuff.Mode.SRC_IN,仅保留遮罩区域内的原图内容
  • 若需支持缩放拖拽,可在DraggableImageView中扩展GestureDetector添加缩放逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 22:36:20