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
- DraggableGridView可拖动的GridView
- DraggableGridView可拖动的GridView
- 可拖动重排GridView
- Android之ViewGroup实现可拖动的GridView
- Android之ViewGroup实现可拖动的GridView
- Android之ViewGroup实现可拖动的GridView
- Android之ViewGroup实现可拖动的GridView
- Android之ViewGroup实现可拖动的GridView
- 可拖动GridView的实现,类似支付宝界面
- android 新闻栏目管理(可拖动排序的gridview)
- android 自定义View开发实战(六) 可拖动的GridView
- Android自定义GridView之仿支付宝首页可拖动、可删除的九宫格
- Android自定义GridView之仿支付宝首页可拖动、可删除的九宫格
- 可拖动排序ListView和GridView
- 仿照支付宝可拖动gridview
- android可拖动排序GridView实现
- 可以拖动的GridView
- 可拖动的DIV
- ubuntu 重新安装mysql
- Objective-C中的@property和@synthesize用法
- 怎么计算两个日期之间的差值
- POJ 3615 Cow Hurdles //Floyd算法
- 要看的书单
- DraggableGridView可拖动的GridView
- java EE之jsp注释、声明以及输出jsp表达式 复习
- Linux 内存管理之 mmap 解析(二)
- Uva10859 - Placing Lampposts
- 基数排序
- CMake简介及使用实例
- 1220 数字三角形(4解)
- 今天心情真不好啊。
- loadrunner 11 录制脚本时提示IE浏览器已停止工作