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

安卓开发:如何在DragEvent事件中运行时将ImageView定位到指定坐标

实现自由放置ImageView的修复方案

你的代码存在以下几个核心问题导致图片无法正常显示:

  • 布局中的dropzone使用普通View,它不是视图容器,无法承载子View,需要换成支持自由定位的容器如FrameLayout
  • 添加ImageView时调用了addTouchables(),该方法仅将控件加入可触摸集合,并不会把View添加到视图渲染树中,需要用容器的addView()方法
  • 存在两处拼写错误:
    1. 三角形拖拽时ClipData存的字符串误写为"circle",应该改为"triangle"
    2. 形状匹配时case "cirlce"拼写错误,应该改为"circle"
  • 动态创建的ImageView没有设置宽高参数,默认宽高为0导致无法显示
  • 拖拽阴影的自定义逻辑冗余无效,可简化处理

第一步:修改布局XML

将原布局里的dropzone从普通View替换为FrameLayout容器:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:orientation="horizontal"
            android:layout_gravity="center">
                <Button
                    android:id="@+id/rectangle"
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent"
                    android:text="Rectangle" />

                <Button
                    android:id="@+id/circle"
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent"
                    android:text="Circle" />

                <Button
                    android:id="@+id/triangle"
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent"
                    android:text="Triangle" />
        </LinearLayout>
        <!-- 替换为FrameLayout容器 -->
        <FrameLayout
            android:id="@+id/dropzone"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/background_color">
        </FrameLayout>
</LinearLayout>

第二步:修改Activity代码

1. 调整dropzone变量类型

把原代码中private View dropzone = null;修改为private FrameLayout dropzone = null;

2. 修复拖拽触发逻辑

修正拼写错误,简化拖拽阴影生成逻辑:

private final class MyTouchListener implements View.OnLongClickListener {
    @SuppressLint("UseCompatLoadingForDrawables")
    @Override
    public boolean onLongClick(View v) {
            final int id = v.getId();
            Drawable shadow = null;
            ClipData.Item shape = null;

            if(id == R.id.circle) {
                shape = new ClipData.Item("circle");
                shadow = getResources().getDrawable(R.drawable.circle,null);
            } else if( id == R.id.rectangle) {
                shape = new ClipData.Item("rectangle");
                shadow = getResources().getDrawable(R.drawable.rectangle, null);
            } else if( id == R.id.triangle ) {
                // 修复三角形形状字符串错误
                shape = new ClipData.Item("triangle");
                shadow = getResources().getDrawable(R.drawable.triangle, null);
            }
            ImageView shadowImage = new ImageView(v.getContext());
            shadowImage.setImageDrawable(shadow);
            shadowImage.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
            shadowImage.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
            
            // 直接用形状图生成拖拽阴影
            View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(shadowImage);

            String[] mimeTypes = {ClipDescription.MIMETYPE_TEXT_PLAIN};
            ClipData draggedData = new ClipData(new ClipDescription("ClipData".toString(),mimeTypes),shape);
            v.startDragAndDrop(draggedData,shadowBuilder,v,0);

            return true;
    }
}

3. 修复放置逻辑

修正拼写错误,改用addView添加子视图:

private final class MyDragListener implements View.OnDragListener {
    public boolean onDrag(View v, DragEvent event) {
        final int id = v.getId();
        switch (event.getAction()) {
            case DragEvent.ACTION_DRAG_STARTED:
                Log.v("DROP","Coordinates: "+event.getX()+" , "+event.getY());
                break;
            case DragEvent.ACTION_DRAG_ENTERED:
                break;
            case DragEvent.ACTION_DRAG_EXITED:
                break;
            case DragEvent.ACTION_DROP:
                Log.v("DROP","item has been dropped");

                ClipData.Item item = event.getClipData().getItemAt(0);
                String shape = item.getText().toString();
                Log.v("DROP","Coordinates: "+event.getX()+" , "+event.getY());
                Log.v("DROP","Shape: "+shape);

                Drawable d = null;

                switch (shape){
                    // 修复circle拼写错误
                    case "circle":
                        d = getResources().getDrawable(R.drawable.circle,null);
                        break;
                    case "rectangle":
                        d = getResources().getDrawable(R.drawable.rectangle,null);
                        break;
                    case "triangle":
                        d = getResources().getDrawable(R.drawable.triangle,null);
                        break;
                }

                if(d == null) return true; // 空值容错
                Context ctx = v.getContext();
                ImageView img = new ImageView(ctx);
                img.setImageDrawable(d);
                // 设置宽高为自适应
                img.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT));
                // 坐标偏移优化:让图片中心对准松手位置
                img.setX(event.getX() - d.getIntrinsicWidth()/2f);
                img.setY(event.getY() - d.getIntrinsicHeight()/2f);
                // 直接将ImageView添加到容器
                ((FrameLayout)v).addView(img);

                break;
            case DragEvent.ACTION_DRAG_ENDED:

            default:
                break;
        }
        return true;
    }
}

可选扩展:实现已放置元素重定位

如果需要支持已经放置的图片拖拽调整位置,只需要给每个动态创建的ImageView设置和按钮一致的OnLongClickListener拖拽逻辑即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.11 03:12:03