Android Open Source - DynamicGridView Dynamic Grid View






From Project

Back to project page DynamicGridView.

License

The source code is released under:

GNU General Public License

If you think the Android project DynamicGridView listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.authy.dynamicgridview;
/*ww w .  jav  a 2  s. c o  m*/
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.ClipData;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.DragEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.AdapterView;
import android.widget.GridView;
import android.widget.ListAdapter;

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Created by fernandinho on 10/29/14.
 *
 * Important: To properly use the DynamicGridView you must use the ViewHolder patterns in your
 * adapter. Not doing so wil result in weird visibility bugs (views disappearing/re-appearing)
 */
public class DynamicGridView extends GridView implements AdapterView.OnItemLongClickListener, View.OnDragListener {

    public static final String TAG = "DynamicGridView";

    public final static float SCROLL_BOUND_UP = 0.20f;
    public final static float SCROLL_BOUND_DOWN = 0.80f;
    public final static int SCROLL_SPEED = 8;

    private OnDragListener onDragListener;
    private OnDropListener onDropListener;

    private int currentlyDraggedOverPosition;
    private int lastDraggedOverPosition;

    private Rect mTouchFrame;

    private int isAnimationRunning;
    private boolean pendingDrop;

    public DynamicGridView(Context context) {
        super(context);
        init();
    }

    public DynamicGridView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public DynamicGridView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    private void init() {
        onDragListener = new DefOnDragListener();
        onDropListener = new DefOnDropListener();
        setOnItemLongClickListener(this);
        setOnDragListener(this);

        currentlyDraggedOverPosition = -1;
        isAnimationRunning = 0;
        pendingDrop = false;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {



        return super.onTouchEvent(event);
    }

    @Override
    public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {

        startDragAt(position, view);
        return true;
    }

    @Override
    public boolean onDrag(View v, DragEvent event) {

        int action = event.getAction();
        switch (action){
            case DragEvent.ACTION_DRAG_STARTED:
                log("drag started");
                return true;
            case DragEvent.ACTION_DRAG_ENDED:
                log("drag ended");
                dropItem(event);
                return true;
            case DragEvent.ACTION_DROP:
                dropItem(event);
                log("dropping");
                return true;
            case DragEvent.ACTION_DRAG_EXITED:
                log("drag exited");
                return true;
            case DragEvent.ACTION_DRAG_LOCATION:
                updateDrag(event);
                return true;
            default:
                return false;
        }
    }

    /**
     * Starts a drag operation at the given position
     * @param position
     * @param view
     */
    public void startDragAt(int position, View view){
        currentlyDraggedOverPosition = position;
        lastDraggedOverPosition = position;
        getAdapter().setDraggingPosition(position);
        ClipData clipData = ClipData.newPlainText("label","text");
        DragShadowBuilder shadowBuilder = new DragShadowBuilder(view);
        view.startDrag(clipData, shadowBuilder, null,0);
        getAdapter().notifyDataSetChanged();
    }

    private void dropItem(DragEvent event){
        log("dropping with %d pending animations",isAnimationRunning);
        currentlyDraggedOverPosition = -1;
        lastDraggedOverPosition = -1;
        getAdapter().setDraggingPosition(-1);
        getAdapter().setDraggingOver(-1);
        getAdapter().notifyDataSetChanged();
        pendingDrop = false;
    }

    private void updateDrag(DragEvent event){
        int pos = pointToPosition((int)event.getX(), (int)event.getY());

        if(pos != INVALID_POSITION && pos != currentlyDraggedOverPosition ){
            lastDraggedOverPosition = currentlyDraggedOverPosition;
            currentlyDraggedOverPosition = pos;
            getAdapter().setDraggingOver(pos);
            getAdapter().notifyDataSetChanged();
            swapItems(currentlyDraggedOverPosition, lastDraggedOverPosition);
        }
    }

    public void swapItems(final int current, final int last){

        SwapDirection direction = getSwapDirection(current, last);

        log("Moved  " + direction + " from " + current + " to " + last);

        getAdapter().swap(current, last);
        getAdapter().setDraggingPosition(current);
        getAdapter().notifyDataSetChanged();
    }


    public View getViewByPosition(int pos) {
        final int firstListItemPosition = getFirstVisiblePosition();
        final int lastListItemPosition = firstListItemPosition + getChildCount() - 1;

        if (pos < firstListItemPosition || pos > lastListItemPosition ) {
            return getAdapter().getView(pos, null, this);
        } else {
            final int childIndex = pos - firstListItemPosition;
            return getChildAt(childIndex);
        }
    }

    private int getXDirectionSign(SwapDirection direction) {
        if(direction == SwapDirection.left){
            return 1;
        }
        else if (direction == SwapDirection.right){
            return -1;
        }
        return 0;
    }

    private int getYDirectionSign(SwapDirection direction) {
        if(direction == SwapDirection.up){
            return 1;
        }
        else if (direction == SwapDirection.down){
            return -1;
        }
        return 0;
    }

    private TranslateAnimation createTranslationAnimations(View view, float startX, float endX, float startY, float endY) {
        TranslateAnimation animation = new TranslateAnimation(startX, endX, startY, endY);
        animation.setDuration(100);
        view.setAnimation(animation);
        view.setAlpha(1.0f);
        return animation;
    }

    private SwapDirection getSwapDirection(int pos1, int pos2){
        int[] pos1XY = getXYPos(pos1);
        int[] pos2XY = getXYPos(pos2);

        int xDiff = pos1XY[0] - pos2XY[0];
        int yDiff = pos1XY[1] - pos2XY[1];
        if(xDiff > 0){
            return SwapDirection.right;
        }
        else if (xDiff < 0){
            return SwapDirection.left;
        }
        else if (yDiff > 0){
            return SwapDirection.down;
        }
        else if (yDiff < 0){
            return SwapDirection.up;
        }
        return null;
    }

    private int[] getXYPos(int pos){
        int columns = getNumColumns();
        int y = pos/columns;
        int x = pos%columns - 1;
        return new int[]{x,y};
    }

    /**
     * Maps a point to a position in the list.
     *
     * @param x X in local coordinate
     * @param y Y in local coordinate
     * @return The position of the item which contains the specified point, or
     *         {@link #INVALID_POSITION} if the point does not intersect an item.
     */
    public int pointToPosition(int x, int y) {
        Rect frame = mTouchFrame;
        if (frame == null) {
            mTouchFrame = new Rect();
            frame = mTouchFrame;
        }

        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;
    }

    /**
     * Equivalent to {@link #setAdapter(android.widget.ListAdapter)}
     */
    public void setAdapter(DynamicGridAdapter<?> adapter) {
        this.setAdapter((ListAdapter)adapter);
    }

    @Override
    public DynamicGridAdapter<?> getAdapter() {
        return (DynamicGridAdapter)super.getAdapter();
    }

    private static void log(String format, Object... args){
        String formatted = String.format(format, args);
        Log.d(TAG, formatted);
    }

    public interface OnDragListener {

        /**
         * Called when a drag operation is started
         *
         * @param pos the position where the drag operation was started
         */
        public void onDragStarted(int pos);

        /**
         * This method is called while the user is dragging the view around
         *
         * @param initalPosition the position in the adapter where the drag operation was started
         * @param initial the initial motion event that triggered the drag operation
         * @param current the current motion event
         */
        public void onDragged(int initalPosition, MotionEvent initial, MotionEvent current);
    }

    public interface OnDropListener {

        /**
         * Called when a dragged item is dropped
         *
         * @param from the original position where the item drag was started
         * @param to the final position where the item was dropped
         */
        public void onDrop(int from, int to);
    }

    /**
     * Implementation of OnDragListener that simply logs the methods
     */
    public static class DefOnDragListener implements OnDragListener{
        @Override
        public void onDragStarted(int pos) {
            log("Drag started at %d ", pos);
        }

        @Override
        public void onDragged(int pos, MotionEvent initial, MotionEvent current) {
            log("Dragging from %d to (%.2f, %.2f)", pos, current.getX(), current.getY());
        }
    }

    /**
     * Implementation of OnDropListener that simply logs the methods
     */
    public static class DefOnDropListener implements OnDropListener {
        @Override
        public void onDrop(int from, int to) {
            log("Dropped from %d to %d", from, to);
        }
    }

    public static enum SwapDirection{
        left, up, right, down
    }

}




Java Source Code List

com.authy.dynamicgridview.ApplicationTest.java
com.authy.dynamicgridview.DragView.java
com.authy.dynamicgridview.DynamicGridAdapter.java
com.authy.dynamicgridview.DynamicGridView.java
com.authy.dynamicgridview.ScrollDirection.java
com.authy.dynamicgridview.SwapHistory.java
com.authy.dynamicgridview.TestActivity.java