Android拖放功能

时间:2013-09-10 17:46:01

标签: android drag-and-drop

有没有办法在API 8 Android中实现拖放功能?

查看here,但它出现在API 11之后。

我需要将视图从一个LinearLayout拖到另一个{{1}}。我可以在API 8上实现这个吗?

2 个答案:

答案 0 :(得分:2)

试试这个

import android.app.Activity;
import android.content.ClipData;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Bundle;
import android.view.DragEvent;
import android.view.View;
import android.view.View.DragShadowBuilder;
import android.view.View.OnDragListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;

public class MainActivity extends Activity {

ListView source = null;
TextView target1 = null;
TextView target2 = null;
TextView target3 = null;

String[] listItems = {"Samsung", "Apple", "Google", "Nokia"};

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    source = (ListView)findViewById(R.id.dragSource);
    target1 = (TextView) findViewById(R.id.dragTarget1);
    target2 = (TextView) findViewById(R.id.dragTarget2);
    target3 = (TextView) findViewById(R.id.dragTarget3);

    ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, listItems);
    source.setAdapter(adapter);

    // Start Drag
    source.setOnItemClickListener(new OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position,
                long id) {
            String item = listItems[position];

            ClipData data = ClipData.newPlainText("DragIt", item);
            source.startDrag(data, new MyShadowBuilder(view), null, 0);
        }
    });

    // Handle Drag
    target1.setOnDragListener(new MyDragListener());
    target2.setOnDragListener(new MyDragListener());
    target3.setOnDragListener(new MyDragListener());
}

// Drag Shadow
private class MyShadowBuilder extends DragShadowBuilder {

    public MyShadowBuilder(View v) {
        super(v);
    }

    @Override
    public void onDrawShadow(Canvas canvas) {
        // Set Drag image background or anything you want
        int width = getView().getWidth();
        int height = getView().getHeight();
        Paint paint = new Paint();
        paint.setColor(0x55858585);

        canvas.drawRect(new Rect(0, 0, width, height), paint);

        super.onDrawShadow(canvas);
    }

    @Override
    public void onProvideShadowMetrics(Point shadowSize,
            Point shadowTouchPoint) {

        int width = getView().getWidth();
        int height = getView().getHeight();

        shadowSize.set(width, height);

        shadowTouchPoint.set(width/2, height);
    }
}

// Drag Listener
private class MyDragListener implements OnDragListener {
    private final int DEFAULT_BG_COLOR = 0xFF858585;
    private final int HIGHLIGHT_BG_COLOR = 0xFF0000FF;

    @Override
    public boolean onDrag(View v, DragEvent event) {

        if(event.getAction() == DragEvent.ACTION_DRAG_ENTERED) {
            v.setBackgroundColor(HIGHLIGHT_BG_COLOR);
        }
        else if(event.getAction() == DragEvent.ACTION_DRAG_EXITED) {
            v.setBackgroundColor(DEFAULT_BG_COLOR);
        }
        else if(event.getAction() == DragEvent.ACTION_DROP) {
            // Perform drop
            ClipData clip = event.getClipData();
            ClipData.Item item = clip.getItemAt(0);
            String text = item.getText().toString();

            ((TextView) v).setText(text);
            v.setBackgroundColor(DEFAULT_BG_COLOR);
        }
        // Send true to listen All Drag Events.
        return true; 
    }
}
}

XML就像:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal" >

<LinearLayout
    android:layout_width="161dp"
    android:layout_height="fill_parent"
    android:background="#FF858585"
    android:orientation="vertical" >


    <TextView
        android:id="@+id/dragTarget1"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_weight="0.04"
        android:text="Drop Here"
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <TextView
        android:id="@+id/dragTarget2"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_weight="0.04"
        android:text="Drop Here"
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <TextView
        android:id="@+id/dragTarget3"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_weight="0.04"
        android:text="Drop Here"
        android:textAppearance="?android:attr/textAppearanceLarge" />
</LinearLayout>

<LinearLayout
    android:layout_width="wrap_content"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <ListView
        android:id="@+id/dragSource"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >
    </ListView>

</LinearLayout>

答案 1 :(得分:1)

使用WindowManager尝试另一种方法:

    package com.example.cooldraganddrop;

    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.Color;
    import android.graphics.PixelFormat;
    import android.graphics.drawable.BitmapDrawable;

    import android.util.AttributeSet;
    import android.view.Gravity;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.WindowManager;
    import android.widget.AdapterView;
    import android.widget.ImageView;

    public class CoolDragAndDropGridView extends SpanVariableGridView implements `View.OnTouchListener {`

        private static final int ITEM_HOVER_DELAY = 450;

        private int mDragPointX;
        private int mDragPointY;
        private int mDragOffsetX;
        private int mDragOffsetY;
        private int mDragPosition = AdapterView.INVALID_POSITION;
        private int mDropPosition = AdapterView.INVALID_POSITION;
        private int mCurrentPosition = AdapterView.INVALID_POSITION;
        private Runnable mDelayedOnDragRunnable = null;

        ScrollingStrategy mScrollingStrategy = null;
        WindowManager mWindowManager = null;
        WindowManager.LayoutParams mWindowParams = null;
        private ImageView mDragImageView = null;
        private boolean mDragAndDropStarted = false;
        private DragAndDropListener mDragAndDropListener = null;
        private OnTrackTouchEventsListener mOnTrackTouchEventsListener = null;

        public static interface OnTrackTouchEventsListener {

                void trackTouchEvents(final MotionEvent motionEvent);

        };

        public static interface DragAndDropListener {

                void onDragItem(int from);

                void onDraggingItem(int from, int to);

                void onDropItem(int from, int to);

                boolean isDragAndDropEnabled(int position);
        }

        public CoolDragAndDropGridView(Context context) {
                super(context);

                initialize();
        }

        public CoolDragAndDropGridView(Context context, AttributeSet attrs, int defStyle) {
                super(context, attrs, defStyle);

                initialize();
        }

        public CoolDragAndDropGridView(Context context, AttributeSet attrs) {
                super(context, attrs);

                initialize();
        }

        private void initialize() {
                setOnTouchListener(this);
                setChildrenDrawingOrderEnabled(true);
        }

        public void startDragAndDrop() {

                mDragAndDropStarted = true;

        }

        public void setDragAndDropListener(DragAndDropListener dragAndDropListener) {

                mDragAndDropListener = dragAndDropListener;

        }

        private void destroyDragImageView() {

                if (mDragImageView != null) {

                        mWindowManager.removeView(mDragImageView);

                        BitmapDrawable bitmapDrawable = (BitmapDrawable) mDragImageView.getDrawable();
                        if (bitmapDrawable != null) {
                                final Bitmap bitmap = bitmapDrawable.getBitmap();
                                if (bitmap != null && !bitmap.isRecycled()) {
                                        bitmap.recycle();
                                }
                        }

                        mDragImageView.setImageDrawable(null);
                        mDragImageView = null;
                }

        }

        private ImageView createDragImageView(final View v, final int x, final int y) {

                v.destroyDrawingCache();
                v.setDrawingCacheEnabled(true);
                Bitmap bm = Bitmap.createBitmap(v.getDrawingCache());

                mDragPointX = x - v.getLeft();
                mDragPointY = y - v.getTop();

                mWindowParams = new WindowManager.LayoutParams();
                mWindowParams.gravity = Gravity.TOP | Gravity.LEFT;

                mWindowParams.x = x - mDragPointX + mDragOffsetX;
                mWindowParams.y = y - mDragPointY + mDragOffsetY;

                mWindowParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
                mWindowParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
                mWindowParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
                                | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;

                mWindowParams.format = PixelFormat.TRANSLUCENT;
                mWindowParams.alpha = 0.7f;
                mWindowParams.windowAnimations = 0;

                ImageView iv = new ImageView(getContext());
                iv.setBackgroundColor(Color.parseColor("#ff555555"));
                iv.setImageBitmap(bm);

                mWindowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);// "window"
                mWindowManager.addView(iv, mWindowParams);
                return iv;

        }

        private void startDrag(final int x, final int y) {

                final View v = getChildAt(mDragPosition);

                destroyDragImageView();

                mDragImageView = createDragImageView(v, x, y);
                v.setVisibility(View.INVISIBLE);

                if (mDragAndDropListener != null) {

                        mDragAndDropListener.onDragItem(mDragPosition);
                }

        }

        @Override
        protected int getChildDrawingOrder(int childCount, int i) {
                if (mCurrentPosition == -1)
                        return i;
                else if (i == childCount - 1)
                        return mCurrentPosition;
                else if (i >= mCurrentPosition)
                        return i + 1;
                return i;
        }

        private void onDrop() {

                destroyDragImageView();

                removeCallbacks(mDelayedOnDragRunnable);

                View v = getChildAt(mDropPosition);
                v.setVisibility(View.VISIBLE);

                v.clearAnimation();

                if (mDragAndDropListener != null && mDropPosition != AdapterView.INVALID_POSITION) {

                        mDragAndDropListener.onDropItem(mDragPosition, mDropPosition);
                }

                mDragPosition = mDropPosition = mCurrentPosition = AdapterView.INVALID_POSITION;
                mDragAndDropStarted = false;
        }

        public void setScrollingStrategy(ScrollingStrategy scrollingStrategy) {

                mScrollingStrategy = scrollingStrategy;

        }

        private void onDrag(final int x, final int y) {

                if (mScrollingStrategy != null && mScrollingStrategy.performScrolling(x, y, this)) {

                        removeCallbacks(mDelayedOnDragRunnable);

                        return;
                }

                final int tempDropPosition = pointToPosition(mCurrentPosition, x, y);

                if (mDragAndDropListener != null && mDropPosition != tempDropPosition && tempDropPosition != AdapterView.INVALID_POSITION) {

                        removeCallbacks(mDelayedOnDragRunnable);

                        if (mDragAndDropListener.isDragAndDropEnabled(tempDropPosition)) {

                                mDropPosition = tempDropPosition;

                                mDelayedOnDragRunnable = new Runnable() {

                                        @Override
                                        public void run() {

                                                mDragAndDropListener.onDraggingItem(mCurrentPosition, tempDropPosition);
                                                performDragAndDropSwapping(mCurrentPosition, tempDropPosition);

                                                final int nextDropPosition = pointToPosition(tempDropPosition, x, y);

                                                if (nextDropPosition == AdapterView.INVALID_POSITION) {

                                                        mCurrentPosition = mDropPosition = tempDropPosition;

                                                }
                                        }
                                };

                                postDelayed(mDelayedOnDragRunnable, ITEM_HOVER_DELAY);

                        } else {

                                mDropPosition = mDragPosition;

                        }

                }

                if (mDragImageView != null) {

                        mWindowParams.x = x - mDragPointX + mDragOffsetX;
                        mWindowParams.y = y - mDragPointY + mDragOffsetY;
                        mWindowManager.updateViewLayout(mDragImageView, mWindowParams);
                }

        }

        public void setOnTrackTouchEventListener(OnTrackTouchEventsListener onTrackTouchEventsListener) {

                mOnTrackTouchEventsListener = onTrackTouchEventsListener;
        }

        @Override
        public boolean onInterceptTouchEvent(MotionEvent event) {

                if (mOnTrackTouchEventsListener != null) {
                        mOnTrackTouchEventsListener.trackTouchEvents(event);
                }

                switch (event.getAction()) {

                case MotionEvent.ACTION_DOWN:
                case MotionEvent.ACTION_MOVE:

                        if (mDragAndDropListener != null && mDragAndDropStarted) {

                                mDragAndDropStarted = false;

                                getParent().requestDisallowInterceptTouchEvent(true);

                                return launchDragAndDrop(event);
                        }

                        break;

                default:
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_CANCEL:

                        mDragAndDropStarted = false;

                        getParent().requestDisallowInterceptTouchEvent(false);

                        break;
                }

                return super.onInterceptTouchEvent(event);
        }

        private boolean launchDragAndDrop(final MotionEvent event) {

                final int x = (int) event.getX();
                final int y = (int) event.getY();

                mCurrentPosition = mDragPosition = mDropPosition = pointToPosition(mDragPosition, x, y);

                if (mDragPosition != AdapterView.INVALID_POSITION && mDragAndDropListener.isDragAndDropEnabled(mDragPosition)) {

                        mDragOffsetX = (int) (event.getRawX() - x);
                        mDragOffsetY = (int) (event.getRawY() - y);

                        startDrag(x, y);

                        return true;
                }

                return false;
        }

        @Override
        public boolean onTouch(View view, MotionEvent event) {

                if (mDragPosition != AdapterView.INVALID_POSITION && mDragImageView != null) {

                        final int x = (int) event.getX();
                        final int y = (int) event.getY();

                        switch (event.getAction()) {

                        case MotionEvent.ACTION_MOVE:

                                mDragOffsetX = (int) (event.getRawX() - x);
                                mDragOffsetY = (int) (event.getRawY() - y);

                                onDrag(x, y);

                                break;

                        case MotionEvent.ACTION_UP:
                        case MotionEvent.ACTION_CANCEL:

                                onDrop();

                                resetLongClickTransition();

                                getParent().requestDisallowInterceptTouchEvent(false);

                                return false;

                        default:

                        }

                        return true;
                }

                return false;
        }
}

使用这种拖放方法的示例是here