All computer source code presented on this page, unless it includes attribution to another author, is provided by Ed Halley under the Artistic License. Use such code freely and without any expectation of support. I would like to know if you make anything cool with the code, or need questions answered.
python/
    bindings.py
    boards.py
    buzz.py
    caches.py
    cards.py
    constraints.py
    csql.py
    english.py
    getch.py
    getopts.py
    gizmos.py
    goals.py
    improv.py
    interpolations.py
    namespaces.py
    nihongo.py
    nodes.py
    octalplus.py
    patterns.py
    physics.py
    pids.py
    pieces.py
    quizzes.py
    recipes.py
    relays.py
    romaji.py
    ropen.py
    sheets.py
    stores.py
    strokes.py
    subscriptions.py
    svgbuild.py
    testing.py
    things.py
    timing.py
    ucsv.py
    useful.py
    uuid.py
    vectors.py
    weighted.py
java/
    CSVReader.java
    CSVWriter.java
    GlobFilenameFilter.java
    RegexFilenameFilter.java
    StringBufferOutputStream.java
    ThreadSet.java
    Throttle.java
    TracingThread.java
    Utf8ConsoleTest.java
    droid/
        ArrangeViewsTouchListener.java
        DownloadFileTask.java
perl/
    CVQM.pm
    Kana.pm
    Typo.pm
cxx/
    CCache.h
    equalish.cpp
Download ArrangeViewsTouchListener.java
/*
**********
**
** Copyright (C) 2010 Ed Halley
** http://halley.cc/ed/
**
** Adapted and expanded from a simpler example found on anddev.org by 'royiby':
** http://tinyurl.com/39apoad
**
**********
*/

package cc.halley.droid;

import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnTouchListener;
import android.widget.FrameLayout;

/**
 * Allow the user to drag and drop views within their parent FrameLayout area.
 *
 * To use this, create a FrameLayout and add some child views.  Create an
 * instance of this class, and set it as the TouchListener for any views
 * that should allow the user to drag them.
 */
public class ArrangeViewsTouchListener
    implements OnTouchListener
{
    static final int DRAG_THRESHOLD = 10; // px -> should use dips
    static final int FLING_THRESHOLD_VELOCITY = 100;

    boolean dragging = false;
    boolean flinging = false;
    int hanchor = 0; int vanchor = 0;
    int hoffset = 0; int voffset = 0;
    int hrecent = 0; int vrecent = 0;

    /**
     * Override if a child view has some reason to refuse dragging even after
     * having this touch listener attached.  May check the view's getID or
     * dynamic state to decide if drag support is allowed or denied.
     * @param v the view to be considered for dragging
     * @return true if the view is intended for rearranging ability
     */
    public boolean isDraggable(View v)
    {
        return true;
    }

    /**
     * Prepare a view for dragging.  By default, the view is raised to the
     * top of the stacking order, but an override could resize the view to
     * appear slightly larger as it is dragged.
     * @param v the view being dragged
     * @param x the horizontal location of the touch, relative to the parent
     * @param y the vertical location of the touch, relative to the parent
     */
    public void raiseView(View v, int x, int y)
    {
        ViewGroup parent = (ViewGroup)(v.getParent());
        parent.bringChildToFront(v);
        v.clearAnimation();
    }

    /**
     * Prepare a view no longer being dragged.  By default, nothing is done,
     * but an override could resize the view back to its original size.
     * @param v the view now being dropped
     * @param x the horizontal location of the touch, relative to the parent
     * @param y the vertical location of the touch, relative to the parent
     */
    public void lowerView(View v, int x, int y)
    {
    }

    /**
     * Prepare a view no longer being dragged, but released at high velocity.
     * By default, nothing is done, but an override could let the view continue
     * to slide all the way out of view or fade out.
     * @param v the view now being flung
     * @param x the horizontal location of the touch, relative to the parent
     * @param y the vertical location of the touch, relative to the parent
     */
    public void flingView(View v, int x, int y)
    {
    }

    /**
     * Activate any touch-only behavior on a view that was tapped.
     * By default, calls the built-in performClick() method on the view.
     * @param v the view that was touched
     */
    public void touchView(View v)
    {
        v.performClick();
    }

    /**
     * Reposition a view to a new location mid-drag or at the end of a drag.
     * By default, simply adjusts the top left margins to cause the move, and
     * avoids letting the dragged view go out of the bounds of the parent area.
     * @param v the view being dragged
     * @param x the horizontal location of the left edge of this view
     * @param y the vertical location of the top edge of this view
     */
    public void moveView(View v, int x, int y)
    {
        ViewGroup.LayoutParams params = v.getLayoutParams();
        if (params instanceof FrameLayout.LayoutParams)
        {
            FrameLayout.LayoutParams par = (FrameLayout.LayoutParams)params;

            // to support neat layout, like aligning into
            // grids or against other edges, now is a good
            // time to adjust x and y accordingly

            // don't allow view to mash against a border or go past it
            View parent = (View)(v.getParent());
            x = Math.min(x, parent.getWidth() - v.getWidth());
            x = Math.max(x, 0);
            y = Math.min(y, parent.getHeight() - v.getHeight());
            y = Math.max(y, 0);

            par.leftMargin = x;
            par.topMargin = y;
            v.setLayoutParams(par);
        }
    }

    /**
     * The actual touch event handling.
     * If the user starts a touch, we watch for a sufficient movement before
     * we consider the touch to be a dragging gesture.  Once dragging, we raise
     * the view, move the view, and lower it when it is released.  If the touch
     * is released without moving sufficiently, we try to "click" the view.
     * (Yes, you can "drag" a button view but also click it with a plain tap.)
     */
    public boolean onTouch(View v, MotionEvent event)
    {
        int x = (int)event.getRawX();
        int y = (int)event.getRawY();
        if (isDraggable(v))
        {
            switch (event.getAction())
            {
            case MotionEvent.ACTION_DOWN:
                dragging = false;
                hanchor = hrecent = x;
                vanchor = vrecent = y;
                hoffset = x - v.getLeft();
                voffset = y - v.getTop();
                break;

            case MotionEvent.ACTION_MOVE:
                if (!dragging)
                {
                    if (Math.abs(x - hanchor) > DRAG_THRESHOLD)
                        dragging = true;
                    if (Math.abs(y - vanchor) > DRAG_THRESHOLD)
                        dragging = true;
                    raiseView(v, x - hoffset, y - voffset);
                }
                if (!flinging)
                {
                    int vsq = (x-hrecent)*(x-hrecent) +
                              (y-vrecent)*(y-vrecent);
                    int thresh = FLING_THRESHOLD_VELOCITY;
                    thresh *= thresh;
                    if (vsq >= thresh)
                        flinging = true;
                }
                if (dragging)
                    moveView(v, x - hoffset, y - voffset);
                hrecent = x;
                vrecent = y;
                break;

            case MotionEvent.ACTION_UP:
                if (dragging)
                {
                    moveView(v, x - hoffset, y - voffset);
                    if (flinging)
                        flingView(v, x - hoffset, y - voffset);
                    else
                        lowerView(v, x - hoffset, y - voffset);
                    dragging = flinging = false;
                }
                else
                {
                    flinging = false;
                    touchView(v);
                }
                break;
            }
        }
        return true;
    }
}


Contact Ed Halley by email at ed@halley.cc.
Text, code, layout and artwork are Copyright © 1996-2013 Ed Halley.
Copying in whole or in part, with author attribution, is expressly allowed.
Any references to trademarks are illustrative and are controlled by their respective owners.
Make donations with PayPal - it's fast, free and secure!