android可拖拽item的ListView--DragListVie

來源:互聯網
上載者:User

標籤:

本部落格原創,轉載請標明 原文出處:http://blog.csdn.net/sql26/article/details/52252644

 

1.概述

在android項目開發中,需求對ListView中的商品item進行拖拽重新排序,網上看了一些文章做的效果不錯,就是代碼不開源唯寫了思路,要麼代碼沒注釋,還不如自己寫一個。。

 

2.:



3.原理:

1.在touch事件裡面通過ListView的pointToPosition(x, y)方法拿到當前點擊的item的position;


2.根據當前點擊的x,y判斷是否點是的拖拽觸發按鈕;


3.擷取點擊的條目視圖,itemView = ListView.getChildAt(dragEndPosition - getFirstVisiblePosition());


4.通過itemView.setDrawingCacheEnabled(true);  Bitmap.createBitmap(itemView.getDrawingCache())拷貝當前view為bigtmap;


5.通過WindowManager來把這個bitmap展示出來,可以用windowParams = WindowManager.LayoutParams();  windowManager.addView(imageView, windowParams);來設定itemView的位置,大小;


6.在onTouchEvent中的滑動事件MotionEvent.ACTION_MOVE中即時更改windowParams的Y值,並且更新視圖windowManager.updateViewLayout(dragImageView, windowParams);


7.即時切換移動中相鄰2個item的資料;


8.監聽touch事件中MotionEvent.ACTION_UP行為,為拖拽結束訊號,調用WindowManager.removeView(View view)來銷毀建立的懸浮View;由於第7步的原因,起始拖拽的item的資料已經移動到當前position,看起來的效果就像是拖過來的;

注意:並不是真的把item的視圖進行切換,而是轉移了他們的資料而已,懸浮view只是一種互動形式。過程中資料的交換,類似冒泡排序


4.代碼

DragListView:

package com.lunge.dragablelistview;import android.content.Context;import android.graphics.Bitmap;import android.graphics.Color;import android.util.AttributeSet;import android.util.Log;import android.view.Gravity;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.view.WindowManager;import android.widget.AdapterView;import android.widget.ImageView;import android.widget.ListView;/** * Created by Lunger on 8/17 2016 11:21 */public class DragListView extends ListView {    private WindowManager windowManager;// windows視窗控制類    private WindowManager.LayoutParams windowParams;// 用於控制拖拽項的顯示的參數    private ImageView dragImageView;// 被拖拽的項(item),其實就是一個ImageView    private int dragbeginPosition;// 手指拖動項原始position    private int dragEndPosition;// 手指點擊準備拖動的時候,當前拖動項在列表中的位置.    private int dragPoint;// 在當前資料項目中的位置    private int dragYOffset;// 當前視圖和螢幕的距離(這裡只使用了y方向上)    private int upScrollBounce;// 拖動的時候,開始向上滾動的邊界    private int downScrollBounce;// 拖動的時候,開始向下滾動的邊界    private final static int step = 1;// ListView 滑動步伐.    private int current_Step;// 當前步伐.    private int temChangId;// 臨時交換id    private boolean isLock;// 是否上鎖.    private MyDragListener mMyDragListener;    /**     * @param isLock 拖拽功能的開關,true為關閉     */    public void setLock(boolean isLock) {        this.isLock = isLock;    }    public DragListView(Context context, AttributeSet attrs) {        super(context, attrs);    }    /***     * touch事件攔截 在這裡我進行相應攔截,     */    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        // 按下        if (ev.getAction() == MotionEvent.ACTION_DOWN && !isLock) {            int x = (int) ev.getX();// 擷取相對與ListView的x座標            int y = (int) ev.getY();// 擷取相應與ListView的y座標            temChangId = dragbeginPosition = dragEndPosition = pointToPosition(x, y);            // 無效不進行處理            if (dragEndPosition == AdapterView.INVALID_POSITION) {                return super.onInterceptTouchEvent(ev);            }            // 擷取當前位置的item視圖(可見狀態)            ViewGroup itemView = (ViewGroup) getChildAt(dragEndPosition                    - getFirstVisiblePosition());            // 擷取到的dragPoint其實就是在你點擊指定item項中的高度.            dragPoint = y - itemView.getTop();            // 這個值是固定的:其實就是ListView這個控制項與螢幕最頂部的距離(一般為標題列+狀態列.            dragYOffset = (int) (ev.getRawY() - y);            // 擷取可拖拽的表徵圖            View dragger = itemView.findViewById(R.id.iv_move);            //點擊的x座標大於移動按鈕的x座標,就當成是按到了iv_move觸發了移動            if (dragger != null && x > dragger.getLeft()) { //如果想點擊item的任意位置都能進行拖拽,把x > dragger.getLeft()限定去掉就行                upScrollBounce = getHeight() / 3;// 取得向上滾動的邊際,大概為該控制項的1/3                downScrollBounce = getHeight() * 2 / 3;// 取得向下滾動的邊際,大概為該控制項的2/3                itemView.setBackgroundColor(Color.parseColor("#a35151"));                itemView.setDrawingCacheEnabled(true);// 開啟cache.                Bitmap bm = Bitmap.createBitmap(itemView.getDrawingCache());// 根據cache建立一個新的bitmap對象,就是你拖著狂奔的對象                startDrag(bm, y);// 初始化影像            }            return false;        }        return super.onInterceptTouchEvent(ev);    }    /**     * 觸摸事件處理     */    @Override    public boolean onTouchEvent(MotionEvent ev) {        // item的view不為空白,且擷取的dragPosition有效        if (dragImageView != null && dragEndPosition != INVALID_POSITION                && !isLock) {            int action = ev.getAction();            switch (action) {                case MotionEvent.ACTION_UP:                    int upY = (int) ev.getY();                    stopDrag();                    onDrop(upY);                    break;                case MotionEvent.ACTION_MOVE:                    int moveY = (int) ev.getY();                    onDrag(moveY);                    break;                case MotionEvent.ACTION_DOWN:                    break;                default:                    break;            }            return true;// 取消ListView滑動.        }        return super.onTouchEvent(ev);    }    /**     * 準備拖動,初始化拖動項的映像     *     * @param bm     * @param y     */    private void startDrag(Bitmap bm, int y) {        /***         * 初始化window.         */        windowParams = new WindowManager.LayoutParams();        windowParams.gravity = Gravity.TOP;        windowParams.x = 0;        windowParams.y = y - dragPoint + dragYOffset;        windowParams.width = WindowManager.LayoutParams.WRAP_CONTENT;        windowParams.height = WindowManager.LayoutParams.WRAP_CONTENT;        windowParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE// 不需擷取焦點                | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE// 不需接受觸摸事件                | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON// 保持裝置常開,並保持亮度不變。                | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;        // 視窗佔滿整個螢幕,忽略周圍的裝飾邊框(例如狀態列)。此視窗需考慮到裝飾邊框的內容。        ImageView imageView = new ImageView(getContext());        imageView.setImageBitmap(bm);        windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);        windowManager.addView(imageView, windowParams);        dragImageView = imageView;    }    /**     * 拖動執行,在Move方法中執行     *     * @param y     */    public void onDrag(int y) {        int drag_top = y - dragPoint;// 拖拽view的top值不能<0,否則則出界.        if (dragImageView != null && drag_top >= 0) {            windowParams.alpha = 0.65f;            windowParams.y = y - dragPoint + dragYOffset;            windowManager.updateViewLayout(dragImageView, windowParams);// 時時移動(拖拽移動的核心)        }        // 為了避免滑動到分割線的時候,返回-1的問題        int tempPosition = pointToPosition(0, y);        if (tempPosition != INVALID_POSITION) {            dragEndPosition = tempPosition;        }        onChange(y);// 時時交換        doScroller(y);// listview移動.    }    /***     * ListView的移動.     * 要明白移動原理:當我移動到下端的時候,ListView向上滑動,當我移動到上端的時候,ListView要向下滑動。     * 正好和實際的相反.     */    public void doScroller(int y) {        // ListView需要下滑        if (y < upScrollBounce) {            current_Step = step + (upScrollBounce - y) / 10;// 時時步伐        }// ListView需要上滑        else if (y > downScrollBounce) {            current_Step = -(step + (y - downScrollBounce)) / 10;// 時時步伐        } else {            current_Step = 0;        }        // 擷取你拖拽滑動到位置及顯示item相應的view上(註:可顯示部分)(position)        View view = getChildAt(dragEndPosition - getFirstVisiblePosition());        // 真正滾動的方法setSelectionFromTop()        if (view != null)            setSelectionFromTop(dragEndPosition, view.getTop() + current_Step);    }    /**     * 停止拖動,刪除影像     */    public void stopDrag() {        if (dragImageView != null) {            windowManager.removeView(dragImageView);            dragImageView = null;        }    }    /***     * 拖動時時change     */    private void onChange(int y) {        // 資料交換        if (dragEndPosition < getAdapter().getCount()) {            DragListAdapter adapter = (DragListAdapter) getAdapter();            if (dragEndPosition != temChangId) {                adapter.update(temChangId, dragEndPosition);                temChangId = dragEndPosition;// 將點擊最初所在位置position付給臨時的,用於判斷是否換位.            }        }        // 為了避免滑動到分割線的時候,返回-1的問題        int tempPosition = pointToPosition(0, y);        if (tempPosition != INVALID_POSITION) {            dragEndPosition = tempPosition;        }        // 超出邊界處理(如果向上超過第二項Top的話,那麼就放置在第一個位置)        if (y < getChildAt(0).getTop()) {            // 超出上邊界            dragEndPosition = 0;            // 如果拖動超過最後一項的最下邊那麼就防止在最下邊        } else if (y > getChildAt(getChildCount() - 1).getBottom()) {            // 超出下邊界            dragEndPosition = getAdapter().getCount() - 1;        }    }    /**     * 拖動放下的時候     *     * @param y     */    public void onDrop(int y) {        // 資料交換        if (dragEndPosition < getAdapter().getCount()) {            DragListAdapter adapter = (DragListAdapter) getAdapter();            adapter.notifyDataSetChanged();// 重新整理.            Log.d("wbl", "dragEndPosition :" + dragEndPosition);            Log.d("wbl", "dragbeginPosition :" + dragbeginPosition);            //換位成功後的回調            if (mMyDragListener != null) {                mMyDragListener.onDragFinish(dragbeginPosition, dragEndPosition);            }        }    }    //換位成功後的回調介面    interface MyDragListener {        void onDragFinish(int srcPositon, int finalPosition);    }    //設定換位成功後的回調介面    public void setMyDragListener(MyDragListener listener) {        mMyDragListener = listener;    }}


DragListAdapter:

package com.lunge.dragablelistview;import android.content.Context;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.TextView;import java.util.ArrayList;/** * Created by Lunger on 8/17 2016 11:21 */class DragListAdapter extends BaseAdapter {    private ArrayList<String> mDatas;    private Context context;    public DragListAdapter(Context context, ArrayList<String> arrayTitles) {        this.context = context;        this.mDatas = arrayTitles;    }    @Override    public View getView(final int position, View convertView, ViewGroup parent) {        View view;        /***         * 在這裡儘可能每次都進行執行個體化新的,這樣在拖拽ListView的時候不會出現錯亂.         * 具體原因不明,不過這樣經過測試,目前沒有發現錯亂。雖說效率不高,但是做拖拽LisView足夠了。         */        view = LayoutInflater.from(context).inflate(                R.layout.drag_list_item, null);        TextView textView = (TextView) view                .findViewById(R.id.tv_name);        textView.setText(mDatas.get(position));        return view;    }    /***     * 動態修改ListVIiw的方位.(資料移位)     *     * @param start 點擊移動的position     * @param end   鬆開時候的position     */    public void update(int start, int end) {        String data = mDatas.get(start);        mDatas.remove(start);// 刪除該項        mDatas.add(end, data);// 添加刪除項        notifyDataSetChanged();// 重新整理ListView    }    @Override    public int getCount() {        return mDatas.size();    }    @Override    public Object getItem(int position) {        return mDatas.get(position);    }    @Override    public long getItemId(int position) {        return position;    }}


item布局:

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"                android:layout_width="match_parent"                android:layout_height="match_parent">    <TextView        android:id="@+id/tv_name"        android:layout_width="300px"        android:layout_height="100px"        android:layout_centerVertical="true"        android:gravity="center"        android:text="Your infomation"        android:textSize="25px"/>    <ImageView        android:id="@+id/iv_move"        android:layout_width="53px"        android:layout_height="75px"        android:layout_alignParentRight="true"        android:layout_centerVertical="true"        android:layout_marginRight="20px"        android:src="@mipmap/ic_launcher"/></RelativeLayout>


MainActivity:

package com.lunge.dragablelistview;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.widget.Toast;import java.util.ArrayList;/** * Created by Lunger on 8/17 2016 11:21*/public class MainActivity extends AppCompatActivity {    private DragListView mLv;    private ArrayList<String> mDatas;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mLv = (DragListView) findViewById(R.id.lv);        mDatas = new ArrayList<>();        for (int i = 0; i < 50; i++) {            mDatas.add("Monster kill " + i);        }        mLv.setAdapter(new DragListAdapter(this, mDatas));        mLv.setMyDragListener(new DragListView.MyDragListener() {            @Override            public void onDragFinish(int srcPositon, int finalPosition) {                Toast.makeText(MainActivity.this, "beginPoisiton : " + srcPositon + "...endPosition : " + finalPosition, Toast.LENGTH_LONG).show();            }        });    }}


main布局:

<?xml version="1.0" encoding="utf-8"?><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:paddingBottom="@dimen/activity_vertical_margin"    android:paddingLeft="@dimen/activity_horizontal_margin"    android:paddingRight="@dimen/activity_horizontal_margin"    android:paddingTop="@dimen/activity_vertical_margin"    tools:context="com.lunge.dragablelistview.MainActivity">    <com.lunge.dragablelistview.DragListView        android:id="@+id/lv"        android:layout_width="wrap_content"        android:layout_height="match_parent"        /></RelativeLayout>



android可拖拽item的ListView--DragListVie

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.