I have a program that creates a Grid and rearranges it by drag-and-droping, first of all everything is functional BUT not the way I wanted it. The must common rearrange is this, you drag an object and when you drop it falls into that position moving all the rest forward until they find the empty space, what I want is more simple; I want the objects to switch with the one that's in the position you dropped it. This is the code of the adapter:
@SuppressLint("WrongCall")
public class DragGridView extends ViewGroup implements View.OnTouchListener,
View.OnClickListener, View.OnLongClickListener {
public static float childRatio = .9f;
protected int colCount, childSize, padding, dpi, scroll = 0;
protected float lastDelta = 0;
protected Handler handler = new Handler();
protected int dragged = -1, lastX = -1, lastY = -1, lastTarget = -1;
protected boolean enabled = true, touching = false;
public static int animT = 150;
protected ArrayList<Integer> newPositions = new ArrayList<Integer>();
protected OnRearrangeListener onRearrangeListener;
protected OnClickListener secondaryOnClickListener;
private OnItemClickListener onItemClickListener;
public interface OnRearrangeListener {
public abstract void onRearrange(int oldIndex, int newIndex);
}
public DragGridView(Context context, AttributeSet attrs) {
super(context, attrs);
setListeners();
handler.removeCallbacks(updateTask);
handler.postAtTime(updateTask, SystemClock.uptimeMillis() + 500);
setChildrenDrawingOrderEnabled(true);
DisplayMetrics metrics = new DisplayMetrics();
((Activity) context).getWindowManager().getDefaultDisplay()
.getMetrics(metrics);
dpi = metrics.densityDpi;
}
protected void setListeners() {
setOnTouchListener(this);
super.setOnClickListener(this);
setOnLongClickListener(this);
}
@Override
public void setOnClickListener(OnClickListener l) {
secondaryOnClickListener = l;
}
protected Runnable updateTask = new Runnable() {
public void run() {
if (dragged != -1) {
if (lastY < padding * 3 && scroll > 0)
scroll -= 20;
else if (lastY > getBottom() - getTop() - (padding * 3)
&& scroll < getMaxScroll())
scroll += 20;
} else if (lastDelta != 0 && !touching) {
scroll += lastDelta;
lastDelta *= .9;
if (Math.abs(lastDelta) < .25)
lastDelta = 0;
}
clampScroll();
onLayout(true, getLeft(), getTop(), getRight(), getBottom());
handler.postDelayed(this, 25);
}
};
@Override
public void addView(View child) {
super.addView(child);
newPositions.add(-1);
};
@Override
public void removeViewAt(int index) {
super.removeViewAt(index);
newPositions.remove(index);
};
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// compute width of view, in dp
float w = (r - l) / (dpi / 160f);
colCount = 2;
int sub = 240;
w -= 280;
while (w > 0) {
colCount++;
w -= sub;
sub += 40;
}
childSize = (r - l) / colCount;
childSize = Math.round(childSize * childRatio);
padding = ((r - l) - (childSize * colCount)) / (colCount + 1);
for (int i = 0; i < getChildCount(); i++)
if (i != dragged) {
Point xy = getCoorFromIndex(i);
getChildAt(i).layout(xy.x, xy.y, xy.x + childSize,
xy.y + childSize);
}
}
@Override
protected int getChildDrawingOrder(int childCount, int i) {
if (dragged == -1)
return i;
else if (i == childCount - 1)
return dragged;
else if (i >= dragged)
return i + 1;
return i;
}
public int getIndexFromCoor(int x, int y) {
int col = getColOrRowFromCoor(x), row = getColOrRowFromCoor(y + scroll);
if (col == -1 || row == -1)
return -1;
int index = row * colCount + col;
if (index >= getChildCount())
return -1;
return index;
}
protected int getColOrRowFromCoor(int coor) {
coor -= padding;
for (int i = 0; coor > 0; i++) {
if (coor < childSize)
return i;
coor -= (childSize + padding);
}
return -1;
}
protected int getTargetFromCoor(int x, int y) {
if (getColOrRowFromCoor(y + scroll) == -1)
return -1;
int leftPos = getIndexFromCoor(x - (childSize / 4), y);
int rightPos = getIndexFromCoor(x + (childSize / 4), y);
if (leftPos == -1 && rightPos == -1)
return -1;
if (leftPos == rightPos)
return -1;
int target = -1;
if (rightPos > -1)
target = rightPos;
else if (leftPos > -1)
target = leftPos + 1;
if (dragged < target)
return target - 1;
return target;
}
protected Point getCoorFromIndex(int index) {
int col = index % colCount;
int row = index / colCount;
return new Point(padding + (childSize + padding) * col, padding
+ (childSize + padding) * row - scroll);
}
public int getIndexOf(View child) {
for (int i = 0; i < getChildCount(); i++)
if (getChildAt(i) == child)
return i;
return -1;
}
public void onClick(View view) {
if (enabled) {
if (secondaryOnClickListener != null)
secondaryOnClickListener.onClick(view);
if (onItemClickListener != null && getLastIndex() != -1)
onItemClickListener.onItemClick(null,
getChildAt(getLastIndex()), getLastIndex(),
getLastIndex() / colCount);
}
}
public boolean onLongClick(View view) {
if (!enabled)
return false;
int index = getLastIndex();
if (index != -1) {
dragged = index;
animateDragged();
return true;
}
return false;
}
@SuppressLint("WrongCall")
public boolean onTouch(View view, MotionEvent event) {
int action = event.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
enabled = true;
lastX = (int) event.getX();
lastY = (int) event.getY();
touching = true;
break;
case MotionEvent.ACTION_MOVE:
int delta = lastY - (int) event.getY();
if (dragged != -1) {
// change draw location of dragged visual
int x = (int) event.getX(), y = (int) event.getY();
int l = x - (3 * childSize / 4), t = y - (3 * childSize / 4);
getChildAt(dragged).layout(l, t, l + (childSize * 3 / 2),
t + (childSize * 3 / 2));
// check for new target hover
int target = getTargetFromCoor(x, y);
if (lastTarget != target) {
if (target != -1) {
animateGap(target);
lastTarget = target;
}
}
} else {
scroll += delta;
clampScroll();
if (Math.abs(delta) > 2)
enabled = false;
onLayout(true, getLeft(), getTop(), getRight(), getBottom());
}
lastX = (int) event.getX();
lastY = (int) event.getY();
lastDelta = delta;
break;
case MotionEvent.ACTION_UP:
if (dragged != -1) {
View v = getChildAt(dragged);
if (lastTarget != -1)
reorderChildren();
else {
Point xy = getCoorFromIndex(dragged);
v.layout(xy.x, xy.y, xy.x + childSize, xy.y + childSize);
}
v.clearAnimation();
if (v instanceof ImageView)
((ImageView) v).setAlpha(255);
lastTarget = -1;
dragged = -1;
}
touching = false;
break;
}
if (dragged != -1)
return true;
return false;
}
protected void animateDragged() {
View v = getChildAt(dragged);
int x = getCoorFromIndex(dragged).x + childSize / 2, y = getCoorFromIndex(dragged).y
+ childSize / 2;
int l = x - (3 * childSize / 4), t = y - (3 * childSize / 4);
v.layout(l, t, l + (childSize * 3 / 2), t + (childSize * 3 / 2));
AnimationSet animSet = new AnimationSet(true);
ScaleAnimation scale = new ScaleAnimation(.667f, 1, .667f, 1,
childSize * 3 / 4, childSize * 3 / 4);
scale.setDuration(animT);
AlphaAnimation alpha = new AlphaAnimation(1, .5f);
alpha.setDuration(animT);
animSet.addAnimation(scale);
animSet.addAnimation(alpha);
animSet.setFillEnabled(true);
animSet.setFillAfter(true);
v.clearAnimation();
v.startAnimation(animSet);
}
protected void animateGap(int target) {
for (int i = 0; i < getChildCount(); i++) {
View v = getChildAt(i);
if (i == dragged)
continue;
int newPos = i;
if (dragged < target && i >= dragged + 1 && i <= target)
newPos--;
else if (target < dragged && i >= target && i < dragged)
newPos++;
int oldPos = i;
if (newPositions.get(i) != -1)
oldPos = newPositions.get(i);
if (oldPos == newPos)
continue;
Point oldXY = getCoorFromIndex(oldPos);
Point newXY = getCoorFromIndex(newPos);
Point oldOffset = new Point(oldXY.x - v.getLeft(), oldXY.y
- v.getTop());
Point newOffset = new Point(newXY.x - v.getLeft(), newXY.y
- v.getTop());
TranslateAnimation translate = new TranslateAnimation(
Animation.ABSOLUTE, oldOffset.x, Animation.ABSOLUTE,
newOffset.x, Animation.ABSOLUTE, oldOffset.y,
Animation.ABSOLUTE, newOffset.y);
translate.setDuration(animT);
translate.setFillEnabled(true);
translate.setFillAfter(true);
v.clearAnimation();
v.startAnimation(translate);
newPositions.set(i, newPos);
}
}
protected void reorderChildren() {
if (onRearrangeListener != null)
onRearrangeListener.onRearrange(dragged, lastTarget);
ArrayList<View> children = new ArrayList<View>();
for (int i = 0; i < getChildCount(); i++) {
getChildAt(i).clearAnimation();
children.add(getChildAt(i));
}
removeAllViews();
while (dragged != lastTarget)
if (lastTarget == children.size())
{
children.add(children.remove(dragged));
dragged = lastTarget;
} else if (dragged < lastTarget)
{
Collections.swap(children, dragged, dragged + 1);
dragged++;
} else if (dragged > lastTarget)
{
Collections.swap(children, dragged, dragged - 1);
dragged--;
}
for (int i = 0; i < children.size(); i++) {
newPositions.set(i, -1);
addView(children.get(i));
}
onLayout(true, getLeft(), getTop(), getRight(), getBottom());
}
@SuppressLint("WrongCall")
public void scrollToTop() {
scroll = 0;
}
public void scrollToBottom() {
scroll = Integer.MAX_VALUE;
clampScroll();
}
protected void clampScroll() {
int stretch = 3, overreach = getHeight() / 2;
int max = getMaxScroll();
max = Math.max(max, 0);
if (scroll < -overreach) {
scroll = -overreach;
lastDelta = 0;
} else if (scroll > max + overreach) {
scroll = max + overreach;
lastDelta = 0;
} else if (scroll < 0) {
if (scroll >= -stretch)
scroll = 0;
else if (!touching)
scroll -= scroll / stretch;
} else if (scroll > max) {
if (scroll <= max + stretch)
scroll = max;
else if (!touching)
scroll += (max - scroll) / stretch;
}
}
protected int getMaxScroll() {
int rowCount = (int) Math.ceil((double) getChildCount() / colCount), max = rowCount
* childSize + (rowCount + 1) * padding - getHeight();
return max;
}
public int getLastIndex() {
return getIndexFromCoor(lastX, lastY);
}
public void setOnRearrangeListener(OnRearrangeListener l) {
this.onRearrangeListener = l;
}
public void setOnItemClickListener(OnItemClickListener l) {
this.onItemClickListener = l;
}
}
The Methods I think I have to change are AnimateGap and reorderChildren, but don't know how to do it exactly.