当前位置: 移动技术网 > IT编程>移动开发>Android > Android自定义View实现可以拖拽的GridView

Android自定义View实现可以拖拽的GridView

2019年07月24日  | 移动技术网IT编程  | 我要评论

塔文.耀万鹏衮,骑牛难下,开国大典演员

先看看效果图

主要思想:

1、监听触碰事件
2、用windowmanager添加拖曳的图片
3、用collections.swap()交换list数据

自定义代码:

public class draggridveiw extends gridview {

  private final int press_time = 1000;//长按时间

  private int mdownx;//触碰时的x坐标
  private int mdowny;//触碰时的y坐标
  private int mmovex;//移动时的x坐标
  private int mmovey;//移动时的y坐标

  private int moffset2top;//draggridview距离屏幕顶部的偏移量
  private int moffset2left;//draggridview距离屏幕左边的偏移量
  private int mpointtoitemtop;//触碰点距离itemview的上边距
  private int mpointtoitemleft;//触碰点距离itemview的左边距
  private int mstatusheight;//状态栏高度

  private boolean isdraging;//是否正在拖曳

  private bitmap mbitmap;//itemview的图片
  private int mtouchpostiion;//触碰的位置
  private view mtouchitemview;//触碰的itemview

  private vibrator mvibrator;//震动器
  private imageview mdragimageview;//拖曳的view
  private windowmanager mwindowmanager;//窗口管理器
  private windowmanager.layoutparams mwindowlayoutparams;//窗口管理器布局

  private onchanagelistener onchanagelistener;//交换事件监听器

  private handler mhandler = new handler();


  public draggridveiw(context context) {
    this(context, null);
  }

  public draggridveiw(context context, attributeset attrs) {
    this(context, attrs, 0);
  }

  public draggridveiw(context context, attributeset attrs, int defstyleattr) {
    super(context, attrs, defstyleattr);
    mstatusheight = getstatusheight(context);
    mvibrator = (vibrator) context.getsystemservice(context.vibrator_service);
    mwindowmanager = (windowmanager) context.getsystemservice(context.window_service);
  }


  @override
  public boolean dispatchtouchevent(motionevent ev) {
    switch (ev.getaction()) {
      case motionevent.action_down:
        //使用handler延迟dragresponsems执行mlongclickrunnable
        mhandler.postdelayed(mlongclickrunnable, press_time);

        mdownx = (int) ev.getx();
        mdowny = (int) ev.gety();

        //根据按下的x,y坐标获取所点击item的position
        mtouchpostiion = pointtoposition(mdownx, mdowny);

        if (mtouchpostiion == adapterview.invalid_position) {
          return super.dispatchtouchevent(ev);
        }

        //根据position获取该item所对应的view
        mtouchitemview = getchildat(mtouchpostiion - getfirstvisibleposition());

        //下面这几个距离大家可以参考我的博客上面的图来理解下
        mpointtoitemtop = mdowny - mtouchitemview.gettop();
        mpointtoitemleft = mdownx - mtouchitemview.getleft();

        moffset2top = (int) (ev.getrawy() - mdowny);
        moffset2left = (int) (ev.getrawx() - mdownx);

        //开启mdragitemview绘图缓存
        mtouchitemview.setdrawingcacheenabled(true);
        //获取mdragitemview在缓存中的bitmap对象
        mbitmap = bitmap.createbitmap(mtouchitemview.getdrawingcache());
        //这一步很关键,释放绘图缓存,避免出现重复的镜像
        mtouchitemview.destroydrawingcache();

        break;
      case motionevent.action_move:
        int movex = (int) ev.getx();
        int movey = (int) ev.gety();

        //拖曳点超出gridview区域则取消拖曳事件
        if (ev.gety() > getheight() || ev.gety() < 0) {
          onstopdrag();
        }

        //如果我们在按下的item上面移动,只要超过item的边界就移除mrunnable
        if (!istouchinitem(mtouchitemview, movex, movey)) {
          mhandler.removecallbacks(mlongclickrunnable);
        }
        break;
      case motionevent.action_up:
        mhandler.removecallbacks(mlongclickrunnable);
        break;
    }
    return super.dispatchtouchevent(ev);
  }

  @override
  public boolean ontouchevent(motionevent ev) {
    if (isdraging && mdragimageview != null) {
      switch (ev.getaction()) {
        case motionevent.action_move:
          mmovex = (int) ev.getx();
          mmovey = (int) ev.gety();
          //拖动item
          ondragitem(mmovex, mmovey);
          break;
        case motionevent.action_up:
          onstopdrag();

          break;
      }
      return true;
    }
    return super.ontouchevent(ev);
  }


  //处理长按事件的线程
  private runnable mlongclickrunnable = new runnable() {
    @override
    public void run() {
      isdraging = true; //设置可以拖拽
      mvibrator.vibrate(50); //震动一下
      mtouchitemview.setvisibility(view.invisible);//隐藏该itemview

      //根据我们按下的点显示itemview镜像
      createdragview(mbitmap, mdownx, mdowny);
    }
  };


  //添加拖动view
  private void createdragview(bitmap bitmap, int downx, int downy) {
    mwindowlayoutparams = new windowmanager.layoutparams();
    mwindowlayoutparams.format = pixelformat.translucent; //图片之外的其他地方透明
    mwindowlayoutparams.gravity = gravity.top | gravity.left;
    mwindowlayoutparams.x = downx - mpointtoitemtop + moffset2left;
    mwindowlayoutparams.y = downy - mpointtoitemtop + moffset2top - mstatusheight;
    mwindowlayoutparams.alpha = 0.6f; //透明度
    mwindowlayoutparams.width = windowmanager.layoutparams.wrap_content;
    mwindowlayoutparams.height = windowmanager.layoutparams.wrap_content;
    mwindowlayoutparams.flags = windowmanager.layoutparams.flag_not_focusable
        | windowmanager.layoutparams.flag_not_touchable;

    mdragimageview = new imageview(getcontext());
    mdragimageview.setimagebitmap(bitmap);
    mwindowmanager.addview(mdragimageview, mwindowlayoutparams);
  }


  private void removedragview() {
    if (mdragimageview != null) {
      mwindowmanager.removeview(mdragimageview);
      mdragimageview = null;
    }
  }

  //是否点击在gridview的item上面
  private boolean istouchinitem(view dragview, int x, int y) {
    int leftoffset = dragview.getleft();
    int topoffset = dragview.gettop();
    if (x < leftoffset || x > leftoffset + dragview.getwidth()) {
      return false;
    }
    if (y < topoffset || y > topoffset + dragview.getheight()) {
      return false;
    }
    return true;
  }

  //拖动事件处理
  private void ondragitem(int movex, int movey) {
    mwindowlayoutparams.x = movex - mpointtoitemleft + moffset2left;
    mwindowlayoutparams.y = movey - mpointtoitemtop + moffset2top - mstatusheight;
    mwindowmanager.updateviewlayout(mdragimageview, mwindowlayoutparams); //更新dragview的位置
    onswapitem(movex, movey);//item的相互交换
  }

  //交换item,并且控制item之间的显示与隐藏效果
  private void onswapitem(int movex, int movey) {
    //获取我们手指移动到的那个item的position
    int tempposition = pointtoposition(movex, movey);

    //假如tempposition 改变了并且tempposition不等于-1,则进行交换
    if (tempposition != mtouchpostiion && tempposition != adapterview.invalid_position) {
      getchildat(tempposition - getfirstvisibleposition()).setvisibility(view.invisible);//拖动到了新的item,新的item隐藏掉
      getchildat(mtouchpostiion - getfirstvisibleposition()).setvisibility(view.visible);//之前的item显示出来

      if (onchanagelistener != null) {
        onchanagelistener.onchange(mtouchpostiion, tempposition);
      }

      mtouchpostiion = tempposition;
    }
  }

  //停止拖拽我们将之前隐藏的item显示出来,并将dragview移除
  private void onstopdrag() {
    isdraging = false;
    getchildat(mtouchpostiion - getfirstvisibleposition()).setvisibility(view.visible);
    removedragview();
  }

  //item交换事件监听
  public void setonchangelistener(onchanagelistener onchanagelistener) {
    this.onchanagelistener = onchanagelistener;
  }

  //获取状态栏高度
  private int getstatusheight(context context) {
    int statusheight = 0;
    rect localrect = new rect();
    ((activity) context).getwindow().getdecorview().getwindowvisibledisplayframe(localrect);
    statusheight = localrect.top;
    if (0 == statusheight) {
      class<?> localclass;
      try {
        localclass = class.forname("com.android.internal.r$dimen");
        object localobject = localclass.newinstance();
        int i5 = integer.parseint(localclass.getfield("status_bar_height").get(localobject).tostring());
        statusheight = context.getresources().getdimensionpixelsize(i5);
      } catch (exception e) {
        e.printstacktrace();
      }
    }
    return statusheight;
  }

  //当item交换位置的时候回调的方法,我们只需要在该方法中实现数据的交换即可
  public interface onchanagelistener {
    public void onchange(int from, int to);
  }
}

使用方法:

   list<hashmap<string, object>> datasourcelist = new arraylist<>();

    dragveiw = (draggridveiw) findviewbyid(r.id.view_drag);

    for (int i = 0; i < 8; i++) {
      hashmap<string, object> itemhashmap = new hashmap<>();
      itemhashmap.put("item_image", r.drawable.sample_1);
      itemhashmap.put("item_text", "拖拽 " + integer.tostring(i));
      datasourcelist.add(itemhashmap);
    }

    final simpleadapter msimpleadapter = new simpleadapter(this, datasourcelist,
        r.layout.item_drag, new string[]{"item_image", "item_text"},
        new int[]{r.id.item_image, r.id.item_text});

    dragveiw.setadapter(msimpleadapter);

    dragveiw.setonchangelistener(new draggridveiw.onchanagelistener() {
      @override
      public void onchange(int from, int to) {
        hashmap<string, object> temp = datasourcelist.get(from);
        //这里的处理需要注意下
        if (from < to) {
          for (int i = from; i < to; i++) {
            collections.swap(datasourcelist, i, i + 1);
          }
        } else if (from > to) {
          for (int i = from; i > to; i--) {
            collections.swap(datasourcelist, i, i - 1);
          }
        }

        datasourcelist.set(to, temp);
        msimpleadapter.notifydatasetchanged();
      }
    });

附录:

log.v("-->getwidth", string.valueof(getwidth()));//dragview的宽度
log.v("-->getheight", string.valueof(getheight()));//dragview的高度
log.v("-->getleft", string.valueof(getleft()));//dragview左边距离屏幕左侧的长度
log.v("-->gettop", string.valueof(gettop()));///dragview上边距离屏幕顶部的长度
log.v("-->getrawx", string.valueof(ev.getrawx()));//触碰点相对于屏幕的x坐标
log.v("-->getrawy", string.valueof(ev.getrawy()));//触碰点相对于屏幕的y坐标
log.v("-->getx", string.valueof(ev.getx()));//触碰点相对于dragview的x坐标
log.v("-->gety", string.valueof(ev.gety()));//触碰点相对于dragview的y坐标

log.v("-->getitemwidth", string.valueof(mtouchitemview.getwidth()));//dragview中itemview的宽度
log.v("-->getitemheight", string.valueof(mtouchitemview.getheight()));//dragview中itemview的高度
log.v("-->getitemleft", string.valueof(mtouchitemview.getleft()));//dragview中itemview左边距离dragview左侧的长度
log.v("-->getitemtop", string.valueof(mtouchitemview.gettop()));//dragview中itemview上边距离dragview顶部的长度

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网