码迷,mamicode.com
首页 > 其他好文 > 详细

可拖动GridView的实现,类似支付宝界面

时间:2016-07-18 20:24:41      阅读:453      评论:0      收藏:0      [点我收藏+]

标签:

1.概述

之前实现过一个仿支付宝界面的代码,可拖动网格视图。其实实现的原理网上都可以找到,我也是参考网上实现的方法,实现了自己需要的界面。并对实现的原理和方法进行了分析,现在进行总结,放太久都快忘记自己做过这回事了。原理和实现网上大部分地方都可以找到,我是根据自己的理解进行分析的,现在对之前的工作进行总结,了解实现的基本过程和方法。GridView拖动的源码来源于网上,根据需求修改成了需要的效果,下面简单说明下实现过程。

在说明实现之前,先上一张总体的界面效果图:

技术分享

为了更好说明程序种各个变量的意义,我把界面增加了一个缩进,效果如下

技术分享

2.可拖动GridView实现原理

实现的原理并不复杂,通过GridView提供的基本方法、一些动画的基本操作以及移动时逻辑的判断和处理即可实现,为了更好说明代码实现的原理,对代码中使用的一些变量进行说明,参考下面这张图,时间仓促,随便画的,是想更好说明问题。。

技术分享

从上图可以看出相关参数的实际意义,下面将从ACTION_DOWN,ACTION_MOVE,ACTION_UP这三个常用的action分析拖动GridView的基本流程。

 

3.实现过程

1.ACTION_DOWN

在ACTION_DOWN触发的时候,这里保存了手指按下的坐标:

screenX= (int)ev.getX();
screenY= (int)ev.getY();

另外一个设置了长按监听,可以参考代码中setOnItemClickListener()方法。

在这个方法里,首先保存了按下子View的宽和高:

itemHeight = dragItem.getHeight();
itemWidth = dragItem.getWidth();

这个用于后续计算网格移动的距离。

保存按下点相对于按下子View的x,y坐标:

touchItemX= screenX- dragItem.getLeft();
touchItemY= screenY- dragItem.getTop();

这个主要使用来计算之后随手势拖动图片的位置。

如果是长按,代表已经触发了拖动过程,这个时候需要根据按下子View的显示内容创建一张图片,这张图片是用来随手势拖动显示的。View类提供了getDrawingCache()方法来获取一个View的的显示缓存,它返回的是一个bitmap的引用,而我们可以使用这个返回值创建一个自己的bitmap。

dragItem.destroyDrawingCache();
dragItem.setDrawingCacheEnabled(true);
Bitmap dragBitmap = Bitmap.createBitmap(dragItem.getDrawingCache());

创建完成移动的bitmap之后,还需要初始化一些参数值,包括移动的位置,对齐方式,创建一个ImageView来随手势拖动,这样以后每次拖动的时候只要设置随移动点移动就可以了。

ImageView iv = newImageView(getContext());
iv.setImageBitmap(dragBitmap); // 设置bitmap
windowManager = (WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE);
windowManager.addView(iv, windowParams);
dragImageView= iv; // 拖动的Item

之后把按下的子View隐藏起来,因为这个时候已经创建子View的一张图片,看起来就好像子View随按下动作弹起来了一样。

2.ACTION_MOVE:

在移动手势的时候,主要完成两方面的事情,一是手指移动时点击的图标会随手势移动,二是当移动满足一定条件是,子View会自动调整自己的位置。

2.1 图标随手势移动

图标随手势移动时调用updateViewLayout()方法,它会根据传入的参数更新View显示的位置。

private void onDrag(int x,int y, int rawx,int rawy) {
    if (dragImageView !=null) {
        windowParams.alpha = 0.6f;
        windowParams.x = rawx -touchItemX; // 获取最新的
        windowParams.y = rawy -touchItemY;
        windowManager.updateViewLayout(dragImageView,windowParams); // 让dragImageView随手指拖动
    }
}

2.2根据手势移动坐标更新子View的位置

接着需要根据手势移动最新位置来调整GridView的项目,需要处理下面几项内容:

1.获取当前拖动的拖动x,y对应GridView的位置,使用pointToPosition()方法获取。

   int dPosition = pointToPosition(x, y);

2.计算当前拖动的x,y坐标位置需要移动多少个子View,使用上面计算出来的位置减去初始位置,得到的差值就是需要移动的子View数目,取绝对值

movecount= dropPosition- dragPosition;
int movecount_abs =Math.abs(movecount); // 取绝对值

3.是否满足条件,满足条件开始移动子View

if (movecount == 0) {// 说明不需要移动任何项
    return;
}
if (dPosition !=dragPosition) { //拖动位置和最新位置不一致

4.开始移动子View位置,首先计算移动一个子View,首先计算移动子View到相邻位置所需要移动的x,y轴的距离

    float x_vlaue = ((float) getHorizontalSpacing()/ (float)itemWidth) + 1.0f;
    float y_vlaue = ((float) getVerticalSpacing() /(float)itemHeight) + 1.0f;

之后开始循环移动子View。

这里又分两种情况,分别是手势向右拖动,子View向左移动,另外一种是分别是手势向左拖动,子View向右移动。其中向右拖动可能会夸行,向左也一样。在手势移动的时候会根据是否需要移动子View的需要,首先计算出移动子View的x,y距离。

当手势向右移动时,计算逻辑代码如下:

holdPosition = dragPosition+ i + 1; // 移动的位置项
if (dragPosition/nColumns== holdPosition/nColumns){ // 同一行向右拖动时处理
    to_x= -x_vlaue;
    to_y= 0;
} else if (holdPosition% 3 == 0) { // 处理第一行的第一个显示项,往上一行移动到最后
    to_x= 2 * x_vlaue;
    to_y= -y_vlaue;
} else {
    to_x= -x_vlaue;
    to_y= 0;
}

代码中判断了移动的子View是否在同一行,分别做了不同的逻辑处理,因为这里是写了3列的GridView,计算的时候都是根据这个参数计算的。

当手势向左移动时,代码和上面差不多:

holdPosition = dragPosition- i - 1;
if (dragPosition/nColumns== holdPosition/nColumns){
    to_x= x_vlaue;
    to_y= 0;
} else if ((holdPosition+ 1) % 3 == 0) {
    to_x= -2 * x_vlaue;
    to_y= y_vlaue;
} else {
    to_x= x_vlaue;
    to_y= 0;
}

计算出了子View需要移动的x,y距离之后,接下来就是要使用动画移动子View了。在这里直接创建了动画并设置了上述步骤计算出来的x,y距离,开始移动子View:

ViewGroup moveViewGroup =(ViewGroup) getChildAt(holdPosition);
Animation moveAnimation =getMoveAnimation(to_x, to_y);
moveViewGroup.startAnimation(moveAnimation);

这里是循环移动子View的过程,移动完成第一个接着会移动第二个,以此类推,所以我们看到的效果就是有几个子View会自动移动到他们需要移动的位置。

如果最后一个子View移动完成,这时候会更新Adapter中的数据,并且更新界面,这里主要是判断最后一个子View动画结束时处理上述的工作。

if (holdPosition==dropPosition){
    LastAnimationID = moveAnimation.toString();
}
@Override
public voidonAnimationEnd(Animation animation) {
    // TODO Auto-generated method stub
    // 如果为最后个动画结束,那执行下面的方法
    if (animation.toString().equalsIgnoreCase(LastAnimationID)) {
        DgvAdaptermDragAdapter = (DgvAdapter) getAdapter();
        mDragAdapter.exchange(startPosition,dropPosition);
<span style="white-space:pre">	</span>startPosition = dropPosition;
<span style="white-space:pre">	</span>dragPosition = dropPosition;
<span style="white-space:pre">	</span>isMoving = false;
    }
}

在exchange()方法中,主要是根据起点位置和结束点位置对数据进行了更新,然后更新GridView显示数据。

public void exchange(int dragPostion,int dropPostion) {
    holdPosition = dropPostion;
    DgvItemdragItem = getItem(dragPostion);
    if (dragPostion <dropPostion) {
        dgvList.add(dropPostion + 1,dragItem);
        dgvList.remove(dragPostion);
    }else{
        dgvList.add(dropPostion,dragItem);
        dgvList.remove(dragPostion +1);
    }
    isChanged = true;
    notifyDataSetChanged();
}

这里移动子View的过程就结束了。

3.ACTION_UP:

当停止触摸时,这里主要做两件事情,一是把之前创建的一些临时数据清除,这里主要清除了拖动图片的缓存。

private void stopDrag() {
    if (dragImageView !=null) {
        windowManager.removeView(dragImageView);
        dragImageView = null;
    }
}

另外一个是把之前点击隐藏的子View显示出来。

private void onDrop(int x,int y) {
    int tempPostion =pointToPosition(x, y);
    dropPosition = tempPostion;
    DgvAdaptermDragAdapter = (DgvAdapter) getAdapter();
    mDragAdapter.setShowDropItem(true);// 显示刚拖动的item
    mDragAdapter.notifyDataSetChanged();//刷新适配器,让对应的item显示
}

这样,一次移动的动作就完成了。

4.GridView列表状态保存

这里保存GridView的状态是在退出的时候,获取adapter里面的数据,并把它存在数据库,下次进入的时候从数据库加载,这样就能够把上次移动的顺序保存下来,并在下次加载的时候按上次顺序显示。

private voidsaveChannel() {
    DgvManager.getManage().deleteMjbhOfAll();
    DgvManager.getManage().saveItems(dgvAdapter.getChannnelLst());
}

4.总结

综合上面的分析,下面给可拖动GridView的实现方式作初略的总结:

1.ACTION_DOWN:

保存了按下点的相关参数,创建了一张用户可拖动的临时图片,并初始化了图片拖动参数,最后把按下的子View隐藏了,结果就显示了创建的图片,视觉上就像子View弹起来显示一样。

2.ACTION_MOVE

图片随手势移动,计算移动的参数,逐个移动子View,移动完成之后更新数据和界面。

3.ACTION_UP

清除临时数据和显示之前隐藏的子View。

4.退出时保存当前GridView的状态。

下面附上一张简单流程图:

 技术分享

 

 

 

 

 

 

 

 


可拖动GridView的实现,类似支付宝界面

标签:

原文地址:http://blog.csdn.net/qq282330332/article/details/51698224

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!