网络上关于GridView可拖动的例子已经不少了,包括带动画不带动画的都有一堆,但几乎都是通过继承Android原生控件GridView来扩展的,当然这种实现方式是很容易联想到的,也是最容易实现的。我随便百度了一下,就有一个:http://zhangcb666.blog.163.com/blog/static/4696352920124221043837/,大家可以参考一下,我这里就不赘述了。
今天跟大家分享另外一种方式,通过继承ViewGroup来实现,我们都知道,ViewGroup可以填充很多个View,因此,我觉得可以类似把GridView的每一个Item填充到我们自定义的ViewGroup中,然后监听长按时间,实现拖动的效果,同时加上动画效果,个人感觉比网上其他实现方式更加简洁和美观,唯一的缺点就是:没有setAdapter的函数,添加的item,需要我们手动add到ViewGroup中,如果item不是特别复杂和繁多,个人觉得也不算什么问题。好了,废话不多说,我们先来看看效果图,第一张是静态效果,第二张是拖动时的效果图。
其实代码也是很简单的,总共就两个类:一个自定义控件DragGridView,还有一个使用的例子MainActivity。
我们先来看看DragGridView的代码部分:
- /**
- * 另外一种方式实现动画可拖动item的GridView
- *
- * @author way
- *
- */
- public class DragGridView extends ViewGroup implements View.OnTouchListener,
- View.OnClickListener, View.OnLongClickListener {
- // layout vars
- public static float childRatio = .9f;
- protected int colCount, childSize, padding, dpi, scroll = 0;
- protected float lastDelta = 0;
- protected Handler handler = new Handler();
- // dragging vars
- protected int dragged = –1, lastX = –1, lastY = –1, lastTarget = –1;
- protected boolean enabled = true, touching = false;
- // anim vars
- public static int animT = 150;
- protected ArrayList<Integer> newPositions = new ArrayList<Integer>();
- // listeners
- protected OnRearrangeListener onRearrangeListener;
- protected OnClickListener secondaryOnClickListener;
- private OnItemClickListener onItemClickListener;
- /**
- * 拖动item的接口
- */
- public interface OnRearrangeListener {
- public abstract void onRearrange(int oldIndex, int newIndex);
- }
- // CONSTRUCTOR AND HELPERS
- public DragGridView(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;
- }
- protected void setListeners() {
- setOnTouchListener(this);
- super.setOnClickListener(this);
- setOnLongClickListener(this);
- }
- @Override
- public void setOnClickListener(OnClickListener l) {
- secondaryOnClickListener = l;
- }
- protected Runnable updateTask = new Runnable() {
- public void run() {
- if (dragged != –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);
- }
- };
- @Override
- public void addView(View child) {
- super.addView(child);
- newPositions.add(-1);
- };
- @Override
- public void removeViewAt(int index) {
- super.removeViewAt(index);
- newPositions.remove(index);
- };
- // LAYOUT
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- // compute width of view, in dp
- float w = (r – l) / (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 = (r – l) / colCount;
- childSize = Math.round(childSize * childRatio);
- padding = ((r – l) – (childSize * colCount)) / (colCount + 1);
- for (int i = 0; i < getChildCount(); i++)
- if (i != dragged) {
- 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 (dragged == –1)
- return i;
- else if (i == childCount – 1)
- return dragged;
- else if (i >= dragged)
- 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;
- }
- 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 (dragged < target)
- return target – 1;
- // Toast.makeText(getContext(), “Target: ” + target + “.”,
- // Toast.LENGTH_SHORT).show();
- return target;
- }
- 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 (enabled) {
- if (secondaryOnClickListener != null)
- secondaryOnClickListener.onClick(view);
- if (onItemClickListener != null && getLastIndex() != –1)
- onItemClickListener.onItemClick(null,
- getChildAt(getLastIndex()), getLastIndex(),
- getLastIndex() / colCount);
- }
- }
- public boolean onLongClick(View view) {
- if (!enabled)
- return false;
- int index = getLastIndex();
- if (index != –1) {
- dragged = index;
- animateDragged();
- return true;
- }
- return false;
- }
- public boolean onTouch(View view, MotionEvent event) {
- int action = event.getAction();
- switch (action & MotionEvent.ACTION_MASK) {
- case MotionEvent.ACTION_DOWN:
- enabled = true;
- lastX = (int) event.getX();
- lastY = (int) event.getY();
- touching = true;
- break;
- case MotionEvent.ACTION_MOVE:
- int delta = lastY – (int) event.getY();
- if (dragged != –1) {
- // change draw location of dragged visual
- int x = (int) event.getX(), y = (int) event.getY();
- int l = x – (3 * childSize / 4), t = y – (3 * childSize / 4);
- getChildAt(dragged).layout(l, t, l + (childSize * 3 / 2),
- t + (childSize * 3 / 2));
- // check for new target hover
- int target = getTargetFromCoor(x, y);
- if (lastTarget != target) {
- if (target != –1) {
- animateGap(target);
- lastTarget = target;
- }
- }
- } else {
- scroll += delta;
- clampScroll();
- if (Math.abs(delta) > 2)
- enabled = false;
- onLayout(true, getLeft(), getTop(), getRight(), getBottom());
- }
- lastX = (int) event.getX();
- lastY = (int) event.getY();
- lastDelta = delta;
- break;
- case MotionEvent.ACTION_UP:
- if (dragged != –1) {
- View v = getChildAt(dragged);
- if (lastTarget != –1)
- reorderChildren();
- else {
- Point xy = getCoorFromIndex(dragged);
- v.layout(xy.x, xy.y, xy.x + childSize, xy.y + childSize);
- }
- v.clearAnimation();
- if (v instanceof ImageView)
- ((ImageView) v).setAlpha(255);
- lastTarget = –1;
- dragged = –1;
- }
- touching = false;
- break;
- }
- if (dragged != –1)
- return true;
- return false;
- }
- // EVENT HELPERS
- protected void animateDragged() {
- View v = getChildAt(dragged);
- int x = getCoorFromIndex(dragged).x + childSize / 2, y = getCoorFromIndex(dragged).y
- + childSize / 2;
- int l = x – (3 * childSize / 4), t = y – (3 * childSize / 4);
- v.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);
- v.clearAnimation();
- v.startAnimation(animSet);
- }
- protected void animateGap(int target) {
- for (int i = 0; i < getChildCount(); i++) {
- View v = getChildAt(i);
- if (i == dragged)
- continue;
- int newPos = i;
- if (dragged < target && i >= dragged + 1 && i <= target)
- newPos–;
- else if (target < dragged && i >= target && i < dragged)
- newPos++;
- // animate
- int oldPos = i;
- if (newPositions.get(i) != –1)
- oldPos = newPositions.get(i);
- if (oldPos == newPos)
- continue;
- Point oldXY = getCoorFromIndex(oldPos);
- Point newXY = getCoorFromIndex(newPos);
- Point oldOffset = new Point(oldXY.x – v.getLeft(), oldXY.y
- – v.getTop());
- Point newOffset = new Point(newXY.x – v.getLeft(), newXY.y
- – v.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);
- v.clearAnimation();
- v.startAnimation(translate);
- newPositions.set(i, newPos);
- }
- }
- protected void reorderChildren() {
- // FIGURE OUT HOW TO REORDER CHILDREN WITHOUT REMOVING THEM ALL AND
- // RECONSTRUCTING THE LIST!!!
- if (onRearrangeListener != null)
- onRearrangeListener.onRearrange(dragged, lastTarget);
- ArrayList<View> children = new ArrayList<View>();
- for (int i = 0; i < getChildCount(); i++) {
- getChildAt(i).clearAnimation();
- children.add(getChildAt(i));
- }
- removeAllViews();
- while (dragged != lastTarget)
- if (lastTarget == children.size()) // dragged and dropped to the
- // right of the last element
- {
- children.add(children.remove(dragged));
- dragged = lastTarget;
- } else if (dragged < lastTarget) // shift to the right
- {
- Collections.swap(children, dragged, dragged + 1);
- dragged++;
- } else if (dragged > lastTarget) // shift to the left
- {
- Collections.swap(children, dragged, dragged – 1);
- dragged–;
- }
- for (int i = 0; i < children.size(); i++) {
- newPositions.set(i, –1);
- addView(children.get(i));
- }
- onLayout(true, getLeft(), getTop(), getRight(), getBottom());
- }
- 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;
- }
- }
然后是在布局文件中声明:main.xml
- <?xml version=“1.0” encoding=“utf-8”?>
- <RelativeLayout xmlns:android=“http://schemas.android.com/apk/res/android”
- android:layout_width=“fill_parent”
- android:layout_height=“fill_parent” >
- <com.way.view.DragGridView
- android:id=“@+id/vgv”
- android:layout_width=“fill_parent”
- android:layout_height=“fill_parent”
- android:layout_alignParentLeft=“true”
- android:layout_alignParentTop=“true” />
- <Button
- android:id=“@+id/add_item_btn”
- android:layout_width=“wrap_content”
- android:layout_height=“wrap_content”
- android:layout_alignParentBottom=“true”
- android:layout_alignParentLeft=“true”
- android:text=“@string/button1Text” />
- <Button
- android:id=“@+id/view_poem_item”
- android:layout_width=“wrap_content”
- android:layout_height=“wrap_content”
- android:layout_alignParentBottom=“true”
- android:layout_toRightOf=“@+id/add_item_btn”
- android:text=“@string/button2Text” />
- </RelativeLayout>
最后就可以直接在代码中调用了MainActivity:
- /**
- * MainActivity
- *
- * @author way
- *
- */
- public class MainActivity extends Activity {
- static Random random = new Random();
- static String[] words = “我 是 一 只 大 笨 猪”.split(” “);
- DragGridView mDragGridView;
- Button mAddBtn, mViewBtn;
- ArrayList<String> poem = new ArrayList<String>();
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- mDragGridView = ((DragGridView) findViewById(R.id.vgv));
- mAddBtn = ((Button) findViewById(R.id.add_item_btn));
- mViewBtn = ((Button) findViewById(R.id.view_poem_item));
- setListeners();
- }
- private void setListeners() {
- mDragGridView.setOnRearrangeListener(new OnRearrangeListener() {
- public void onRearrange(int oldIndex, int newIndex) {
- String word = poem.remove(oldIndex);
- if (oldIndex < newIndex)
- poem.add(newIndex, word);
- else
- poem.add(newIndex, word);
- }
- });
- mDragGridView.setOnItemClickListener(new OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
- long arg3) {
- mDragGridView.removeViewAt(arg2);
- poem.remove(arg2);
- }
- });
- mAddBtn.setOnClickListener(new OnClickListener() {
- public void onClick(View arg0) {
- String word = words[random.nextInt(words.length)];
- ImageView view = new ImageView(MainActivity.this);
- view.setImageBitmap(getThumb(word));
- mDragGridView.addView(view);
- poem.add(word);
- }
- });
- mViewBtn.setOnClickListener(new OnClickListener() {
- public void onClick(View arg0) {
- String finishedPoem = “”;
- for (String s : poem)
- finishedPoem += s + ” “;
- new AlertDialog.Builder(MainActivity.this).setTitle(“这是你选择的”)
- .setMessage(finishedPoem).show();
- }
- });
- }
- private Bitmap getThumb(String s) {
- Bitmap bmp = Bitmap.createBitmap(150, 150, Bitmap.Config.RGB_565);
- Canvas canvas = new Canvas(bmp);
- Paint paint = new Paint();
- paint.setColor(Color.rgb(random.nextInt(128), random.nextInt(128),
- random.nextInt(128)));
- paint.setTextSize(24);
- paint.setFlags(Paint.ANTI_ALIAS_FLAG);
- canvas.drawRect(new Rect(0, 0, 150, 150), paint);
- paint.setColor(Color.WHITE);
- paint.setTextAlign(Paint.Align.CENTER);
- canvas.drawText(s, 75, 75, paint);
- return bmp;
- }
- }
原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/5918.html