欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2024-03-31 18:15:10
先看看效果图 主要思想: 1、监听触碰事件 2、用windowmanager添加拖曳的图片 3、用collections.swap()交换list数据 自...

先看看效果图

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

主要思想:

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顶部的长度

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