您当前的位置: 首页 > 

xiangzhihong8

暂无认证

  • 3浏览

    0关注

    1324博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

gradeview可拖动效果实现

xiangzhihong8 发布时间:2014-05-08 18:32:56 ,浏览量:3

下面先上这次实现功能的效果图:(注:这个效果图没有拖拽的时候移动动画,DEMO里面有,可以下载看看)

一、开发心里历程

刚开始接触这个的时候,不知道要如何实现,去网上翻了一大堆资料,懂了个大概,就是目前可以找到的都是拖拽的时候,不带移动动画的,和线上的客户端交互效果相差甚远,在反反复复的尝试查看相关东西,大致的做了出来,目前在模拟器上似乎有一点小BUG,真机测试没有问题,就先放上来,如果发现问题在修改优化。代码反面,没有好好的修改调整,可能会有点乱,请见谅哈。

二、开发前的准备

1.了解重写View的相关知识,并且知道GridView的一些内部方法,如:怎么通过触摸的坐标获取对应的position等(这里我采用的是继承GridView控件)

2.了解屏幕触摸动作传递原理    这里我以前转载的一篇或许会有帮助:Android事件分发机制完全解析,带你从源码的角度彻底理解(全)

3.了解位移动画Animation,本DEMO中主要用到:TranslateAnimation  平移动画

4.了解WindowManager的窗口机制,这里的item拖拽等都要设计到这个。

5.了解SQLiteDatabase 以及SQLiteOpenHelper等数据库操作相关的类,本DEMO中主要用到数据库进行存储频道信息,如果你要用文档进行存储读取也可以。

三、开发思路

1.  获取数据库中频道的列表,如果为空,赋予默认列表,并存入数据库,之后通过对应的适配器赋给对应的GridView

2.  2个GridView--(1.DragGrid   2. OtherGridView)

DragGrid 用于显示我的频道,带有长按拖拽效果

OtherGridView用于显示更多频道,不带推拽效果

注:由于屏幕大小不一定,外层使用ScrollView,所以2者都要重写计算高度

3.  点击2个GridView的时候,根据点击的Item对应的position,获取position对应的view,进行创建一层移动的动画层

起始位置:点击的positiongetLocationInWindow()获取。终点位置:另一个GridView的最后个ITEM 的position + 1的位置。

并赋予移动动画,等动画结束后对2者对应的频道列表进行数据的remove和add操作。

4.  设置点击和拖动的限制条件,如  推荐  这个ITEM是不允许用户操作的。

5.  拖动的DragGrid的操作:

(1)长按获取长按的ITEM的position  -- dragPosition 以及对应的view ,手指触摸屏幕的时候,调用onInterceptTouchEvent来获取MotionEvent.ACTION_DOWN事件,获取对应的数据。由于这里是继承了GridView,所以长按时间可以通过setOnItemLongClickListener监听来执行,或则你也可以通过计算点击时间来监听是否长按。

(2)通过onTouchEvent(MotionEvent ev)来监听手指的移动和抬起动作。当它移动到 其它的item下面,并且下方的item对应的position  不等于 dragPosition,进行数据交换,并且2者之间的所有item进行移动动画,动画结束后,数据更替刷新界面。

(3) 抬起手后,清除掉拖动时候创建的view,让GridView中的数据显示。

6.  退出时候,将改变后的频道列表存入数据库。

四、流程图

下面是大体的流程图:

五、核心代码
点击进行添加删除:
[java] view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /** GRIDVIEW对应的ITEM点击监听接口  */  
  2.     @Override  
  3.     public void onItemClick(AdapterView parent, final View view, final int position,long id) {  
  4.         //如果点击的时候,之前动画还没结束,那么就让点击事件无效  
  5.         if(isMove){  
  6.             return;  
  7.         }  
  8.         switch (parent.getId()) {  
  9.         case R.id.userGridView:  
  10.             //position为 0,1 的不可以进行任何操作  
  11.             if (position != 0 && position != 1) {  
  12.                 final ImageView moveImageView = getView(view);  
  13.                 if (moveImageView != null) {  
  14.                     TextView newTextView = (TextView) view.findViewById(R.id.text_item);  
  15.                     final int[] startLocation = new int[2];  
  16.                     newTextView.getLocationInWindow(startLocation);  
  17.                     final ChannelItem channel = ((DragAdapter) parent.getAdapter()).getItem(position);//获取点击的频道内容  
  18.                     otherAdapter.setVisible(false);  
  19.                     //添加到最后一个  
  20.                     otherAdapter.addItem(channel);  
  21.                     new Handler().postDelayed(new Runnable() {  
  22.                         public void run() {  
  23.                             try {  
  24.                                 int[] endLocation = new int[2];  
  25.                                 //获取终点的坐标  
  26.                                 otherGridView.getChildAt(otherGridView.getLastVisiblePosition()).getLocationInWindow(endLocation);  
  27.                                 MoveAnim(moveImageView, startLocation , endLocation, channel,userGridView);  
  28.                                 userAdapter.setRemove(position);  
  29.                             } catch (Exception localException) {  
  30.                             }  
  31.                         }  
  32.                     }, 50L);  
  33.                 }  
  34.             }  
  35.             break;  
  36.         case R.id.otherGridView:  
  37.             final ImageView moveImageView = getView(view);  
  38.             if (moveImageView != null){  
  39.                 TextView newTextView = (TextView) view.findViewById(R.id.text_item);  
  40.                 final int[] startLocation = new int[2];  
  41.                 newTextView.getLocationInWindow(startLocation);  
  42.                 final ChannelItem channel = ((OtherAdapter) parent.getAdapter()).getItem(position);  
  43.                 userAdapter.setVisible(false);  
  44.                 //添加到最后一个  
  45.                 userAdapter.addItem(channel);  
  46.                 new Handler().postDelayed(new Runnable() {  
  47.                     public void run() {  
  48.                         try {  
  49.                             int[] endLocation = new int[2];  
  50.                             //获取终点的坐标  
  51.                             userGridView.getChildAt(userGridView.getLastVisiblePosition()).getLocationInWindow(endLocation);  
  52.                             MoveAnim(moveImageView, startLocation , endLocation, channel,otherGridView);  
  53.                             otherAdapter.setRemove(position);  
  54.                         } catch (Exception localException) {  
  55.                         }  
  56.                     }  
  57.                 }, 50L);  
  58.             }  
  59.             break;  
  60.         default:  
  61.             break;  
  62.         }  
  63.     }  
移动动画:
[java] view plain copy 在CODE上查看代码片 派生到我的代码片
  1. private void MoveAnim(View moveView, int[] startLocation,int[] endLocation, final ChannelItem moveChannel,  
  2.             final GridView clickGridView) {  
  3.         int[] initLocation = new int[2];  
  4.         //获取传递过来的VIEW的坐标  
  5.         moveView.getLocationInWindow(initLocation);  
  6.         //得到要移动的VIEW,并放入对应的容器中  
  7.         final ViewGroup moveViewGroup = getMoveViewGroup();  
  8.         final View mMoveView = getMoveView(moveViewGroup, moveView, initLocation);  
  9.         //创建移动动画  
  10.         TranslateAnimation moveAnimation = new TranslateAnimation(  
  11.                 startLocation[0], endLocation[0], startLocation[1],  
  12.                 endLocation[1]);  
  13.         moveAnimation.setDuration(300L);//动画时间  
  14.         //动画配置  
  15.         AnimationSet moveAnimationSet = new AnimationSet(true);  
  16.         moveAnimationSet.setFillAfter(false);//动画效果执行完毕后,View对象不保留在终止的位置  
  17.         moveAnimationSet.addAnimation(moveAnimation);  
  18.         mMoveView.startAnimation(moveAnimationSet);  
  19.         moveAnimationSet.setAnimationListener(new AnimationListener() {  
  20.               
  21.             @Override  
  22.             public void onAnimationStart(Animation animation) {  
  23.                 isMove = true;  
  24.             }  
  25.               
  26.             @Override  
  27.             public void onAnimationRepeat(Animation animation) {  
  28.             }  
  29.               
  30.             @Override  
  31.             public void onAnimationEnd(Animation animation) {  
  32.                 moveViewGroup.removeView(mMoveView);  
  33.                 // instanceof 方法判断2边实例是不是一样,判断点击的是DragGrid还是OtherGridView  
  34.                 if (clickGridView instanceof DragGrid) {  
  35.                     otherAdapter.setVisible(true);  
  36.                     otherAdapter.notifyDataSetChanged();  
  37.                     userAdapter.remove();  
  38.                 }else{  
  39.                     userAdapter.setVisible(true);  
  40.                     userAdapter.notifyDataSetChanged();  
  41.                     otherAdapter.remove();  
  42.                 }  
  43.                 isMove = false;  
  44.             }  
  45.         });  
  46.     }  
可拖拽的DragGrid代码: 
[java] view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public class DragGrid extends GridView {  
  2.     /** 点击时候的X位置 */  
  3.     public int downX;  
  4.     /** 点击时候的Y位置 */  
  5.     public int downY;  
  6.     /** 点击时候对应整个界面的X位置 */  
  7.     public int windowX;  
  8.     /** 点击时候对应整个界面的Y位置 */  
  9.     public int windowY;  
  10.     /** 屏幕上的X */  
  11.     private int win_view_x;  
  12.     /** 屏幕上的Y */  
  13.     private int win_view_y;  
  14.     /** 拖动的里x的距离 */  
  15.     int dragOffsetX;  
  16.     /** 拖动的里Y的距离 */  
  17.     int dragOffsetY;  
  18.     /** 长按时候对应postion */  
  19.     public int dragPosition;  
  20.     /** Up后对应的ITEM的Position */  
  21.     private int dropPosition;  
  22.     /** 开始拖动的ITEM的Position */  
  23.     private int startPosition;  
  24.     /** item高 */  
  25.     private int itemHeight;  
  26.     /** item宽 */  
  27.     private int itemWidth;  
  28.     /** 拖动的时候对应ITEM的VIEW */  
  29.     private View dragImageView = null;  
  30.     /** 长按的时候ITEM的VIEW */  
  31.     private ViewGroup dragItemView = null;  
  32.     /** WindowManager管理器 */  
  33.     private WindowManager windowManager = null;  
  34.     /** */  
  35.     private WindowManager.LayoutParams windowParams = null;  
  36.     /** item总量 */  
  37.     private int itemTotalCount;  
  38.     /** 一行的ITEM数量 */  
  39.     private int nColumns = 4;  
  40.     /** 行数 */  
  41.     private int nRows;  
  42.     /** 剩余部分 */  
  43.     private int Remainder;  
  44.     /** 是否在移动 */  
  45.     private boolean isMoving = false;  
  46.     /** */  
  47.     private int holdPosition;  
  48.     /** 拖动的时候放大的倍数 */  
  49.     private double dragScale = 1.2D;  
  50.     /** 震动器 */  
  51.     private Vibrator mVibrator;  
  52.     /** 每个ITEM之间的水平间距 */  
  53.     private int mHorizontalSpacing = 15;  
  54.     /** 每个ITEM之间的竖直间距 */  
  55.     private int mVerticalSpacing = 15;  
  56.     /* 移动时候最后个动画的ID */  
  57.     private String LastAnimationID;  
  58.   
  59.     public DragGrid(Context context) {  
  60.         super(context);  
  61.         init(context);  
  62.     }  
  63.   
  64.     public DragGrid(Context context, AttributeSet attrs, int defStyle) {  
  65.         super(context, attrs, defStyle);  
  66.         init(context);  
  67.     }  
  68.   
  69.     public DragGrid(Context context, AttributeSet attrs) {  
  70.         super(context, attrs);  
  71.         init(context);  
  72.     }  
  73.   
  74.     public void init(Context context) {  
  75.         mVibrator = (Vibrator) context  
  76.                 .getSystemService(Context.VIBRATOR_SERVICE);  
  77.         // 将布局文件中设置的间距dip转为px  
  78.         mHorizontalSpacing = DataTools.dip2px(context, mHorizontalSpacing);  
  79.     }  
  80.   
  81.     @Override  
  82.     public boolean onInterceptTouchEvent(MotionEvent ev) {  
  83.         // TODO Auto-generated method stub  
  84.         if (ev.getAction() == MotionEvent.ACTION_DOWN) {  
  85.             downX = (int) ev.getX();  
  86.             downY = (int) ev.getY();  
  87.             windowX = (int) ev.getX();  
  88.             windowY = (int) ev.getY();  
  89.             setOnItemClickListener(ev);  
  90.         }  
  91.         return super.onInterceptTouchEvent(ev);  
  92.     }  
  93.   
  94.     @Override  
  95.     public boolean onTouchEvent(MotionEvent ev) {  
  96.         // TODO Auto-generated method stub  
  97.         boolean bool = true;  
  98.         if (dragImageView != null  
  99.                 && dragPosition != AdapterView.INVALID_POSITION) {  
  100.             // 移动时候的对应x,y位置  
  101.             bool = super.onTouchEvent(ev);  
  102.             int x = (int) ev.getX();  
  103.             int y = (int) ev.getY();  
  104.             switch (ev.getAction()) {  
  105.             case MotionEvent.ACTION_DOWN:  
  106.                 downX = (int) ev.getX();  
  107.                 windowX = (int) ev.getX();  
  108.                 downY = (int) ev.getY();  
  109.                 windowY = (int) ev.getY();  
  110.                 break;  
  111.             case MotionEvent.ACTION_MOVE:  
  112.                 onDrag(x, y, (int) ev.getRawX(), (int) ev.getRawY());  
  113.                 if (!isMoving) {  
  114.                     OnMove(x, y);  
  115.                 }  
  116.                 if (pointToPosition(x, y) != AdapterView.INVALID_POSITION) {  
  117.                     break;  
  118.                 }  
  119.                 break;  
  120.             case MotionEvent.ACTION_UP:  
  121.                 stopDrag();  
  122.                 onDrop(x, y);  
  123.                 requestDisallowInterceptTouchEvent(false);  
  124.                 break;  
  125.   
  126.             default:  
  127.                 break;  
  128.             }  
  129.         }  
  130.         return super.onTouchEvent(ev);  
  131.     }  
  132.   
  133.     /** 在拖动的情况 */  
  134.     private void onDrag(int x, int y, int rawx, int rawy) {  
  135.         if (dragImageView != null) {  
  136.             windowParams.alpha = 0.6f;  
  137.             windowParams.x = rawx - win_view_x;  
  138.             windowParams.y = rawy - win_view_y;  
  139.             windowManager.updateViewLayout(dragImageView, windowParams);  
  140.         }  
  141.     }  
  142.   
  143.     /** 在松手下放的情况 */  
  144.     private void onDrop(int x, int y) {  
  145.         // 根据拖动到的x,y坐标获取拖动位置下方的ITEM对应的POSTION  
  146.         int tempPostion = pointToPosition(x, y);  
  147.         dropPosition = tempPostion;  
  148.         DragAdapter mDragAdapter = (DragAdapter) getAdapter();  
  149.         // 显示刚拖动的ITEM  
  150.         mDragAdapter.setShowDropItem(true);  
  151.         // 刷新适配器,让对应的ITEM显示  
  152.         mDragAdapter.notifyDataSetChanged();  
  153.     }  
  154.   
  155.     /** 
  156.      * 长按点击监听 
  157.      * @param ev 
  158.      */  
  159.     public void setOnItemClickListener(final MotionEvent ev) {  
  160.         setOnItemLongClickListener(new OnItemLongClickListener() {  
  161.   
  162.             @Override  
  163.             public boolean onItemLongClick(AdapterView parent, View view,  
  164.                     int position, long id) {  
  165.                 int x = (int) ev.getX();// 长安事件的X位置  
  166.                 int y = (int) ev.getY();// 长安事件的y位置  
  167.                 startPosition = position;// 第一次点击的postion  
  168.                 dragPosition = position;  
  169.                 if (startPosition > 2,  
  170.                 MeasureSpec.AT_MOST);  
  171.         super.onMeasure(widthMeasureSpec, expandSpec);  
  172.     }  
  173.   
  174.     /** 隐藏 放下 的ITEM */  
  175.     private void hideDropItem() {  
  176.         ((DragAdapter) getAdapter()).setShowDropItem(false);  
  177.     }  
  178.   
  179.     /** 获取移动动画 */  
  180.     public Animation getMoveAnimation(float toXValue, float toYValue) {  
  181.         TranslateAnimation mTranslateAnimation = new TranslateAnimation(  
  182.                 Animation.RELATIVE_TO_SELF, 0.0F, Animation.RELATIVE_TO_SELF,  
  183.                 toXValue, Animation.RELATIVE_TO_SELF, 0.0F,  
  184.                 Animation.RELATIVE_TO_SELF, toYValue);// 当前位置移动到指定位置  
  185.         mTranslateAnimation.setFillAfter(true);// 设置一个动画效果执行完毕后,View对象保留在终止的位置。  
  186.         mTranslateAnimation.setDuration(300L);  
  187.         return mTranslateAnimation;  
  188.     }  
  189.   
  190.     /** 移动的时候触发 */  
  191.     public void OnMove(int x, int y) {  
  192.         // 拖动的VIEW下方的POSTION  
  193.         int dPosition = pointToPosition(x, y);  
  194.         // 判断下方的POSTION是否是最开始2个不能拖动的  
  195.         if (dPosition > 1) {  
  196.             if ((dPosition == -1) || (dPosition == dragPosition)) {  
  197.                 return;  
  198.             }  
  199.             dropPosition = dPosition;  
  200.             if (dragPosition != startPosition) {  
  201.                 dragPosition = startPosition;  
  202.             }  
  203.             int movecount;  
  204.             // 拖动的=开始拖的,并且 拖动的 不等于放下的  
  205.             if ((dragPosition == startPosition)  
  206.                     || (dragPosition != dropPosition)) {  
  207.                 // 移需要移动的动ITEM数量  
  208.                 movecount = dropPosition - dragPosition;  
  209.             } else {  
  210.                 // 移需要移动的动ITEM数量为0  
  211.                 movecount = 0;  
  212.             }  
  213.             if (movecount == 0) {  
  214.                 return;  
  215.             }  
  216.   
  217.             int movecount_abs = Math.abs(movecount);  
  218.   
  219.             if (dPosition != dragPosition) {  
  220.                 // dragGroup设置为不可见  
  221.                 ViewGroup dragGroup = (ViewGroup) getChildAt(dragPosition);  
  222.                 dragGroup.setVisibility(View.INVISIBLE);  
  223.                 float to_x = 1;// 当前下方positon  
  224.                 float to_y;// 当前下方右边positon  
  225.                 // x_vlaue移动的距离百分比(相对于自己长度的百分比)  
  226.                 float x_vlaue = ((float) mHorizontalSpacing / (float) itemWidth) + 1.0f;  
  227.                 // y_vlaue移动的距离百分比(相对于自己宽度的百分比)  
  228.                 float y_vlaue = ((float) mVerticalSpacing / (float) itemHeight) + 1.0f;  
  229.                 Log.d("x_vlaue", "x_vlaue = " + x_vlaue);  
  230.                 for (int i = 0; i  0) {  
  231.                         // 判断是不是同一行的  
  232.                         holdPosition = dragPosition + i + 1;  
  233.                         if (dragPosition / nColumns == holdPosition / nColumns) {  
  234.                             to_x = -x_vlaue;  
  235.                             to_y = 0;  
  236.                         } else if (holdPosition % 4 == 0) {  
  237.                             to_x = 3 * x_vlaue;  
  238.                             to_y = -y_vlaue;  
  239.                         } else {  
  240.                             to_x = -x_vlaue;  
  241.                             to_y = 0;  
  242.                         }  
  243.                     } else {  
  244.                         // 向右,下移到上,右移到左  
  245.                         holdPosition = dragPosition - i - 1;  
  246.                         if (dragPosition / nColumns == holdPosition / nColumns) {  
  247.                             to_x = x_vlaue;  
  248.                             to_y = 0;  
  249.                         } else if ((holdPosition + 1) % 4 == 0) {  
  250.                             to_x = -3 * x_vlaue;  
  251.                             to_y = y_vlaue;  
  252.                         } else {  
  253.                             to_x = x_vlaue;  
  254.                             to_y = 0;  
  255.                         }  
  256.                     }  
  257.                     ViewGroup moveViewGroup = (ViewGroup) getChildAt(holdPosition);  
  258.                     Animation moveAnimation = getMoveAnimation(to_x, to_y);  
  259.                     moveViewGroup.startAnimation(moveAnimation);  
  260.                     // 如果是最后一个移动的,那么设置他的最后个动画ID为LastAnimationID  
  261.                     if (holdPosition == dropPosition) {  
  262.                         LastAnimationID = moveAnimation.toString();  
  263.                     }  
  264.                     moveAnimation.setAnimationListener(new AnimationListener() {  
  265.   
  266.                         @Override  
  267.                         public void onAnimationStart(Animation animation) {  
  268.                             // TODO Auto-generated method stub  
  269.                             isMoving = true;  
  270.                         }  
  271.   
  272.                         @Override  
  273.                         public void onAnimationRepeat(Animation animation) {  
  274.                             // TODO Auto-generated method stub  
  275.   
  276.                         }  
  277.   
  278.                         @Override  
  279.                         public void onAnimationEnd(Animation animation) {  
  280.                             // TODO Auto-generated method stub  
  281.                             // 如果为最后个动画结束,那执行下面的方法  
  282.                             if (animation.toString().equalsIgnoreCase(  
  283.                                     LastAnimationID)) {  
  284.                                 DragAdapter mDragAdapter = (DragAdapter) getAdapter();  
  285.                                 mDragAdapter.exchange(startPosition,  
  286.                                         dropPosition);  
  287.                                 startPosition = dropPosition;  
  288.                                 dragPosition = dropPosition;  
  289.                                 isMoving = false;  
  290.                             }  
  291.                         }  
  292.                     });  
  293.                 }  
  294.             }  
  295.         }  
  296.     }  
  297. }  
数据库SQLHelper文件
[java] view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public class SQLHelper extends SQLiteOpenHelper {  
  2.     public static final String DB_NAME = "database.db";// 数据库名称  
  3.     public static final int VERSION = 1;  
  4.       
  5.     public static final String TABLE_CHANNEL = "channel";//数据表   
  6.   
  7.     public static final String ID = "id";//  
  8.     public static final String NAME = "name";  
  9.     public static final String ORDERID = "orderId";  
  10.     public static final String SELECTED = "selected";  
  11.     private Context context;  
  12.     public SQLHelper(Context context) {  
  13.         super(context, DB_NAME, null, VERSION);  
  14.         this.context = context;  
  15.     }  
  16.   
  17.     public Context getContext(){  
  18.         return context;  
  19.     }  
  20.       
  21.     @Override  
  22.     public void onCreate(SQLiteDatabase db) {  
  23.         // TODO 创建数据库后,对数据库的操作  
  24.         String sql = "create table if not exists "+TABLE_CHANNEL +  
  25.                 "(_id INTEGER PRIMARY KEY AUTOINCREMENT, " +  
  26.                 ID + " INTEGER , " +  
  27.                 NAME + " TEXT , " +  
  28.                 ORDERID + " INTEGER , " +  
  29.                 SELECTED + " SELECTED)";  
  30.         db.execSQL(sql);  
  31.     }  
  32.   
  33.     @Override  
  34.     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {  
  35.         // TODO 更改数据库版本的操作  
  36.         onCreate(db);  
  37.     }  
  38.   
  39. }  
注:本DEMO中,加入了长按震动,所以在权限里面记得加上“
[java] view plain copy 在CODE上查看代码片 派生到我的代码片
  1.   
  2.   
  3.   
  4.   
  5.   
  6.   
六、源码下载
源码DEMO下载地址如下:下载地址
关注
打赏
1482932726
查看更多评论
立即登录/注册

微信扫码登录

0.0421s