【问题标题】:Drag and Drop for imageview not working拖放图像视图不起作用
【发布时间】:2015-02-16 02:36:48
【问题描述】:

我的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

我真的尝试了很多。

【问题讨论】:

  • 最好使用MotionEvent 而不是DragEvent。我做了同样的here

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


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    试试这个代码拖放,你可以参考这个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;
        }
    };
    

    【讨论】:

    • 谢谢。我会试试这个。我想知道我哪里出错了。我只是找不到我的代码的问题。
    • 我无法在您的 xml 中看到两种不同的拖放布局。而且我认为您通过在运行时在侦听器的丢弃标志上添加控件来做错事。
    • 我想在同一个布局中拖放。我该怎么做?。
    • 我分享的代码是针对同一布局中的元素的。
    【解决方案3】:

    将您的 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;
    

    就是这样,你可以直接复制粘贴上面的代码。

    【讨论】:

      【解决方案4】:

      这是一个按钮,但适用于所有视图。我的按钮位于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;
              }
          });
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-08-07
        • 2022-11-03
        • 2011-11-02
        • 1970-01-01
        相关资源
        最近更新 更多