拖放图像视图无法正常工作

时间:2015-02-16 02:36:48

标签: android drag-and-drop imageview relativelayout ontouchlistener

我的RelativeLayout有一张图片。我只是试图让它在整个布局中可拖动。问题是每次我拖放时,它都会回到原来的位置。这是我的

drag_layout.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/mainView"
    android:background="@drawable/bg_animation"
    tools:context="com.example.activities.AnimationActivity">
    <ImageView
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:src="@drawable/ic_launcher"
        android:id="@+id/appLogo"
        android:layout_alignBottom="@+id/ba_cell_animation"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="47dp" />
</RelativeLayout>

AnimationActivity.java

public class AnimationActivity extends ActionBarActivity implements View.OnTouchListener, View.OnDragListener {

    static ImageView mLogo;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_animation);
        setTitle("Animation");
        Typeface mAnimPromptTF = Typeface.createFromAsset(getAssets(), "fonts/Jelloween - Machinato ExtraLight.ttf");
        Typeface mAnimBonusTF = Typeface.createFromAsset(getAssets(), "fonts/Jelloween - Machinato SemiBold Italic.ttf");
        mAnimPrompt = (TextView) findViewById(R.id.anim_prompt);
        mAnimBonus = (TextView) findViewById(R.id.anim_bonus);
        mAnimPrompt.setTypeface(mAnimPromptTF);
        mAnimBonus.setTypeface(mAnimBonusTF);

        mLogo = (ImageView) findViewById(R.id.appLogo);


        mLogo.setOnTouchListener(this);
        findViewById(R.id.mainView).setOnDragListener(this);

    }

    @Override
    public boolean onTouch(View v, MotionEvent e) {
        // TODO Auto-generated method stub
        if (e.getAction() == MotionEvent.ACTION_DOWN) {
            View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(v);
            v.startDrag(null, shadowBuilder, v, 0);
            v.setVisibility(View.INVISIBLE);
            return true;
        } else {
            return false;
        }
    }

    @Override
    public boolean onDrag(View v, DragEvent e) {
        // TODO Auto-generated method stub

        switch (e.getAction()) {
            case DragEvent.ACTION_DROP:
                View view = (View) e.getLocalState();
                ViewGroup from = (ViewGroup) view.getParent();
                from.removeView(view);
                RelativeLayout to = (RelativeLayout) v;
                to.addView(view);
                view.setVisibility(View.VISIBLE);

                break;

            //the drag point has entered the bounding box of the View
            case DragEvent.ACTION_DRAG_ENTERED:
                break;

            //the user has moved the drag shadow outside the bounding box of the View
            case DragEvent.ACTION_DRAG_EXITED:
                break;

            // the drag and drop operation has concluded.
            case DragEvent.ACTION_DRAG_ENDED:
                break;

            default:


                break;
        }

        return true;
    }

    @Override
    public void onBackPressed() {
        Intent intent = new Intent(this, MainActivity.class);
        startActivity(intent);
    }
}

我尝试了以下所有链接,但仍然不知道我哪里出错:

http://www.vogella.com/tutorials/AndroidDragAndDrop/article.html

http://codingjunkie.net/android-drag-and-drop-part1

http://tech-papers.org/android-drag-and-drop

我真的尝试了很多。

4 个答案:

答案 0 :(得分:2)

我终于找到了解决方案请参考以下代码: 就像这段代码一样简单。

@Override
    public boolean onTouch(View v, MotionEvent e) {

        switch (e.getAction()) {
            case MotionEvent.ACTION_DOWN:

                View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(v);
                v.startDrag(null, shadowBuilder, v, 0);
                return true;
        }

        return false;

    }

    @Override
    public boolean onDrag(View mainView, DragEvent e) {
        View view = (View) e.getLocalState();
        switch (e.getAction()) {
            case DragEvent.ACTION_DROP:
                view.setX(e.getX() - (view.getWidth() / 2));
                view.setY(e.getY() - (view.getHeight() / 2));
                view.invalidate();
                mainView.invalidate();
                return true;
            case DragEvent.ACTION_DRAG_STARTED:
                return true;

            case DragEvent.ACTION_DRAG_EXITED:
                break;

            case DragEvent.ACTION_DRAG_ENDED:
                mainView.invalidate();
                return true;

            default:


                break;
        }

        return true;
    }

答案 1 :(得分:0)

尝试使用此代码进行拖放操作,您可以参考此link,它可以使用它。

    // Create a string for the ImageView label
private static final String IMAGEVIEW_TAG = "icon bitmap"

// Creates a new ImageView
ImageView imageView = new ImageView(this);

// Sets the bitmap for the ImageView from an icon bit map (defined elsewhere)
imageView.setImageBitmap(mIconBitmap);

// Sets the tag
imageView.setTag(IMAGEVIEW_TAG);

    ...

// Sets a long click listener for the ImageView using an anonymous listener object that
// implements the OnLongClickListener interface
imageView.setOnLongClickListener(new View.OnLongClickListener() {

    // Defines the one method for the interface, which is called when the View is long-clicked
    public boolean onLongClick(View v) {

    // Create a new ClipData.
    // This is done in two steps to provide clarity. The convenience method
    // ClipData.newPlainText() can create a plain text ClipData in one step.

    // Create a new ClipData.Item from the ImageView object's tag
    ClipData.Item item = new ClipData.Item(v.getTag());

    // Create a new ClipData using the tag as a label, the plain text MIME type, and
    // the already-created item. This will create a new ClipDescription object within the
    // ClipData, and set its MIME type entry to "text/plain"
    ClipData dragData = new ClipData(v.getTag(),ClipData.MIMETYPE_TEXT_PLAIN,item);

    // Instantiates the drag shadow builder.
    View.DragShadowBuilder myShadow = new MyDragShadowBuilder(imageView);

    // Starts the drag

            v.startDrag(dragData,  // the data to be dragged
                        myShadow,  // the drag shadow builder
                        null,      // no need to use local data
                        0          // flags (not currently used, set to 0)
            );

    }
}

自定义阴影构建器

 private static class MyDragShadowBuilder extends View.DragShadowBuilder {

    // The drag shadow image, defined as a drawable thing
    private static Drawable shadow;

        // Defines the constructor for myDragShadowBuilder
        public MyDragShadowBuilder(View v) {

            // Stores the View parameter passed to myDragShadowBuilder.
            super(v);

            // Creates a draggable image that will fill the Canvas provided by the system.
            shadow = new ColorDrawable(Color.LTGRAY);
        }

        // Defines a callback that sends the drag shadow dimensions and touch point back to the
        // system.
        @Override
        public void onProvideShadowMetrics (Point size, Point touch)
            // Defines local variables
            private int width, height;

            // Sets the width of the shadow to half the width of the original View
            width = getView().getWidth() / 2;

            // Sets the height of the shadow to half the height of the original View
            height = getView().getHeight() / 2;

            // The drag shadow is a ColorDrawable. This sets its dimensions to be the same as the
            // Canvas that the system will provide. As a result, the drag shadow will fill the
            // Canvas.
            shadow.setBounds(0, 0, width, height);

            // Sets the size parameter's width and height values. These get back to the system
            // through the size parameter.
            size.set(width, height);

            // Sets the touch point's position to be in the middle of the drag shadow
            touch.set(width / 2, height / 2);
        }

        // Defines a callback that draws the drag shadow in a Canvas that the system constructs
        // from the dimensions passed in onProvideShadowMetrics().
        @Override
        public void onDrawShadow(Canvas canvas) {

            // Draws the ColorDrawable in the Canvas passed in from the system.
            shadow.draw(canvas);
        }
    }

拖动事件侦听器

// Creates a new drag event listener
mDragListen = new myDragEventListener();

View imageView = new ImageView(this);

// Sets the drag event listener for the View
imageView.setOnDragListener(mDragListen);

...

protected class myDragEventListener implements View.OnDragListener {

    // This is the method that the system calls when it dispatches a drag event to the
    // listener.
    public boolean onDrag(View v, DragEvent event) {

        // Defines a variable to store the action type for the incoming event
        final int action = event.getAction();

        // Handles each of the expected events
        switch(action) {

            case DragEvent.ACTION_DRAG_STARTED:

                // Determines if this View can accept the dragged data
                if (event.getClipDescription().hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)) {

                    // As an example of what your application might do,
                    // applies a blue color tint to the View to indicate that it can accept
                    // data.
                    v.setColorFilter(Color.BLUE);

                    // Invalidate the view to force a redraw in the new tint
                    v.invalidate();

                    // returns true to indicate that the View can accept the dragged data.
                    return true;

                }

                // Returns false. During the current drag and drop operation, this View will
                // not receive events again until ACTION_DRAG_ENDED is sent.
                return false;

            case DragEvent.ACTION_DRAG_ENTERED:

                // Applies a green tint to the View. Return true; the return value is ignored.

                v.setColorFilter(Color.GREEN);

                // Invalidate the view to force a redraw in the new tint
                v.invalidate();

                return true;

            case DragEvent.ACTION_DRAG_LOCATION:

                // Ignore the event
                return true;

            case DragEvent.ACTION_DRAG_EXITED:

                // Re-sets the color tint to blue. Returns true; the return value is ignored.
                v.setColorFilter(Color.BLUE);

                // Invalidate the view to force a redraw in the new tint
                v.invalidate();

                return true;

            case DragEvent.ACTION_DROP:

                // Gets the item containing the dragged data
                ClipData.Item item = event.getClipData().getItemAt(0);

                // Gets the text data from the item.
                dragData = item.getText();

                // Displays a message containing the dragged data.
                Toast.makeText(this, "Dragged data is " + dragData, Toast.LENGTH_LONG);

                // Turns off any color tints
                v.clearColorFilter();

                // Invalidates the view to force a redraw
                v.invalidate();

                // Returns true. DragEvent.getResult() will return true.
                return true;

            case DragEvent.ACTION_DRAG_ENDED:

                // Turns off any color tinting
                v.clearColorFilter();

                // Invalidates the view to force a redraw
                v.invalidate();

                // Does a getResult(), and displays what happened.
                if (event.getResult()) {
                    Toast.makeText(this, "The drop was handled.", Toast.LENGTH_LONG);

                } else {
                    Toast.makeText(this, "The drop didn't work.", Toast.LENGTH_LONG);

                }

                // returns true; the value is ignored.
                return true;

            // An unknown action type was received.
            default:
                Log.e("DragDrop Example","Unknown action type received by OnDragListener.");
                break;
        }

        return false;
    }
};

答案 2 :(得分:0)

将DragEvent.ACTION_DROP案例更改为以下

    case DragEvent.ACTION_DROP:
    RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
            LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
    params.setMargins(e.getX(), e.getY(), 0, 0);
    break;

您可以直接复制粘贴上面的代码。

答案 3 :(得分:0)

这是一个按钮,但适用于所有视图。我的按钮位于RelativeLayout中,如果您的视图位于LinearLayout中,则必须改为创建LinearLayout.LayoutParams

代码:

addBtn.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            if (motionEvent.getAction() == MotionEvent.ACTION_MOVE  ){
                RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(view.getLayoutParams().width, view.getLayoutParams().height);
                params.setMargins(
                        (int) (motionEvent.getRawX() - view.getWidth()/2), // margin left
                        (int) (motionEvent.getRawY() - (view.getHeight()/2)), // margin top
                        (int) (params.width - (motionEvent.getRawX() + view.getWidth()/2)), // margin right
                        (int) (params.height - (motionEvent.getRawY() - (view.getHeight()/2))) // margin bottom
                );
                view.setLayoutParams(params);
            }
            return true;
        }
    });