Skip to content
This repository has been archived by the owner on Jan 29, 2021. It is now read-only.

Added another reorder type to just swap two views without looping through all views between. #62

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ gen/
build/
*.iml

# Gradle
.gradle/

dynamicgrid/proguard-project.txt

dynamicgrid/build.xml
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public abstract class BaseDynamicGridAdapter extends AbstractDynamicGridAdapter

private ArrayList<Object> mItems = new ArrayList<Object>();
private int mColumnCount;
private int mReorderType = DynamicGridView.REORDER_TYPE_SNAKE;

protected BaseDynamicGridAdapter(Context context, int columnCount) {
this.mContext = context;
Expand All @@ -39,6 +40,10 @@ public void set(List<?> items) {
notifyDataSetChanged();
}

public void setReorderType(int reorderType) {
this.mReorderType = reorderType;
}

public void clear() {
clearStableIdMap();
mItems.clear();
Expand Down Expand Up @@ -94,7 +99,11 @@ public void setColumnCount(int columnCount) {
@Override
public void reorderItems(int originalPosition, int newPosition) {
if (newPosition < getCount()) {
DynamicGridUtils.reorder(mItems, originalPosition, newPosition);
if(mReorderType == DynamicGridView.REORDER_TYPE_SNAKE) {
DynamicGridUtils.reorder(mItems, originalPosition, newPosition);
} else if(mReorderType == DynamicGridView.REORDER_TYPE_SWAP) {
DynamicGridUtils.swap(mItems, originalPosition, newPosition);
}
notifyDataSetChanged();
}
}
Expand All @@ -104,6 +113,12 @@ public boolean canReorder(int position) {
return true;
}

@Override
public int getReorderType()
{
return mReorderType;
}

public List<Object> getItems() {
return mItems;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,9 @@ public interface DynamicGridAdapterInterface {
*/
boolean canReorder(int position);

/**
* Determines reorder type.
*/
int getReorderType();

}
119 changes: 78 additions & 41 deletions dynamicgrid/src/org/askerov/dynamicgrid/DynamicGridView.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package org.askerov.dynamicgrid;

import android.animation.*;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.TypeEvaluator;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Bitmap;
Expand All @@ -21,14 +26,20 @@
import android.widget.GridView;
import android.widget.ListAdapter;

import java.util.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;

/**
* Author: alex askerov
* Date: 9/6/13
* Time: 12:31 PM
*/
public class DynamicGridView extends GridView {
public final static int REORDER_TYPE_SNAKE = 1;
public final static int REORDER_TYPE_SWAP = 2;
private static final int INVALID_ID = -1;

private static final int MOVE_DURATION = 300;
Expand Down Expand Up @@ -855,7 +866,7 @@ public boolean onPreDraw() {
mTotalOffsetY += mDeltaY;
mTotalOffsetX += mDeltaX;

animateReorder(mOriginalPosition, mTargetPosition);
animateSnakeReorder(mOriginalPosition, mTargetPosition);

assert mMobileView != null;
mMobileView.setVisibility(View.VISIBLE);
Expand Down Expand Up @@ -913,50 +924,38 @@ private long getId(int position) {

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private void animateReorder(final int oldPosition, final int newPosition) {
if(getAdapterInterface().getReorderType() == REORDER_TYPE_SNAKE) {
animateSnakeReorder(oldPosition, newPosition);
} else if(getAdapterInterface().getReorderType() == REORDER_TYPE_SWAP) {
animateSwapReorder(oldPosition, newPosition);
}
}

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private void animateSnakeReorder(final int oldPosition, final int newPosition) {
boolean isForward = newPosition > oldPosition;
List<Animator> resultList = new LinkedList<Animator>();
if (isForward) {
for (int pos = Math.min(oldPosition, newPosition); pos < Math.max(oldPosition, newPosition); pos++) {
View view = getViewForId(getId(pos));
if ((pos + 1) % getColumnCount() == 0) {
resultList.add(createTranslationAnimations(view, -view.getWidth() * (getColumnCount() - 1), 0,
view.getHeight(), 0));
} else {
resultList.add(createTranslationAnimations(view, view.getWidth(), 0, 0, 0));
}
}
} else {
for (int pos = Math.max(oldPosition, newPosition); pos > Math.min(oldPosition, newPosition); pos--) {
View view = getViewForId(getId(pos));
if ((pos + getColumnCount()) % getColumnCount() == 0) {
resultList.add(createTranslationAnimations(view, view.getWidth() * (getColumnCount() - 1), 0,
-view.getHeight(), 0));
} else {
resultList.add(createTranslationAnimations(view, -view.getWidth(), 0, 0, 0));
}
}
}

AnimatorSet resultSet = new AnimatorSet();
resultSet.playTogether(resultList);
resultSet.setDuration(MOVE_DURATION);
resultSet.setInterpolator(new AccelerateDecelerateInterpolator());
resultSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
mReorderAnimation = true;
updateEnableState();
}
for (int pos = Math.min(oldPosition, newPosition); pos < Math.max(oldPosition, newPosition); pos++) {

@Override
public void onAnimationEnd(Animator animation) {
mReorderAnimation = false;
updateEnableState();
}
});
resultSet.start();
int oldViewPosition = isForward ? pos : pos+1;
int newViewPosition = isForward ? pos+1 : pos;

resultList.add(createViewSwapAnimations(oldViewPosition, newViewPosition));
}

startAnimations(resultList);
}

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private void animateSwapReorder(final int oldPosition, final int newPosition) {

List<Animator> resultList = new LinkedList<Animator>();

resultList.add(createViewSwapAnimations(oldPosition, newPosition));

startAnimations(resultList);
}

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private AnimatorSet createTranslationAnimations(View view, float startX, float endX, float startY, float endY) {
Expand All @@ -975,6 +974,44 @@ protected void dispatchDraw(Canvas canvas) {
}
}

/**
* Basically the old view is set to the new position and
* animates it's way from the old position to the new position.
* @param oldViewPosition Position of the old view.
* @param newViewPosition Position of the new view.
* @return
*/
private AnimatorSet createViewSwapAnimations(int oldViewPosition, int newViewPosition) {
View viewOld = getViewForId(getId(oldViewPosition));
View viewNew = getViewForId(getId(newViewPosition));

return createTranslationAnimations(viewOld, viewNew.getX()-viewOld.getX(), 0, viewNew.getY()-viewOld.getY(), 0);
}

/**
*
* @param resultList
*/
private void startAnimations(List<Animator> resultList) {
AnimatorSet resultSet = new AnimatorSet();
resultSet.playTogether(resultList);
resultSet.setDuration(MOVE_DURATION);
resultSet.setInterpolator(new AccelerateDecelerateInterpolator());
resultSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
mReorderAnimation = true;
updateEnableState();
}

@Override
public void onAnimationEnd(Animator animation) {
mReorderAnimation = false;
updateEnableState();
}
});
resultSet.start();
}

public interface OnDropListener {
void onActionDrop();
Expand Down