• android可拖动排序GridView实现


    经常使用今日头条、网易新闻的同学们应该都会注意到用于管理多个频道的可拖动排序GridView,下面介绍一下可拖动的DragGridView的实现方法。代码放在GitHub上https://github.com/zhaoyu87/DragGridView,需要的同学可以下载

    DragGridView继承自GridView,当长按选中某个item进行拖动,放手更新GridView顺序:

    1.重写onTouchEvent响应拖动事件:被按下时记录按下坐标;拖动时更新被拖动视图显示;放开时更新排序

    2.设置OnItemLongClickListener:响应长按选取拖动item,获取被选中item bitmap,添加到窗口显示

    3.通过view.getDrawingCache()获取被选中item的bitmap,用于绘制拖动的view

    4.使用WindowManager来向窗口添加view,更新view显示。关于WindowManagerService对窗口的组织方式,博客http://blog.csdn.net/luoshengyang/article/details/8498908有介绍,可以参考。

    5. MotionEvent中的getX()为相对于容器的坐标,这里就是GridView;getRawX()为相对于整个屏幕的坐标

    DragGridView实现如下,注释中有更详细的解释

      1 public class DragGridView extends GridView {
      2     private static final int DRAG_IMG_SHOW = 1;
      3     private static final int DRAG_IMG_NOT_SHOW = 0;
      4     private static final String LOG_TAG = "DragGridView";
      5     private static final float AMP_FACTOR = 1.2f;
      6 
      7     /**被拖动的视图*/
      8     private ImageView dragImageView;
      9     private WindowManager.LayoutParams dragImageViewParams;
     10     private WindowManager windowManager;
     11     private boolean isViewOnDrag = false;
     12 
     13     /**前一次拖动的位置*/
     14     private int preDraggedOverPositon = AdapterView.INVALID_POSITION;
     15     private int downRawX;
     16     private int downRawY;
     17 
     18     /**长按选中拖动item*/
     19     private OnItemLongClickListener onLongClickListener = new OnItemLongClickListener(){
     20 
     21         @Override
     22         //长按item开始拖动
     23         public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
     24 
     25             //记录长按item位置
     26             preDraggedOverPositon = position;
     27 
     28             //获取被长按item的drawing cache
     29             view.destroyDrawingCache();
     30             view.setDrawingCacheEnabled(true);
     31             //通过被长按item,获取拖动item的bitmap
     32             Bitmap dragBitmap = Bitmap.createBitmap(view.getDrawingCache());
     33 
     34             //设置拖动item的参数
     35             dragImageViewParams.gravity = Gravity.TOP | Gravity.LEFT;
     36             //设置拖动item为原item 1.2倍
     37             dragImageViewParams.width = (int)(AMP_FACTOR*dragBitmap.getWidth());
     38             dragImageViewParams.height = (int)(AMP_FACTOR*dragBitmap.getHeight());
     39             //设置触摸点为绘制拖动item的中心
     40             dragImageViewParams.x = (downRawX - dragImageViewParams.width/2);
     41             dragImageViewParams.y = (downRawY - dragImageViewParams.height/2);
     42             dragImageViewParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
     43                                         | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
     44                                         | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
     45                                         | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
     46             dragImageViewParams.format = PixelFormat.TRANSLUCENT;
     47             dragImageViewParams.windowAnimations = 0;
     48 
     49             //dragImageView为被拖动item的容器,清空上一次的显示
     50             if((int)dragImageView.getTag() == DRAG_IMG_SHOW) {
     51                 windowManager.removeView(dragImageView);
     52                 dragImageView.setTag(DRAG_IMG_NOT_SHOW);
     53             }
     54 
     55             //设置本次被长按的item
     56             dragImageView.setImageBitmap(dragBitmap);
     57 
     58             //添加拖动item到屏幕
     59             windowManager.addView(dragImageView, dragImageViewParams);
     60             dragImageView.setTag(DRAG_IMG_SHOW);
     61             isViewOnDrag = true;
     62 
     63             //设置被长按item不显示
     64             ((GridViewAdapter)getAdapter()).hideView(position);
     65             return true;
     66         }
     67     };
     68 
     69     public DragGridView(Context context) {
     70         super(context);
     71         initView();
     72     }
     73 
     74     public DragGridView(Context context, AttributeSet attrs) {
     75         super(context, attrs);
     76         initView();
     77     }
     78 
     79     public DragGridView(Context context, AttributeSet attrs, int defStyleAttr) {
     80         super(context, attrs, defStyleAttr);
     81         initView();
     82     }
     83 
     84     public void initView() {
     85         setOnItemLongClickListener(onLongClickListener);
     86         //初始化显示被拖动item的image view
     87         dragImageView = new ImageView(getContext());
     88         dragImageView.setTag(DRAG_IMG_NOT_SHOW);
     89         //初始化用于设置dragImageView的参数对象
     90         dragImageViewParams = new WindowManager.LayoutParams();
     91         //获取窗口管理对象,用于后面向窗口中添加dragImageView
     92         windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
     93     }
     94 
     95 
     96     @Override
     97     public boolean onTouchEvent(MotionEvent ev) {
     98 
     99         //被按下时记录按下的坐标
    100         if(ev.getAction() == MotionEvent.ACTION_DOWN) {
    101             //获取触摸点相对于屏幕的坐标
    102             downRawX = (int)ev.getRawX();
    103             downRawY = (int)ev.getRawY();
    104         }
    105         //dragImageView处于被拖动时,更新dragImageView位置
    106         else if((ev.getAction() == MotionEvent.ACTION_MOVE) && (isViewOnDrag == true)) {
    107             Log.i(LOG_TAG, "" + ev.getRawX() + " " + ev.getRawY());
    108             //设置触摸点为dragImageView中心
    109             dragImageViewParams.x = (int)(ev.getRawX() - dragImageView.getWidth()/2);
    110             dragImageViewParams.y = (int)(ev.getRawY() - dragImageView.getHeight()/2);
    111             //更新窗口显示
    112             windowManager.updateViewLayout(dragImageView, dragImageViewParams);
    113             //获取当前触摸点的item position
    114             int currDraggedPosition = pointToPosition((int)ev.getX(), (int)ev.getY());
    115             //如果当前停留位置item不等于上次停留位置的item,交换本次和上次停留的item
    116             if((currDraggedPosition != AdapterView.INVALID_POSITION) && (currDraggedPosition != preDraggedOverPositon)) {
    117                 ((GridViewAdapter)getAdapter()).swapView(preDraggedOverPositon, currDraggedPosition);
    118                 preDraggedOverPositon = currDraggedPosition;
    119             }
    120         }
    121         //释放dragImageView
    122         else if((ev.getAction() == MotionEvent.ACTION_UP) && (isViewOnDrag == true)) {
    123             ((GridViewAdapter)getAdapter()).showHideView();
    124             if((int)dragImageView.getTag() == DRAG_IMG_SHOW) {
    125                 windowManager.removeView(dragImageView);
    126                 dragImageView.setTag(DRAG_IMG_NOT_SHOW);
    127             }
    128             isViewOnDrag = false;
    129         }
    130         return super.onTouchEvent(ev);
    131     }
    132 }

    GridViewAdapter继承自BaseAdapter:

    1.提供showHideView、hideView两个方法用于显示和隐藏选中Item的Text

    2.提供swapView方法用于拖动过程中更新GridView中item显示

     1 public class GridViewAdapter extends BaseAdapter {
     2     private Context context;
     3     private List<String> strList;
     4     private int hidePosition = AdapterView.INVALID_POSITION;
     5 
     6     public GridViewAdapter(Context context, List<String> strList) {
     7         this.context = context;
     8         this.strList = strList;
     9     }
    10 
    11     @Override
    12     public int getCount() {
    13         return strList.size();
    14     }
    15 
    16     @Override
    17     public String getItem(int position) {
    18         return strList.get(position);
    19     }
    20 
    21     @Override
    22     public long getItemId(int position) {
    23         return position;
    24     }
    25 
    26     @Override
    27     public View getView(int position, View convertView, ViewGroup parent) {
    28         TextView view;
    29         if(convertView == null) {
    30             view = new TextView(context);
    31         }
    32         else {
    33             view = (TextView)convertView;
    34         }
    35 
    36         //hide时隐藏Text
    37         if(position != hidePosition) {
    38             view.setText(strList.get(position));
    39         }
    40         else {
    41             view.setText("");
    42         }
    43         view.setId(position);
    44 
    45         return view;
    46     }
    47 
    48     public void hideView(int pos) {
    49         hidePosition = pos;
    50         notifyDataSetChanged();
    51     }
    52 
    53     public void showHideView() {
    54         hidePosition = AdapterView.INVALID_POSITION;
    55         notifyDataSetChanged();
    56     }
    57 
    58     public void removeView(int pos) {
    59         strList.remove(pos);
    60         notifyDataSetChanged();
    61     }
    62 
    63     //更新拖动时的gridView
    64     public void swapView(int draggedPos, int destPos) {
    65         //从前向后拖动,其他item依次前移
    66         if(draggedPos < destPos) {
    67             strList.add(destPos+1, getItem(draggedPos));
    68             strList.remove(draggedPos);
    69         }
    70         //从后向前拖动,其他item依次后移
    71         else if(draggedPos > destPos) {
    72             strList.add(destPos, getItem(draggedPos));
    73             strList.remove(draggedPos+1);
    74         }
    75         hidePosition = destPos;
    76         notifyDataSetChanged();
    77     }
    78 }
  • 相关阅读:
    返回页面顶部的方法
    一个获取当前 url 查询字符串中的参数的方法
    那些让你看起来很牛逼的Docker使用技巧
    Docker 1.13 新特性 —— Docker服务编排相关
    docker1.13新功能network关注点
    Docker 1.13 最实用命令行:终于可以愉快地打扫房间了
    Docker 1.13 – 新增功能大揭秘
    Docker 1.13 编排能力进化
    Docker
    Docker
  • 原文地址:https://www.cnblogs.com/letusrock/p/4322594.html
Copyright © 2020-2023  润新知