zoukankan      html  css  js  c++  java
  • listview 拖动item效果实现

    listview 拖动item效果实现

    效果图如下:

    拖拽前:


    拖拽后:



    首先参考源码中:TouchInterceptor 类,该类会在下面给出:

    第一步:主类:

    /**
     * 
     */
    package com.example.draglistview;


    /**
     * @author JiaRH
     *
     * @date 2013-12-17 上午10:01:17
     */
    import java.util.Arrays;


    import android.app.ListActivity;


    import android.os.Bundle;


    import android.view.View;


    import android.widget.ArrayAdapter;
    import android.widget.BaseAdapter;


    import android.widget.ListView;


    import android.widget.Toast;


    public class SortableListViewActivity extends ListActivity {


    private TouchInterceptor mList;
    private Object[] sArray = { "1", "2", "3", 4, 5,
    "6", "7" };




    @Override
    public void onCreate(Bundle savedInstanceState) {


    super.onCreate(savedInstanceState);


    setContentView(R.layout.activity_main);


    @SuppressWarnings({ "unchecked", "rawtypes" })
    ArrayAdapter adp = new ArrayAdapter(this, R.layout.list_layout, sArray);


    setListAdapter(adp);
    mList = (TouchInterceptor) getListView();
    mList.setDropListener(mDropListener);


    registerForContextMenu(mList);


    }


    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {


    String selection = sArray[position].toString();


    Toast.makeText(this, selection, Toast.LENGTH_LONG).show();


    }


    private TouchInterceptor.DropListener mDropListener =


    new TouchInterceptor.DropListener() {


    public void drop(int from, int to) {


    System.out.println("Droplisten from:" + from + " to:" + to);


    // Assuming that item is moved up the list


    int direction = -1;


    int loop_start = from;


    int loop_end = to;


    // For instance where the item is dragged down the list


    if (from < to) {


    direction = 1;


    }


    Object target = sArray[from];


    for (int i = loop_start; i != loop_end; i = i + direction) {


    sArray[i] = sArray[i + direction];


    }


    sArray[to] = target;


    System.out.println("Changed array is:" + Arrays.toString(sArray));


    ((BaseAdapter) mList.getAdapter()).notifyDataSetChanged();


    }


    };


    }

    第二步: 主类布局文件;

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical" >


        <com.example.draglistview.TouchInterceptor
            android:id="@android:id/list"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:drawSelectorOnTop="false"
            android:fastScrollEnabled="true"
            android:textSize="18sp" >
        </com.example.draglistview.TouchInterceptor>


    </LinearLayout>

    第三步; 引入TouchInterceptor 类,(注意:红色部分为要修改的地方)

    /*
     * Copyright (C) 2008 The Android Open Source Project
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */


    package com.example.draglistview;


    import android.content.Context;
    import android.content.SharedPreferences;
    import android.content.res.Resources;
    import android.graphics.Bitmap;
    import android.graphics.PixelFormat;
    import android.graphics.Rect;
    import android.graphics.drawable.Drawable;
    import android.graphics.drawable.LevelListDrawable;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.GestureDetector;
    import android.view.Gravity;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.ViewConfiguration;
    import android.view.ViewGroup;
    import android.view.WindowManager;
    import android.view.GestureDetector.SimpleOnGestureListener;
    import android.widget.AdapterView;
    import android.widget.ImageView;
    import android.widget.ListView;
    import android.widget.TextView;


    public class TouchInterceptor extends ListView {


    private ImageView mDragView;
    private WindowManager mWindowManager;
    private WindowManager.LayoutParams mWindowParams;
    /**
    * At which position is the item currently being dragged. Note that this
    * takes in to account header items.
    */
    private int mDragPos;
    /**
    * At which position was the item being dragged originally
    */
    private int mSrcDragPos;
    private int mDragPointX; // at what x offset inside the item did the user
    // grab it
    private int mDragPointY; // at what y offset inside the item did the user
    // grab it
    private int mXOffset; // the difference between screen coordinates and
    // coordinates in this view
    private int mYOffset; // the difference between screen coordinates and
    // coordinates in this view
    private DragListener mDragListener;
    private DropListener mDropListener;
    private RemoveListener mRemoveListener;
    private int mUpperBound;
    private int mLowerBound;
    private int mHeight;
    private GestureDetector mGestureDetector;
    private static final int FLING = 0;
    private static final int SLIDE = 1;
    private static final int TRASH = 2;
    private int mRemoveMode = -1;
    private Rect mTempRect = new Rect();
    private Bitmap mDragBitmap;
    private final int mTouchSlop;
    private int mItemHeightNormal;
    private int mItemHeightExpanded;
    private int mItemHeightHalf;
    private Drawable mTrashcan;


    public TouchInterceptor(Context context, AttributeSet attrs) {
    super(context, attrs);
    SharedPreferences pref = context.getSharedPreferences("Music", 3);
    mRemoveMode = pref.getInt("deletemode", -1);
    mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
    Resources res = getResources();
    mItemHeightNormal = res.getDimensionPixelSize(R.dimen.normal_height);
    mItemHeightHalf = mItemHeightNormal / 2;
    mItemHeightExpanded = res
    .getDimensionPixelSize(R.dimen.expanded_height);
    }


    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
    if (mRemoveListener != null && mGestureDetector == null) {
    if (mRemoveMode == FLING) {
    mGestureDetector = new GestureDetector(getContext(),
    new SimpleOnGestureListener() {
    @Override
    public boolean onFling(MotionEvent e1,
    MotionEvent e2, float velocityX,
    float velocityY) {
    if (mDragView != null) {
    if (velocityX > 1000) {
    Rect r = mTempRect;
    mDragView.getDrawingRect(r);
    if (e2.getX() > r.right * 2 / 3) {
    // fast fling right with release
    // near the right edge of the screen
    stopDragging();
    mRemoveListener.remove(mSrcDragPos);
    unExpandViews(true);
    }
    }
    // flinging while dragging should have no
    // effect
    return true;
    }
    return false;
    }
    });
    }
    }
    if (mDragListener != null || mDropListener != null) {
    switch (ev.getAction()) {
    case MotionEvent.ACTION_DOWN:
    int x = (int) ev.getX();
    int y = (int) ev.getY();
    int itemnum = pointToPosition(x, y);
    if (itemnum == AdapterView.INVALID_POSITION) {
    break;
    }
    // ViewGroup item = (ViewGroup) getChildAt(itemnum -
    // getFirstVisiblePosition());
    TextView item = (TextView) getChildAt(itemnum
    - getFirstVisiblePosition());

    mDragPointX = x - item.getLeft();
    mDragPointY = y - item.getTop();
    mXOffset = ((int) ev.getRawX()) - x;
    mYOffset = ((int) ev.getRawY()) - y;
    // The left side of the item is the grabber for dragging the
    // item
    //if (x < 64) {
    if (item.getRight() - x < 40) {

    item.setDrawingCacheEnabled(true);
    // Create a copy of the drawing cache so that it does not
    // get recycled
    // by the framework when the list tries to clean up memory
    Bitmap bitmap = Bitmap.createBitmap(item.getDrawingCache());
    startDragging(bitmap, x, y);
    mDragPos = itemnum;
    mSrcDragPos = mDragPos;
    mHeight = getHeight();
    int touchSlop = mTouchSlop;
    mUpperBound = Math.min(y - touchSlop, mHeight / 3);
    mLowerBound = Math.max(y + touchSlop, mHeight * 2 / 3);
    return false;
    }
    stopDragging();
    break;
    }
    }
    return super.onInterceptTouchEvent(ev);
    }


    /*
    * pointToPosition() doesn't consider invisible views, but we need to, so
    * implement a slightly different version.
    */
    private int myPointToPosition(int x, int y) {


    if (y < 0) {
    // when dragging off the top of the screen, calculate position
    // by going back from a visible item
    int pos = myPointToPosition(x, y + mItemHeightNormal);
    if (pos > 0) {
    return pos - 1;
    }
    }


    Rect frame = mTempRect;
    final int count = getChildCount();
    for (int i = count - 1; i >= 0; i--) {
    final View child = getChildAt(i);
    child.getHitRect(frame);
    if (frame.contains(x, y)) {
    return getFirstVisiblePosition() + i;
    }
    }
    return INVALID_POSITION;
    }


    private int getItemForPosition(int y) {
    int adjustedy = y - mDragPointY - mItemHeightHalf;
    int pos = myPointToPosition(0, adjustedy);
    if (pos >= 0) {
    if (pos <= mSrcDragPos) {
    pos += 1;
    }
    } else if (adjustedy < 0) {
    // this shouldn't happen anymore now that myPointToPosition deals
    // with this situation
    pos = 0;
    }
    return pos;
    }


    private void adjustScrollBounds(int y) {
    if (y >= mHeight / 3) {
    mUpperBound = mHeight / 3;
    }
    if (y <= mHeight * 2 / 3) {
    mLowerBound = mHeight * 2 / 3;
    }
    }


    /*
    * Restore size and visibility for all listitems
    */
    private void unExpandViews(boolean deletion) {
    for (int i = 0;; i++) {
    View v = getChildAt(i);
    if (v == null) {
    if (deletion) {
    // HACK force update of mItemCount
    int position = getFirstVisiblePosition();
    int y = getChildAt(0).getTop();
    setAdapter(getAdapter());
    setSelectionFromTop(position, y);
    // end hack
    }
    try {
    layoutChildren(); // force children to be recreated where
    // needed
    v = getChildAt(i);
    } catch (IllegalStateException ex) {
    // layoutChildren throws this sometimes, presumably because
    // we're
    // in the process of being torn down but are still getting
    // touch
    // events
    }
    if (v == null) {
    return;
    }
    }
    ViewGroup.LayoutParams params = v.getLayoutParams();
    params.height = mItemHeightNormal;
    v.setLayoutParams(params);
    v.setVisibility(View.VISIBLE);
    }
    }


    /*
    * Adjust visibility and size to make it appear as though an item is being
    * dragged around and other items are making room for it: If dropping the
    * item would result in it still being in the same place, then make the
    * dragged listitem's size normal, but make the item invisible. Otherwise,
    * if the dragged listitem is still on screen, make it as small as possible
    * and expand the item below the insert point. If the dragged item is not on
    * screen, only expand the item below the current insertpoint.
    */
    private void doExpansion() {
    int childnum = mDragPos - getFirstVisiblePosition();
    if (mDragPos > mSrcDragPos) {
    childnum++;
    }
    int numheaders = getHeaderViewsCount();


    View first = getChildAt(mSrcDragPos - getFirstVisiblePosition());
    for (int i = 0;; i++) {
    View vv = getChildAt(i);
    if (vv == null) {
    break;
    }


    int height = mItemHeightNormal;
    int visibility = View.VISIBLE;
    if (mDragPos < numheaders && i == numheaders) {
    // dragging on top of the header item, so adjust the item below
    // instead
    if (vv.equals(first)) {
    visibility = View.INVISIBLE;
    } else {
    height = mItemHeightExpanded;
    }
    } else if (vv.equals(first)) {
    // processing the item that is being dragged
    if (mDragPos == mSrcDragPos
    || getPositionForView(vv) == getCount() - 1) {
    // hovering over the original location
    visibility = View.INVISIBLE;
    } else {
    // not hovering over it
    // Ideally the item would be completely gone, but neither
    // setting its size to 0 nor settings visibility to GONE
    // has the desired effect.
    height = 1;
    }
    } else if (i == childnum) {
    if (mDragPos >= numheaders && mDragPos < getCount() - 1) {
    height = mItemHeightExpanded;
    }
    }
    ViewGroup.LayoutParams params = vv.getLayoutParams();
    params.height = height;
    vv.setLayoutParams(params);
    vv.setVisibility(visibility);
    }
    }


    @Override
    public boolean onTouchEvent(MotionEvent ev) {
    if (mGestureDetector != null) {
    mGestureDetector.onTouchEvent(ev);
    }
    if ((mDragListener != null || mDropListener != null)
    && mDragView != null) {
    int action = ev.getAction();
    switch (action) {
    case MotionEvent.ACTION_UP:
    case MotionEvent.ACTION_CANCEL:
    Rect r = mTempRect;
    mDragView.getDrawingRect(r);
    stopDragging();
    if (mRemoveMode == SLIDE && ev.getX() > r.right * 3 / 4) {
    if (mRemoveListener != null) {
    mRemoveListener.remove(mSrcDragPos);
    }
    unExpandViews(true);
    } else {
    if (mDropListener != null && mDragPos >= 0
    && mDragPos < getCount()) {
    mDropListener.drop(mSrcDragPos, mDragPos);
    }
    unExpandViews(false);
    }
    break;


    case MotionEvent.ACTION_DOWN:
    case MotionEvent.ACTION_MOVE:
    int x = (int) ev.getX();
    int y = (int) ev.getY();
    dragView(x, y);
    int itemnum = getItemForPosition(y);
    if (itemnum >= 0) {
    if (action == MotionEvent.ACTION_DOWN
    || itemnum != mDragPos) {
    if (mDragListener != null) {
    mDragListener.drag(mDragPos, itemnum);
    }
    mDragPos = itemnum;
    doExpansion();
    }
    int speed = 0;
    adjustScrollBounds(y);
    if (y > mLowerBound) {
    // scroll the list up a bit
    if (getLastVisiblePosition() < getCount() - 1) {
    speed = y > (mHeight + mLowerBound) / 2 ? 16 : 4;
    } else {
    speed = 1;
    }
    } else if (y < mUpperBound) {
    // scroll the list down a bit
    speed = y < mUpperBound / 2 ? -16 : -4;
    if (getFirstVisiblePosition() == 0
    && getChildAt(0).getTop() >= getPaddingTop()) {
    // if we're already at the top, don't try to scroll,
    // because
    // it causes the framework to do some extra drawing
    // that messes
    // up our animation
    speed = 0;
    }
    }
    if (speed != 0) {
    smoothScrollBy(speed, 30);
    }
    }
    break;
    }
    return true;
    }
    return super.onTouchEvent(ev);
    }


    private void startDragging(Bitmap bm, int x, int y) {
    stopDragging();


    mWindowParams = new WindowManager.LayoutParams();
    mWindowParams.gravity = Gravity.TOP | Gravity.LEFT;
    mWindowParams.x = x - mDragPointX + mXOffset;
    mWindowParams.y = y - mDragPointY + mYOffset;


    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
    | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
    mWindowParams.format = PixelFormat.TRANSLUCENT;
    mWindowParams.windowAnimations = 0;


    Context context = getContext();
    ImageView v = new ImageView(context);
    // int backGroundColor =
    // context.getResources().getColor(R.color.dragndrop_background);
    // v.setBackgroundColor(backGroundColor);
    // v.setBackgroundResource(R.drawable.ic_launcher);
    v.setPadding(0, 0, 0, 0);
    v.setImageBitmap(bm);
    mDragBitmap = bm;


    mWindowManager = (WindowManager) context
    .getSystemService(Context.WINDOW_SERVICE);
    mWindowManager.addView(v, mWindowParams);
    mDragView = v;
    }


    private void dragView(int x, int y) {
    if (mRemoveMode == SLIDE) {
    float alpha = 1.0f;
    int width = mDragView.getWidth();
    if (x > width / 2) {
    alpha = ((float) (width - x)) / (width / 2);
    }
    mWindowParams.alpha = alpha;
    }


    if (mRemoveMode == FLING || mRemoveMode == TRASH) {
    mWindowParams.x = x - mDragPointX + mXOffset;
    } else {
    mWindowParams.x = 0;
    }
    mWindowParams.y = y - mDragPointY + mYOffset;
    mWindowManager.updateViewLayout(mDragView, mWindowParams);


    if (mTrashcan != null) {
    int width = mDragView.getWidth();
    if (y > getHeight() * 3 / 4) {
    mTrashcan.setLevel(2);
    } else if (width > 0 && x > width / 4) {
    mTrashcan.setLevel(1);
    } else {
    mTrashcan.setLevel(0);
    }
    }
    }


    private void stopDragging() {
    if (mDragView != null) {
    mDragView.setVisibility(GONE);
    WindowManager wm = (WindowManager) getContext().getSystemService(
    Context.WINDOW_SERVICE);
    wm.removeView(mDragView);
    mDragView.setImageDrawable(null);
    mDragView = null;
    }
    if (mDragBitmap != null) {
    mDragBitmap.recycle();
    mDragBitmap = null;
    }
    if (mTrashcan != null) {
    mTrashcan.setLevel(0);
    }
    }


    public void setTrashcan(Drawable trash) {
    mTrashcan = trash;
    mRemoveMode = TRASH;
    }


    public void setDragListener(DragListener l) {
    mDragListener = l;
    }


    public void setDropListener(DropListener l) {
    mDropListener = l;
    }


    public void setRemoveListener(RemoveListener l) {
    mRemoveListener = l;
    }


    public interface DragListener {
    void drag(int from, int to);
    }


    public interface DropListener {
    void drop(int from, int to);
    }


    public interface RemoveListener {
    void remove(int which);
    }
    }

    第四步:item 布局文件:

    <?xml version="1.0" encoding="utf-8"?>
    <TextView xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/title"
        android:layout_width="fill_parent"
        android:layout_height="@dimen/normal_height"
        android:gravity="center_vertical"
        android:paddingLeft="6dip" 
        android:background="@drawable/grablines"/>


    drawable下面的grablines文件:

    <?xml version="1.0" encoding="utf-8"?>
    <bitmap xmlns:android="http://schemas.android.com/apk/res/android"
        android:gravity="right"
        android:src="@drawable/ic_launcher" />

    dimens文件信息:

    <resources>


        <!-- Default screen margins, per the Android Design guidelines. -->
        <dimen name="activity_horizontal_margin">16dp</dimen>
        <dimen name="activity_vertical_margin">16dp</dimen>


        <!-- height of a normal list item in edit playlist mode -->
        <dimen name="normal_height">80dip</dimen>
        <!-- height of an expanded list item in edit playlist mode -->
        <dimen name="expanded_height">160dip</dimen>


        
    </resources>

    Demo 源码下载


  • 相关阅读:
    hadoop之 mr输出到hbase
    北美IT公司大致分档
    推荐系统(协同过滤,slope one)
    机器学习的常见面试问题
    关联规则之Aprior算法(购物篮分析)
    Python的Set和List的性能比较 + 两者之间的转换
    Python 集合set添加删除、交集、并集、集合操作符号
    3.算法-二叉树遍历
    1.系统设计-概要
    2算法-二分查找
  • 原文地址:https://www.cnblogs.com/riasky/p/3478500.html
Copyright © 2011-2022 走看看