【问题标题】:Android Drag and Drop functionalityAndroid 拖放功能
【发布时间】:2013-09-10 17:46:00
【问题描述】:

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

看了here,但是出现在API 11之后。

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

【问题讨论】:

    标签: android drag-and-drop


    【解决方案1】:

    这样试试

    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>
    

    【讨论】:

    • 如何使用此代码将 ImageView 从一个 LinearLayout 拖到另一个? View.OnDragListener 也首次出现在 API11 中,它适用于 API8 吗?
    【解决方案2】:

    使用 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

    【讨论】:

    • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接的答案可能会失效。
    猜你喜欢
    • 2011-11-10
    • 2012-04-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-14
    • 2019-11-19
    • 1970-01-01
    相关资源
    最近更新 更多