17

私はこれを理解するのに本当に時間を費やしており、これまでのところ関連する経験を持つ友人を見つけることができません. これは、VERY FIRST APP をリリースする前の VERY LAST FEATURE です。

オブジェクトを許容範囲にドロップすると、ドラッグ アンド ドロップは完全に機能します。ただし、他の場所にドロップすると、イベントが発生せず、ドラッグ ドロップ操作が失敗した後にクリーンアップできません。ACTION_DRAG_ENDED イベントを発生させる必要があります。ただし、これは ACTION_DRAG_STARTED に true の値で応答した場合にのみ (ドキュメントによると) 起動します (オブジェクトを受け入れることができることを意味します)。問題は ACTION_DRAG_STARTED が起動していないことです!

したがって、問題の核心は、ACTION_DRAG_STARTED を取得していないことだと思います。関連するすべてのドラッグドロップ コード (または少なくともほぼすべて) をここに配置します。

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;
    }

};

拡張情報: dragView はリストビュー (具体的には展開可能なリストビュー) の項目レイアウトです。タッチ イベントを受け入れるビューは、小さなグリップが付いたビュー上の小さなグリフです。これは、ドラッグ操作が進行中のスクリーンショットです (これを取得するためにいくつかの派手な指の作業が必要でした 笑):

画面のドラッグ/ドロップ

したがって、ドラッグしたアイテムを別のアイテムにドロップすると(これにより並べ替えられます)、うまく機能します。他の場所にドロップすると、イベントが発生しないため、クリーンアップできません。たとえば、画面の上部、またはリストが空白領域または下部の青いバーまたはシステム領域のいずれかで不足している場合。

別の方法として、有効な領域からドラッグするのを防ぐ方法を見つけて、この問題を解決することもできます。その方法を知っていれば、それが別の解決方法です。私の最後のオプションは、画面上で可能なすべてのビューにイベントを実装することです (これらはリスト ビュー レイアウトであり、フラグメント上にあり、さまざまなアクティビティ上にある可能性があります)、明らかにこれは望ましくありません。実際、システムUI領域(システムバーや静電容量ボタン領域など)にドロップすると問題が発生する可能性がありますが、わかりません.

ここで役立つ場合は、リスト ビュー アダプターの get ビュー アイテム メソッドで関連するイベント プロシージャを割り当てます (無関係な行を削除しました)。

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;
}

そして最後に、これはリスト アイテム ビューのレイアウト XML です。

<?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>

助けてくれてありがとう!

4

2 に答える 2

11

ドラッグ イベントの通知が必要なビューは登録する必要がありますOnDragListeners。たとえば、特定の物や種類の物が動いたときに、それらの外観を変更する場合 (「ここにドラッグしてください!」または「私にそれを落とさないでください!」) に注意する必要がある場合。ビューがドラッグ中のオブジェクトをドロップする有効な場所でなくても、いわば「ドラッグ コンテキストを認識する」必要がある場合は、 を登録し、OnDragListenerに対して true を返しますACTION_DRAG_STARTED

あなたの非常に徹底的な質問から私が見逃していることの1つは、正確に何をクリーンアップする必要があるかということです. アクティビティのスコープ内にあるいくつかの一般的なことを行う必要があるだけの場合は、イベントを登録OnDragListenerするベースに別のものを追加することを検討できますが、アクティビティが一般的なクリーンアップ コードを実行するようにアラートするのをRelativeLayout待ちます。ACTION_DRAG_ENDED

于 2012-08-29T21:50:13.457 に答える