Android拖放ACTION_DRAG_ENDED未触发 [英] Android Drag and Drop ACTION_DRAG_ENDED not firing

查看:110
本文介绍了Android拖放ACTION_DRAG_ENDED未触发的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我真的有时间想到这一个,到目前为止还没有找到有关相关经验的朋友。在我发布我的第一个应用程序之前,这是我非常的最后的功能,所以它让我疯狂地陷入僵局,结束了!



如果我将对象放在可接受的区域,我的拖放可以完美地工作。但是,如果放在别的地方,我没有收到一个事件,并且在拖放操作失败后无法清理。我需要ACTION_DRAG_ENDED事件才能触发。但是,如果我用ACTION_DRAG_STARTED响应一个值true(意味着它可以接受该对象),那么这只会触发(根据文档)。问题是ACTION_DRAG_STARTED未触发!



所以我相信这个问题的关键是我没有得到ACTION_DRAG_STARTED。我正在把所有相关的拖放代码(或至少几乎全部)放在这里:

  private OnTouchListener onTouchListener =新的OnTouchListener(){

@Override
public boolean onTouch(View v,MotionEvent event){
if(event.getAction()== MotionEvent.ACTION_DOWN){
项目current =(Item)((View)v.getTag())。getTag();
// ClipData data = ClipData.newPlainText(test,testText);
查看dragView =(查看)v.getTag();
DragShadowBuilder shadowBuilder = new ItemDragShadowBuilder(dragView,
new Point(v.getWidth()/ 2,v.getHeight()/ 2));
dragSource = dragView;
v.startDrag(null,shadowBuilder,current,0);
dragView.setVisibility(View.INVISIBLE);
返回true;
} else {
return false;
}
}

};

private static class ItemDragShadowBuilder extends View.DragShadowBuilder {

private Point touchPoint = null;
private Point sizePoint = null;
private查看dragView = null;

public ItemDragShadowBuilder(查看dragView,Point touchPoint){
super();
sizePoint = new Point(dragView.getWidth(),dragView.getHeight());
this.touchPoint = touchPoint;
this.dragView = dragView;
}

@Override
public void onProvideShadowMetrics(Point size,Point touch){
size.set(sizePoint.x,sizePoint.y);
touch.set(touchPoint.x,touchPoint.y);
}

@Override
public void onDrawShadow(Canvas canvas){

dragView.setBackgroundColor(dragView.getContext()。getResources()。getColor (R.color.holoBlueDark));
dragView.draw(canvas);

//canvas.setBitmap(dragView.getDrawingCache());
//canvas.drawColor(Color.WHITE);
//dragView.setAlpha(1);

//如何更改透明度?
//super.onDrawShadow(canvas);
}



}


私人查看dragSource = null;

private OnDragListener onDragEventListener = new OnDragListener(){

@Override
public boolean onDrag(View v,DragEvent event){
final int action = event.getAction();

switch(action){
case DragEvent.ACTION_DRAG_STARTED:
Toast.makeText(v.getContext(),((EditText)v.findViewById(R.id.edtParent) ).getText()。toString()+started,Toast.LENGTH_SHORT / 8).show();
返回true;
// break; // DRAG AND DROP>>> START DOESNT FIRE
case DragEvent.ACTION_DROP:
if((dragSource!= null)&&(dragSource != v)){
项目源=(Item)dragSource.getTag();
项目目标=(项目)v.getTag();
int sourcePos = source.getPosition() ;
int targetPos = target.getPosition();
if(targetPos< sourcePos)
source.moveUp(sourcePos - targetPos);
else
source.moveDown (targetPos - sourcePos);
dragSource.setVisibility(View.VISIBLE);
dragSource = null;
fireOnChecklistNeedsResetListener();
return true;
}
// View view =(View)event.getLocalState();
// Toast.makeText(v.getContext(),((EditText)v.findViewById(R.id.edtParent))。get Text()。toString(),Toast.LENGTH_SHORT / 8).show();
// Toast.makeText(v.getContext(),((EditText)view.findViewById(R.id.edtParent))。getText()。toString(),Toast.LENGTH_SHORT / 8).show() ;
//删除,重新分配视图到ViewGroup
//查看视图=(查看)event.getLocalState();
// ViewGroup owner =(ViewGroup)view.getParent();
// owner.removeView(view);
// LinearLayout container =(LinearLayout)v;
// container.addView(view);
// view.setVisibility(View.VISIBLE);
break;
case DragEvent.ACTION_DRAG_ENDED:
dragSource.setVisibility(View.VISIBLE);
dragSource = null;
fireOnChecklistNeedsResetListener();
if(!event.getResult())
Toast.makeText(v.getContext(),UNHANDLED,Toast.LENGTH_SHORT / 8).show();

//查看vieww =(查看)event.getLocalState();
// Toast.makeText(v.getContext(),((EditText)v.findViewById(R.id.edtParent))。getText()。toString(),Toast.LENGTH_SHORT / 8).show() ;
// Toast.makeText(v.getContext(),((EditText)vieww.findViewById(R.id.edtParent))。getText()。toString(),Toast.LENGTH_SHORT / 8).show() ;
break;
case DragEvent.ACTION_DRAG_ENTERED:

v.setBackgroundColor(v.getContext()。getResources()。getColor(R.color.holoBlueLight));
返回true;
// break;
case DragEvent.ACTION_DRAG_EXITED:
v.setBackgroundColor(v.getContext()。getResources()。getColor(android.R.color.background_light));
返回false;
// break;
默认值:
break;
}
返回false;
}

};

扩展信息:dragView是列表视图中的项目布局(特别是可扩展列表视图)。接受触摸事件的视图是小视图上的小字形。这是一个拖动操作正在进行的屏幕截图(花了一些花哨的手指工作来获得这个哈哈):





所以如果我把拖动的项目放在另一个项目上(这将重新排序)工作很棒如果我把它放在别的地方,没有任何事件会触发,所以我永远都不能清理它。所以例如在屏幕的上部,或者列表在空白区域中是空白的,或者在底部或任何系统区域上的蓝色栏。



我可以或者通过找出一种方法来防止拖出有效区域来解决这个问题,所以如果你知道如何做到这一点,这是另一种解决方法。我最后一个选择是为屏幕上的每个可能的视图实现一个事件(这些都是列表视图布局,一个列表视图,这是一个片段,可能是各种活动),显然这是不可取的。事实上,如果我这样做,如果在系统UI区域(如系统栏或电容按钮区域)中丢失,我仍然可能会遇到问题,但我不确定。



如果这是有帮助的,我在哪里分配相关的事件过程(我删除不相关的行)在列表视图适配器获取视图项目方法:

 code> public View getGroupEdit(int groupPosition,boolean isExpanded,View convertView,
ViewGroup parent){
if(convertView!= null){
//无关的东西省略
} else
convertView = inf.inflate(R.layout.edit_group_item,null);
项目组=(Item)getGroup(groupPosition);
convertView.setTag(group);
EditText edtParent =(EditText)convertView.findViewById(R.id.edtParent);
edtParent.setTag(convertView);
scatterItemText(edtParent);

//无关的东西省略

ImageView imgGrip =(ImageView)convertView.findViewById(R.id.imgGrip);
imgGrip.setTag(convertView);
//无关的东西省略

imgGrip.setOnTouchListener(onTouchListener);
convertView.setOnDragListener(onDragEventListener);
return convertView;
}

最后FWIW,这是列表项视图的布局XML: / p>

 <?xml version =1.0encoding =utf-8?> 
< RelativeLayout xmlns:android =http://schemas.android.com/apk/res/android
android:layout_width =fill_parent
android:layout_height =55dip
android:orientation =horizo​​ntal>
< ImageView
android:id =@ + id / imgGrip
android:layout_width =wrap_content
android:layout_height =wrap_content
android: layout_alignParentLeft =true
android:src =@ drawable / dark_grip2
android:contentDescription =@ string / strReorder/>
< CheckBox
android:id =@ + id / chkParent
android:layout_width =wrap_content
android:layout_height =wrap_content
android: layout_toRightOf =@ id / imgGrip
android:checked =false/>
< EditText
android:id =@ + id / edtParent
android:layout_width =fill_parent
android:layout_height =wrap_content
android: layout_toRightOf =@ id / chkParent
android:layout_toLeftOf =@ + id / btnInsert
android:textSize =17dip
android:inputType =text
android :提示= @串/ strItem/>
< ImageButton
android:id =@ id / btnInsert
android:layout_height =wrap_content
android:layout_width =wrap_content
android:layout_toLeftOf =@ + id / viewParent
android:src =@ drawable / dark_content_new
android:clickable =true
android:hint =@ string / strAddItemAbove
android:contentDescription =@ string / strAddItemAbove/>
< View
android:id =@ id / viewParent
android:layout_height =match_parent
android:layout_width =0dp
android:layout_toLeftOf = @ + ID / btnExpand/>
< ImageButton
android:id =@ id / btnExpand
android:layout_height =wrap_content
android:layout_width =wrap_content
android:layout_alignParentRight =true
android:src =@ drawable / dark_add_sub_item
android:clickable =true
android:hint =@ string / strViewSubItems
android:contentDescription = @串/ strViewSubItems/>
< / RelativeLayout>

非常感谢任何帮助!

解决方案

需要通知拖动事件的视图必须注册 OnDragListeners 。如果他们需要注意特定的事物或类型的事情,例如为了改变它们的外观(或者是DRAG ME HERE!,或者你不会在我身上丢失)。即使您的视图不是放置被拖动对象的有效位置,如果需要拖动上下文感知,则可以注册一个 OnDragListener 并返回true对于 ACTION_DRAG_STARTED



我从你的非常彻底的问题中缺少的一件事是你需要做什么清理了如果您只需要执行一些属于活动范围的通用内容,您可以考虑将基础不同的 OnDragListener 添加到基础 RelativeLayout 为事件注册,但等待 ACTION_DRAG_ENDED 提醒活动执行您的通用清理代码


I'm really having a time figuring this one out and can't find any friends with the relevant experience so far. It's my VERY LAST FEATURE before I release my VERY FIRST APP so it's driving me crazy to have gotten bogged down with it with the end in sight!

My drag and drop works perfectly if I drop the object in an acceptable area. However, if dropped somewhere else I do not get an event and cannot clean up after the failed drag drop operation. I need the ACTION_DRAG_ENDED event to fire. However this only fires (according to the documentation) if I respond to ACTION_DRAG_STARTED with a value of true (meaning it can accept the object). The problem is ACTION_DRAG_STARTED is not firing!

So I believe the crux of the matter is that I'm not getting ACTION_DRAG_STARTED. I'm putting what should be all of the relevant dragdrop code (or at least nearly all) here:

private OnTouchListener onTouchListener = new OnTouchListener() {

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            Item current = (Item) ((View) v.getTag()).getTag();
            //ClipData data = ClipData.newPlainText("test", "testText");
            View dragView = (View) v.getTag();
            DragShadowBuilder shadowBuilder = new ItemDragShadowBuilder(dragView, 
                                new Point(v.getWidth()/2, v.getHeight()/2));
            dragSource = dragView;
            v.startDrag(null, shadowBuilder, current, 0);
            dragView.setVisibility(View.INVISIBLE);
            return true;
        } else {
            return false;
        }       
    }

};

private static class ItemDragShadowBuilder extends View.DragShadowBuilder {

    private Point touchPoint = null;
    private Point sizePoint = null;
    private View dragView = null;

    public ItemDragShadowBuilder(View dragView, Point touchPoint) {
        super();
        sizePoint = new Point(dragView.getWidth(), dragView.getHeight());
        this.touchPoint = touchPoint;
        this.dragView = dragView;
    }

    @Override
    public void onProvideShadowMetrics (Point size, Point touch) {
        size.set(sizePoint.x, sizePoint.y);
        touch.set(touchPoint.x,touchPoint.y);
    }

    @Override
    public void onDrawShadow(Canvas canvas) {

        dragView.setBackgroundColor(dragView.getContext().getResources().getColor(R.color.holoBlueDark));
        dragView.draw(canvas);

        //canvas.setBitmap(dragView.getDrawingCache());
        //canvas.drawColor(Color.WHITE);
        //dragView.setAlpha(1);

        //How do I change the transparency?
        //super.onDrawShadow(canvas);
    }



}


private View dragSource = null;

private OnDragListener onDragEventListener = new OnDragListener() {

    @Override
    public boolean onDrag(View v, DragEvent event) {
        final int action = event.getAction();

        switch (action) {
        case DragEvent.ACTION_DRAG_STARTED:
            Toast.makeText(v.getContext(), ((EditText) v.findViewById(R.id.edtParent)).getText().toString() + " started", Toast.LENGTH_SHORT/8).show();
            return true;
            //break;//DRAG AND DROP>>>START DOESN"T FIRE
        case DragEvent.ACTION_DROP:
            if ((dragSource != null) && (dragSource != v)) {
                Item source = (Item) dragSource.getTag();
                Item target = (Item) v.getTag();
                int sourcePos = source.getPosition();
                int targetPos = target.getPosition();
                if (targetPos < sourcePos)
                    source.moveUp(sourcePos - targetPos);
                else
                    source.moveDown(targetPos - sourcePos);
                dragSource.setVisibility(View.VISIBLE);
                dragSource = null;
                fireOnChecklistNeedsResetListener();
                return true;
            }
//              View view = (View) event.getLocalState();
//              Toast.makeText(v.getContext(), ((EditText) v.findViewById(R.id.edtParent)).getText().toString(), Toast.LENGTH_SHORT/8).show();
//              Toast.makeText(v.getContext(), ((EditText) view.findViewById(R.id.edtParent)).getText().toString(), Toast.LENGTH_SHORT/8).show();
            // Dropped, reassign View to ViewGroup
//              View view = (View) event.getLocalState();
//              ViewGroup owner = (ViewGroup) view.getParent();
//              owner.removeView(view);
//              LinearLayout container = (LinearLayout) v;
//              container.addView(view);
//              view.setVisibility(View.VISIBLE);
            break;
        case DragEvent.ACTION_DRAG_ENDED:
            dragSource.setVisibility(View.VISIBLE);
            dragSource = null;
            fireOnChecklistNeedsResetListener();
            if (!event.getResult())
                Toast.makeText(v.getContext(), "UNHANDLED", Toast.LENGTH_SHORT/8).show();

//              View vieww = (View) event.getLocalState();
//              Toast.makeText(v.getContext(), ((EditText) v.findViewById(R.id.edtParent)).getText().toString(), Toast.LENGTH_SHORT/8).show();
//              Toast.makeText(v.getContext(), ((EditText) vieww.findViewById(R.id.edtParent)).getText().toString(), Toast.LENGTH_SHORT/8).show();
            break;
        case DragEvent.ACTION_DRAG_ENTERED:

            v.setBackgroundColor(v.getContext().getResources().getColor(R.color.holoBlueLight));
            return true;
            //break;
        case DragEvent.ACTION_DRAG_EXITED:        
            v.setBackgroundColor(v.getContext().getResources().getColor(android.R.color.background_light));
            return false;
            //break;
        default:
            break;
    }
        return false;
    }

};

Extended information: The dragView is an item layout in a listview (specifically an expandablelistview). The view that accepts the touch event is a small glyph on the view with a small grip. Here is a screenshot with a drag operation in progress (took some fancy finger work to get this lol):

So if I were to drop the dragged item on another item (this reorders them) it works great. If I drop it somewhere else no event fires so I can never clean it up. So for example in the upper part of the screen or if the list is short in a blank area or the blue bar on bottom or any of the system areas.

I could alternatively solve this problem by figuring out a way to prevent dragging away from a valid area so if you know how to do that, that's another way to solve it. My last option would be to implement an event for every possible view on the screen (again these are list view layouts, on a listview, which is on a fragment, which could be on various activities) so obviously this would not be desirable. And in fact if I do that I still may have a problem if it's dropped in a system UI area (like systembar or capacitive buttons area) but I'm not sure.

In case it is helpful here is where I assign the relevant event procedures (I removed irrelevant lines) in the list view adapters get view item method:

public View getGroupEdit(int groupPosition, boolean isExpanded, View convertView,
        ViewGroup parent) {
    if (convertView != null) {
                //irrelevant stuff omitted
    } else
        convertView = inf.inflate(R.layout.edit_group_item, null);
    Item group = (Item) getGroup(groupPosition);
    convertView.setTag(group);
    EditText edtParent = (EditText) convertView.findViewById(R.id.edtParent);
    edtParent.setTag(convertView);
    scatterItemText(edtParent);

            //irrelevant stuff omitted

    ImageView imgGrip = (ImageView) convertView.findViewById(R.id.imgGrip);
    imgGrip.setTag(convertView);
             //irrelevant stuff omitted     

            imgGrip.setOnTouchListener(onTouchListener);
    convertView.setOnDragListener(onDragEventListener);
    return convertView;
}

And finally FWIW, this is the layout XML for the list item view:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="55dip"
android:orientation="horizontal" >
<ImageView 
    android:id="@+id/imgGrip"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentLeft="true"
    android:src="@drawable/dark_grip2"
    android:contentDescription="@string/strReorder"/>
<CheckBox 
    android:id="@+id/chkParent"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_toRightOf="@id/imgGrip"
    android:checked="false"/>
<EditText
    android:id="@+id/edtParent"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_toRightOf="@id/chkParent"
    android:layout_toLeftOf="@+id/btnInsert"
    android:textSize="17dip" 
    android:inputType="text"
    android:hint="@string/strItem"/>
<ImageButton
    android:id="@id/btnInsert"
    android:layout_height="wrap_content"
    android:layout_width="wrap_content"
    android:layout_toLeftOf="@+id/viewParent"
    android:src="@drawable/dark_content_new"
    android:clickable="true"
    android:hint="@string/strAddItemAbove"
    android:contentDescription="@string/strAddItemAbove" />   
<View 
    android:id="@id/viewParent"
    android:layout_height="match_parent"
    android:layout_width="0dp"
    android:layout_toLeftOf="@+id/btnExpand"/>    
<ImageButton 
    android:id="@id/btnExpand"
    android:layout_height="wrap_content"
    android:layout_width="wrap_content"
    android:layout_alignParentRight="true"
    android:src="@drawable/dark_add_sub_item"
    android:clickable="true"
    android:hint="@string/strViewSubItems"
    android:contentDescription="@string/strViewSubItems"/>   
</RelativeLayout>

Thanks so much for any help!

解决方案

Views that need to be notified of drag events must register OnDragListeners. If they need to be aware when specific things or types of things move, for instance in order to change their appearance (either to a "DRAG ME HERE!" or a "DON'T YOU DARE DROP THAT ON ME!"). Even if your view is not a valid place to drop the object being dragged, if it needs to be 'drag context aware' so to speak, it registers an OnDragListener and returns true forACTION_DRAG_STARTED.

The one thing I'm missing from your very thorough question is what exactly you need to be cleaned up? If you just need to do some generic things that are in the scope of the activity, you might consider adding a different OnDragListener to the base RelativeLayout that registers for the events but waits for ACTION_DRAG_ENDED to alert the activity to perform your generic cleanup code

这篇关于Android拖放ACTION_DRAG_ENDED未触发的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆