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

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的状态。

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

时间: 2024-10-02 07:50:07

可拖动GridView的实现,类似支付宝界面的相关文章

类似支付宝扫描识别银行卡号的技术

类似支付宝扫描识别银行卡号的技术 新关键词:银行卡扫描识别,扫描银行卡卡号识别,银行卡号识别SDK,银行卡OCR识别 新银行卡扫描识别技术的应用背景 实际测试中手动输入16—19位银行卡号码,速度慢,易出错,用户体验非常差.为了提高在移动终端上输入银行卡号的速度和准确性,北京文通科技有限公司结合银行.保险.金融P2P及第三方支付等行业对自动识别银行卡号的迫切需求,推出银行卡号识别SDK,各类APP只需集成银行卡识别SDK后,便可自动识别银行卡号. 二.银行卡识别产品介绍 文通银行卡号识别SDK可

模仿手机支付宝界面

模仿手机支付宝界面 功能分类:其他         支持平台:iOS      运行环境:iOS 开发语言:Object-c  开发工具:Xcode   源码大小:455.66KB 下载地址: http://www.dwz.cn/x9vZl 源码简介 动态显示aplashimage,控制手势密码,TabbarController与navigationController结合使用,定制tableViewController,自定义UIButton. 源码运行截图

本app(仿手机支付宝界面)ios源码

本app(仿手机支付宝界面)主要演示了: 动态显示splashimage如何控制手势密码(AES加密保存数据)如何控制viewcontroller之间的跳转,viewcontroller的代理控制.TabbarController与navigationControlle结合使用动态显示splashimage定制tableViewController自定义UIButton 效果图本app已打包发布到蒲公英平台,网址:http://www.pgyer.com/syD6.可直接安装(无需越狱)查看效果

使用GridView和SimpleAdapter实现手机界面常见的九宫格

首先是两个XML界面: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"

类似支付宝启动页面的实现

支付宝启动页面,是可以随时替换的,个人认为实际上是两张图,只不过第一张本地的图下半部分跟第二张图的下半部分是一样的. 做到这样的效果,第二张图片可以随时替换,请求一个接口就可以了,有什么活动只需要在服务器上传图片就行了.具体步奏: 1.首先在项目里面LaunchImage里面对应放上第一张白色底图 2.在AppDelegate.m文件里面 , - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOption

使用GridView和SimpleAdapter实现手机界面的九宫格

布局文件创建Item创建数据准备适配器绑定和监听器1.布局文件 2.item 3.适配器和监听

Android 仿 窗帘效果 和 登录界面拖动效果 (Scroller类的应用) 附 2个DEMO及源代码

在android学习中,动作交互是软件中重要的一部分.当中的Scroller就是提供了拖动效果的类,在网上.比方说一些Launcher实现滑屏都能够通过这个类去实现.以下要说的就是上次Scroller类学习的后的实践了. 假设你还不了解Scroller类,那请先点击:Android 界面滑动实现---Scroller类 从源代码和开发文档中学习(让你的布局动起来) 了解之后再阅读下面内容.你会发现原来实现起来非常easy. 之前说到过.在广泛使用的側边滑动导航开源库 --SlidingLayer

可以拖动交换item位置的GridView

欢迎关注Android技术分享公众号(小红人). 这篇文章是基于夏安明写的一个可以移动item的Demo改写的,因为原代码有一些BUG,比如adapter不能使用ViewHolder优化(这个问题应该是最大的问题)再比如不能使用上下拉刷新功能(这个是我额外添加的功能,不知道的可以去看看开源中国手机客户端的便签功能) 在Android开发中,我们常常用到ListView和GridView,而有的时候系统的ListView,GridView并不能满足我们的需求,所以我们需要自己定义一个ListVie

Android 仿 窗帘效果 和 登录界面拖动效果 (Scroller类的应用) 附 2个DEMO及源码

在android学习中,动作交互是软件中重要的一部分,其中的Scroller就是提供了拖动效果的类,在网上,比如说一些Launcher实现滑屏都可以通过这个类去实现.下面要说的就是上次Scroller类学习的后的实践了. 如果你还不了解Scroller类,那请先点击:Android 界面滑动实现---Scroller类 从源码和开发文档中学习(让你的布局动起来) 了解之后再阅读以下内容,你会发现原来实现起来很简单. 之前说到过,在广泛使用的侧边滑动导航开源库 --SlidingLayer其实就是