您的位置:首页 > 移动开发 > Android开发

Android拖拽的ExpandableListView

2015-11-24 22:52 423 查看
正如我们知道的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 location
private int mStartFlatPosition;
private int prevY = -1;
private int backgroundColor = 0xe0103010; // different color to identify
private 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;
}

@Override
public 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() {
@Override
public 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 desired
if (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);// 返回值为组的id
mEndPosition[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 view
private 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
// limited
layoutParams.x = x;
}
if (dragOnLongPress) {
// to show that item is detached from the list
layoutParams.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 dragging
private 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 memory
Bitmap 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;
}

@Override
public void setAdapter(ExpandableListAdapter adapter) {
// TODO Auto-generated method stub
super.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 it
itemView.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) {

}
}

}

源码下载
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息