Android拖拽的ExpandableListView

来源:互联网 发布:uploadify java demo 编辑:程序博客网 时间:2024/06/07 15:16

正如我们知道的listview在Android中是一个常用的控件,很多app都喜欢在Listview上面做文章,拖动排序就是一中常见的,github上面有一个很好的demo。ExpandableListView顾名思义就是Listview的一个扩展,用来分组Listview,比如QQ好友列表,既然Listview可以拖拽排序,ExpandableListView当然也是可以排序的,看到了一些demo觉得github这个还是不错的DragNDropListView。代码比较简洁清晰,但它和常见的可以拖拽ExpandableListView一样支持跨组拖动,跨组拖动在有些时候是不必要的,因此我也是在它的代码上面改了下控制不可以跨组拖动

     首先我们需要知道ExpandableListView的两个方法getPackedPositionGroup 返回当前条目所在的组的位置

getPackedPositionChild返回当前条目在改组中的位置

 /**     * Gets the group position from a packed position. See     * {@link #getPackedPositionForChild(int, int)}.     *      * @param packedPosition The packed position from which the group position     *            will be returned.     * @return The group position portion of the packed position. If this does     *         not contain a group, returns -1.     */    public static int getPackedPositionGroup(long packedPosition) {        // Null        if (packedPosition == PACKED_POSITION_VALUE_NULL) return -1;                return (int) ((packedPosition & PACKED_POSITION_MASK_GROUP) >> PACKED_POSITION_SHIFT_GROUP);    }
/**     * Gets the child position from a packed position that is of     * {@link #PACKED_POSITION_TYPE_CHILD} type (use {@link #getPackedPositionType(long)}).     * To get the group that this child belongs to, use     * {@link #getPackedPositionGroup(long)}. See     * {@link #getPackedPositionForChild(int, int)}.     *      * @param packedPosition The packed position from which the child position     *            will be returned.     * @return The child position portion of the packed position. If this does     *         not contain a child, returns -1.     */    public static int getPackedPositionChild(long packedPosition) {        // Null        if (packedPosition == PACKED_POSITION_VALUE_NULL) return -1;                // Group since a group type clears this bit        if ((packedPosition & PACKED_POSITION_MASK_TYPE) != PACKED_POSITION_MASK_TYPE) return -1;        return (int) (packedPosition & PACKED_POSITION_MASK_CHILD);    }
知道这两个方法就很好办了,说白了当遇到两个交换的条目不再同一组中就不支持拖动,也就是拖动无效。直接列修改的ExpandableListView的代码了,注释在代码中

/* * Copyright (C) 2012 Sreekumar SH * * 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.android.dragdrop.listview;import android.content.Context;import android.graphics.Bitmap;import android.graphics.PixelFormat;import android.os.Handler;import android.util.AttributeSet;import android.util.Log;import android.view.Display;import android.view.Gravity;import android.view.MotionEvent;import android.view.View;import android.view.WindowManager;import android.widget.ExpandableListAdapter;import android.widget.ExpandableListView;import android.widget.ImageView;import com.android.dragdrop.R;/** * Custom ExpandableListView which enables drag and drop *  * @author <a href="http://sreekumar.sh" >Sreekumar SH </a> *         (sreekumar.sh@gmail.com) *  */public class DragNDropListView extends ExpandableListView {public interface DragNDropListeners {public void onDrag(float x, float y);/** * Event fired when an item is picked. position[0] - group position * position[1] - child position *  * @param position */public void onPick(int[] position);/** * Event fired when an item is dropped. from - position from where item * is picked. to - position at which item is dropped. from[0] - group * position from[1] - child position *  * @param position */public void onDrop(int[] from, int[] to);}private static final String TAG = "DragNDropListView";private boolean mDragMode;private boolean limitHorizontalDrag = true;private int[] mStartPosition = new int[2];private int[] mEndPosition = new int[2];private int mDragPointOffset; // Used to adjust drag view locationprivate int mStartFlatPosition;private int prevY = -1;private int backgroundColor = 0xe0103010; // different color to identifyprivate int defaultBackgroundColor;private float screenHeight;private float dragRatio;//计算拖动速度private ImageView mDragView;private DragNDropAdapter adapter;private DragNDropListeners listeners;private int dragOffset = 50;private boolean dragOnLongPress;private boolean pressedItem;private Handler handler = new Handler();public DragNDropListView(Context context, AttributeSet attrs) {super(context, attrs);WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);Display display = wm.getDefaultDisplay();screenHeight = display.getHeight();}public void setSelectedBackgroud(int color) {backgroundColor = color;}@Overridepublic boolean onTouchEvent(MotionEvent event) {return touchHandler(event);}private boolean touchHandler(final MotionEvent event) {final int action = event.getAction();final int x = (int) event.getX();final int y = (int) event.getY();if (prevY < 0) {prevY = y;}Log.d(TAG, "Motion event " + event.getAction());int flatPosition = pointToPosition(x, y);dragRatio = getHeight() / screenHeight;long packagedPosition = getExpandableListPosition(flatPosition);if (action == MotionEvent.ACTION_DOWN&& getPackedPositionType(packagedPosition) == 1) {if (dragOnLongPress) {if (pressedItem) {mDragMode = true;pressedItem = false;} else {pressedItem = true;Runnable r = new Runnable() {@Overridepublic void run() {// y coordinate is changing for no reason ??event.setLocation(x, y);touchHandler(event);}};handler.postDelayed(r, 200);return true;}} else if (x < dragOffset) {mDragMode = true;}}if (!mDragMode) {/** when user action on other areas */if ((pressedItem && Math.abs(prevY - y) > 30)|| event.getAction() != MotionEvent.ACTION_MOVE) {pressedItem = false;handler.removeCallbacksAndMessages(null);}return super.onTouchEvent(event);}switch (action) {case MotionEvent.ACTION_DOWN:mStartFlatPosition = flatPosition;mStartPosition[0] = getPackedPositionGroup(packagedPosition);System.out.println("packagedPosition第" + packagedPosition + "组");mStartPosition[1] = getPackedPositionChild(packagedPosition);if (packagedPosition != PACKED_POSITION_VALUE_NULL) {int mItemPosition = flatPosition - getFirstVisiblePosition();mDragPointOffset = y - getChildAt(mItemPosition).getTop();mDragPointOffset -= ((int) event.getRawY()) - y;startDrag(mItemPosition, y);if (listeners != null) {listeners.onPick(mStartPosition);System.out.println("group" + mStartPosition[0]);System.out.println("child" + mStartPosition[0]);}drag(x, y);}break;case MotionEvent.ACTION_MOVE:int speed = (int) ((y - prevY) * dragRatio);if (getLastVisiblePosition() < getCount() && speed > 0) {smoothScrollBy(speed, 1);}if (getFirstVisiblePosition() > 0 && speed < 0) {smoothScrollBy(speed, 1);}drag(x, y);// replace 0 with x if desiredif (listeners != null) {listeners.onDrag(x, y);}break;case MotionEvent.ACTION_CANCEL:case MotionEvent.ACTION_UP:default:mDragMode = false;if (getPackedPositionType(packagedPosition) == 0) {mEndPosition[0] = getPackedPositionGroup(packagedPosition);// 返回值为组的idmEndPosition[1] = 0;} else {mEndPosition[0] = getPackedPositionGroup(packagedPosition);mEndPosition[1] = getPackedPositionChild(packagedPosition);// 返回值为子元素的id}stopDrag(mStartFlatPosition);if (packagedPosition != PACKED_POSITION_VALUE_NULL) {if (adapter != null) {if (mStartPosition[0] == mEndPosition[0]) {// 只有在同一组中可以拖动,去掉条件就是可以跨组拖动adapter.onDrop(mStartPosition, mEndPosition);System.out.println("group" + mStartPosition[0]);System.out.println("child" + mStartPosition[0]);}}if (listeners != null) {if (mStartPosition[0] == mEndPosition[0]) {// 只有在同一组中可以拖动,去掉条件就是可以跨组拖动listeners.onDrop(mStartPosition, mEndPosition);System.out.println("group" + mStartPosition[0]);System.out.println("child" + mStartPosition[0]);}}}break;}prevY = y;return true;}// move the drag viewprivate void drag(int x, int y) {if (mDragView != null) {WindowManager.LayoutParams layoutParams = (WindowManager.LayoutParams) mDragView.getLayoutParams();if (!limitHorizontalDrag) {// no need to move if horizontal drag is// limitedlayoutParams.x = x;}if (dragOnLongPress) {// to show that item is detached from the listlayoutParams.y = y - mDragPointOffset - 20;} else {layoutParams.y = y - mDragPointOffset;}WindowManager mWindowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);mWindowManager.updateViewLayout(mDragView, layoutParams);}}// enable the drag view for draggingprivate void startDrag(int itemIndex, int y) {// stopDrag(itemIndex);View item = getChildAt(itemIndex);if (item == null)return;hideItem(item, mStartPosition);// Create a copy of the drawing cache so that it does not get recycled// by the framework when the list tries to clean up memoryBitmap bitmap = Bitmap.createBitmap(item.getDrawingCache());item.setBackgroundColor(defaultBackgroundColor);WindowManager.LayoutParams mWindowParams = new WindowManager.LayoutParams();mWindowParams.gravity = Gravity.TOP;mWindowParams.x = 0;mWindowParams.y = y - mDragPointOffset;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);v.setImageBitmap(bitmap);WindowManager mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);mWindowManager.addView(v, mWindowParams);mDragView = v;}@Overridepublic void setAdapter(ExpandableListAdapter adapter) {// TODO Auto-generated method stubsuper.setAdapter(adapter);this.adapter = (DragNDropAdapter) adapter;}private void hideItem(View itemView, int[] position) {if (adapter != null) {adapter.onPick(position);}itemView.setVisibility(View.INVISIBLE); // make the item invisible as we// have picked ititemView.setDrawingCacheEnabled(true);defaultBackgroundColor = itemView.getDrawingCacheBackgroundColor();itemView.setBackgroundColor(backgroundColor);ImageView iv = (ImageView) itemView.findViewById(R.id.move_icon_customizer_item);if (iv != null)iv.setVisibility(View.INVISIBLE);}public void showItem(View itemView) {if (itemView != null) {itemView.setVisibility(View.VISIBLE);itemView.setBackgroundColor(defaultBackgroundColor);itemView.setDrawingCacheEnabled(false);ImageView iv = (ImageView) itemView.findViewById(R.id.move_icon_customizer_item);if (iv != null)iv.setVisibility(View.VISIBLE);}}/** * destroy the drag view *  * @param itemIndex *            Index of the item */private void stopDrag(int itemIndex) {int firstPosition = getFirstVisiblePosition() - getHeaderViewsCount();int wantedChild = itemIndex - firstPosition;if (mDragView != null) {if (wantedChild < 0 || wantedChild >= getChildCount()) {// no need to do anything} else {showItem(getChildAt(wantedChild));}mDragView.setVisibility(GONE);WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);wm.removeView(mDragView);mDragView.setImageDrawable(null);mDragView = null;}}/** * @return the limitHorizontalDrag */public boolean isLimitHorizontalDrag() {return limitHorizontalDrag;}/** * @param limitHorizontalDrag *            the limitHorizontalDrag to set */public void setLimitHorizontalDrag(boolean limitHorizontalDrag) {this.limitHorizontalDrag = limitHorizontalDrag;}/** * @return the listeners */public DragNDropListeners getListeners() {return listeners;}/** * @param listeners *            the listeners to set */public void setListeners(DragNDropListeners listeners) {this.listeners = listeners;}/** * @return the dragOffset */public int getDragOffset() {return dragOffset;}/** * @param dragOffset *            the dragOffset to set */public void setDragOffset(int dragOffset) {this.dragOffset = dragOffset;}public boolean isDragOnLongPress() {return dragOnLongPress;}/** * set this to drag an item by long press *  * @param flag */public void setDragOnLongPress(boolean flag) {dragOnLongPress = flag;if (flag) {}}}

源码下载




0 0
原创粉丝点击