DraggableGridView可拖动的GridView

来源:互联网 发布:淘宝店铺不交保证金 编辑:程序博客网 时间:2024/06/06 02:50
//TO DO://// - improve timer performance (especially on Eee Pad)// - improve child rearrangingpackage com.animoto.android.views;import android.app.Activity;import android.content.Context;import android.graphics.Point;import android.os.Handler;import android.os.SystemClock;import android.util.AttributeSet;import android.util.DisplayMetrics;import android.util.Log;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.view.animation.*;import android.widget.AdapterView.OnItemClickListener;import android.widget.ImageView;import java.util.ArrayList;import java.util.Collections;import java.util.List;public class DraggableGridView extends ViewGroup implements View.OnTouchListener, View.OnClickListener, View.OnLongClickListener {    private static final String TAG = "DraggableGridView";    //layout vars    public static float childRatio = .9f;    //anim vars    public static int animT = 150;    protected int colCount;    protected int childSize;    protected int padding;    protected int dpi;    protected int scroll = 0;    protected float lastDelta = 0;    protected Handler handler = new Handler();    /**     * 正在拖动的项目index     */    protected int mDragged = -1;    //dragging vars  begin  +++++++++++++++++++++++++++++++++++++++++++    protected int lastX = -1;    protected int lastY = -1;    protected int mLastTarget = -1;    protected boolean mEnabled = true;    protected boolean touching = false;    //dragging vars  end    +++++++++++++++++++++++++++++++++++++++++++    protected ArrayList<Integer> mNewPositions = new ArrayList<Integer>();    //listeners    protected OnRearrangeListener onRearrangeListener;    protected OnClickListener secondaryOnClickListener;    protected Runnable updateTask = new Runnable() {        public void run() {            if (mDragged != -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);        }    };    /**     * 不可更改的item     */    private List<Integer> mImmutableItemIndex = new ArrayList<Integer>();    private OnItemClickListener onItemClickListener;    //CONSTRUCTOR AND HELPERS    public DraggableGridView(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;    }    public void setImmutableItems(Integer... indexs) {        for (Integer index : indexs) {            mImmutableItemIndex.add(index);        }    }    protected void setListeners() {        setOnTouchListener(this);        super.setOnClickListener(this);        setOnLongClickListener(this);    }    @Override    public void setOnClickListener(OnClickListener l) {        secondaryOnClickListener = l;    }    //OVERRIDES    @Override    public void addView(View child) {        super.addView(child);        mNewPositions.add(-1);    }    ;    @Override    public void removeViewAt(int index) {        super.removeViewAt(index);        mNewPositions.remove(index);    }    ;    //LAYOUT    @Override    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {        //compute width of view, in dp        float w = (right - left) / (dpi / 160f);        //determine number of columns, at least 2        colCount = 2;        int sub = 240;        w -= 280;        while (w > 0) {            colCount++;            w -= sub;            sub += 40;        }        //determine childSize and padding, in px        childSize = (right - left) / colCount;        childSize = Math.round(childSize * childRatio);        padding = ((right - left) - (childSize * colCount)) / (colCount + 1);        for (int i = 0; i < getChildCount(); i++)            if (i != mDragged) {                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 (mDragged == -1)            return i;        else if (i == childCount - 1)            return mDragged;        else if (i >= mDragged)            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) //touch is between columns or rows            return -1;        int index = row * colCount + col;        if (index >= getChildCount())            return -1;        return index;    }    /**     * 根据所在区域,获取其所在行或列     *     * @param coor     * @return     */    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) //touch is between rows            return -1;        //if (getIndexFromCoor(x, y) != -1) //touch on top of another visual        //return -1;        int leftPos = getIndexFromCoor(x - (childSize / 4), y);        int rightPos = getIndexFromCoor(x + (childSize / 4), y);        if (leftPos == -1 && rightPos == -1) //touch is in the middle of nowhere            return -1;        if (leftPos == rightPos) //touch is in the middle of a visual            return -1;        int target = -1;        if (rightPos > -1)            target = rightPos;        else if (leftPos > -1)            target = leftPos + 1;        if (mDragged < target)            return target - 1;        //Toast.makeText(getContext(), "Target: " + target + ".", Toast.LENGTH_SHORT).show();        return target;    }    /**     * 从所在的index,得到当前所在的区域     */    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;    }    //EVENT HANDLERS    public void onClick(View view) {        if (mEnabled) {            if (secondaryOnClickListener != null)                secondaryOnClickListener.onClick(view);            if (onItemClickListener != null && getLastIndex() != -1)                onItemClickListener.onItemClick(null, getChildAt(getLastIndex()), getLastIndex(), getLastIndex() / colCount);        }    }    /**     * 判断是否是  不可更改的     */    private boolean isImmutable(int index) {        if (mImmutableItemIndex == null || mImmutableItemIndex.size() == 0) {            return false;        }        if (mImmutableItemIndex.contains(index)) {            return true;        } else {            return false;        }    }    public boolean onLongClick(View view) {        if (!mEnabled)            return false;        int index = getLastIndex();        if (index != -1) {            Log.d(TAG, "长按的index" + index);            if (!isImmutable(index)) {                mDragged = index;                animateDragged();                return true;            }            return false;        }        return false;    }    public boolean onTouch(View view, MotionEvent event) {        int action = event.getAction();        switch (action & MotionEvent.ACTION_MASK) {            case MotionEvent.ACTION_DOWN:                mEnabled = true;                lastX = (int) event.getX();                lastY = (int) event.getY();                touching = true;                break;            case MotionEvent.ACTION_MOVE:                int delta = lastY - (int) event.getY();                if (mDragged != -1) {                    //拖动了                    //change draw location of ddragged visual                    int x = (int) event.getX();                    int y = (int) event.getY();                    int left = x - (3 * childSize / 4);                    int top = y - (3 * childSize / 4);                    getChildAt(mDragged).layout(left, top, left + (childSize * 3 / 2), top + (childSize * 3 / 2));                    //check for new target hover                    int target = getTargetFromCoor(x, y);                    Log.d(TAG, "target>>>" + target);                    if (mLastTarget != target) {                        if (target != -1) {                            animateGap(target);                        }                    }                    Log.d(TAG, "target>>" + target);                    Log.d(TAG, "lastTargets>>" + mLastTarget);                } else {                    scroll += delta;                    clampScroll();                    if (Math.abs(delta) > 2)                        mEnabled = false;                    onLayout(true, getLeft(), getTop(), getRight(), getBottom());                }                lastX = (int) event.getX();                lastY = (int) event.getY();                lastDelta = delta;                break;            case MotionEvent.ACTION_UP:                if (mDragged != -1) {                    View v = getChildAt(mDragged);                    if (mLastTarget != -1)                        reorderChildren();                    else {                        Point xy = getCoorFromIndex(mDragged);                        v.layout(xy.x, xy.y, xy.x + childSize, xy.y + childSize);                    }                    v.clearAnimation();                    if (v instanceof ImageView)                        ((ImageView) v).setAlpha(255);                    mLastTarget = -1;                    mDragged = -1;                }                touching = false;                break;        }        if (mDragged != -1)            return true;        return false;    }    //EVENT HELPERS    protected void animateDragged() {        View draggingView = getChildAt(mDragged);        int x = getCoorFromIndex(mDragged).x + childSize;        int y = getCoorFromIndex(mDragged).y + childSize / 2;        int l = x - (3 * childSize / 4);        int t = y - (3 * childSize / 4);        draggingView.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);        draggingView.clearAnimation();        draggingView.startAnimation(animSet);    }    /**     * 动态排列视图的顺序     */    protected void animateGap(int target) {        mLastTarget = target;        for (int i = 0; i < getChildCount(); i++) {            View childrenView = getChildAt(i);            if (i == mDragged || isImmutable(i))                continue;            int newPos = i;            if (mDragged < target && i >= mDragged + 1 && i <= target)                newPos--;            else if (target < mDragged && i >= target && i < mDragged)                newPos++;            //animate            int oldPos = i;            if (mNewPositions.get(i) != -1)                oldPos = mNewPositions.get(i);            //如果当前位置和上次位置一样,则不处理            if (oldPos == newPos )                continue;            //yee            if (isImmutable(newPos)) {                if (newPos > i) {                    newPos++;                }else if (newPos < i) {                    newPos--;                }            }            Point oldXY = getCoorFromIndex(oldPos);            Point newXY = getCoorFromIndex(newPos);            Point oldOffset = new Point(oldXY.x - childrenView.getLeft(), oldXY.y - childrenView.getTop());            Point newOffset = new Point(newXY.x - childrenView.getLeft(), newXY.y - childrenView.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);            childrenView.clearAnimation();            childrenView.startAnimation(translate);            mNewPositions.set(i, newPos);        }    }    /**     * 动画结束后,重新排列item(将视图数据列表中的位置更改)     */    protected void reorderChildren() {        //FIGURE OUT HOW TO REORDER CHILDREN WITHOUT REMOVING THEM ALL AND RECONSTRUCTING THE LIST!!!//        if (onRearrangeListener != null)//            onRearrangeListener.onRearrange(mDragged, dlastTarget);        if (isImmutable(mLastTarget) || isImmutable(mDragged)) {            return;        }        ArrayList<View> children = new ArrayList<View>();        for (int i = 0; i < getChildCount(); i++) {            getChildAt(i).clearAnimation();            children.add(getChildAt(i));        }        removeAllViews();        while (mDragged != mLastTarget){            if (mLastTarget == children.size()) {                // ddragged and dropped to the right of the last element                children.add(children.remove(mDragged));                mDragged = mLastTarget;            } else if (mDragged < mLastTarget) {                // shift to the right                swapWithNext(children, mDragged, 1);            } else if (mDragged > mLastTarget) {                swapWithPrev(children, mDragged, 1);            }            if (mDragged < 0) {                break;            }        }        for (int i = 0; i < children.size(); i++) {            mNewPositions.set(i, -1);            addView(children.get(i));        }        onLayout(true, getLeft(), getTop(), getRight(), getBottom());    }    private void swapWithNext(ArrayList<View> childrenViews,int itemIndex, int offset) {        if (isImmutable(itemIndex + offset)) {            offset++;            swapWithNext(childrenViews, mDragged, offset);            return;        }        swap(childrenViews, itemIndex, itemIndex + offset);        for (int i = 0; i < offset; i++) {            mDragged++;        }    }    private void swapWithPrev(ArrayList<View> childrenViews,int itemIndex, int offset) {        if (isImmutable(itemIndex - offset) && (itemIndex - offset) >= 0) {            offset++;            swapWithPrev(childrenViews, mDragged, offset);            return;        }        swap(childrenViews, itemIndex, itemIndex - offset);        for (int i = 0; i < offset; i++) {            mDragged--;        }    }    private void swap(ArrayList<View> childrenViews, int firstItem, int secondItem) {        int childViewSize = childrenViews.size();        if (firstItem < 0 || secondItem < 0) {            Log.d("swap", "first>" + firstItem + "; second>>" + secondItem);            return;        }        if (firstItem >= childViewSize || secondItem >= childViewSize) {            Log.d("swap", "size>>" + childViewSize + ";然而first>" + firstItem + "; second>>" + secondItem);            return;        }        Collections.swap(childrenViews, firstItem, secondItem);        if (onRearrangeListener != null)            onRearrangeListener.onRearrange(firstItem, secondItem);    }    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);    }    //OTHER METHODS    public void setOnRearrangeListener(OnRearrangeListener l) {        this.onRearrangeListener = l;    }    public void setOnItemClickListener(OnItemClickListener l) {        this.onItemClickListener = l;    }}
0 0
原创粉丝点击