安卓开发:如何在DragEvent事件中运行时将ImageView定位到指定坐标
实现自由放置ImageView的修复方案
你的代码存在以下几个核心问题导致图片无法正常显示:
- 布局中的dropzone使用普通
View,它不是视图容器,无法承载子View,需要换成支持自由定位的容器如FrameLayout - 添加ImageView时调用了
addTouchables(),该方法仅将控件加入可触摸集合,并不会把View添加到视图渲染树中,需要用容器的addView()方法 - 存在两处拼写错误:
- 三角形拖拽时ClipData存的字符串误写为
"circle",应该改为"triangle" - 形状匹配时
case "cirlce"拼写错误,应该改为"circle"
- 三角形拖拽时ClipData存的字符串误写为
- 动态创建的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
相关产品推荐
相关产品推荐

