ListView底部item飞入动画效果
2015-09-14 08:52
323 查看
最近有朋友展示了一种效果,就是ListView在滑动的过程中新加入的item会有一个从底部滑入的效果,我感觉这种效果还算不错,就去想了想拿到我身上应该怎么去实现这种效果,在试过几种方案后,最后选择了一种使用起来还算比较简单的方式拿出来分享一下。
在开始分享之前,先来看看我们需要做成什么效果吧,
恩,看到什么效果了吗?仔细看滑动过程中的底部,新加入的item会以一种动画的形式加入,马上,我们就来实现这种效果!
新加入的item会以一种动画的形式加入
我们只要抓住这一点往下想,很快就能想到
我们怎么判断已经滑动到底部了?
很多人会不假思索的回答,这个问题容易! 这不和ListView的分页一样吗!当然不是了, ListView分页的底部是判断的数据集的最后一项,不太适用我们这里,而且纵观ListView的几个方法,我们并没有找到合适的方法去使用,所以,我们只能自己去判断了,怎么判断?还是在监听的
假设,现在我们已经可以可以判断滑动到底部了,我们用一个状态变量
基本的实现思路已经阐述完了,下面我们就来着手用代码来实现我们的思路,我们需要解决以下问题,
尽量将这些代码封装好,以避免每次使用的时候都copy一遍代码
具体用代码怎么判断ListView往下滑动
对于第一个问题,我们采用大多数情况下使用的方式,就是:
自定义一个抽象的Adapter,实现BaseAdapter中的getView方法,并定义一个buildView
来代替getView的功能。
这样做的好处就是,我们可以在getView中做我们想做的事,而不必在意convertView怎么形成。这也非常符合我们的需求,所以代码可以这么写,
上面说了,我们需要监听ListView的滑动,这里我们在BaseFlyAdapter中也一块搞定!那我们的BaseFlyAdapter还需要一个ListView,并给他设置
准备好了这些,我们就来实现
具体的代码都是
首先我们获取ListView的第一个view——
一个或的操作,这里要考虑两种情况,
新的item加入的时候,第一个item已经滑动出屏幕外。
当新的item加入,但第一个item还没滑动出屏幕外。
对于第一种情况,是常规的一种情况,我们直接通过判断第一个可见项,注意这里的第一个可见项是指在我们数据集中的,并且判断是不是大于我们之前保存的firstVisibleItem就ok, 可以看一下最后面的代码,我们去保存了firstVisibleItem和第一个View的top值。对于第二种情况,我们只需要判断View的top值是不是大于我们最后一次保存的值就ok。
ok,到现在为止,我们可以知道ListView是不是往下滑动了,下面就开始给新加入的item添加动画吧。为了灵活,我们将动画的定义放到外部,所以我们还需要给
动画设置好了,我们最后就来看看在getView中怎么做吧。上面说了,动画的执行是在getView中,
首先调用buildView,以前我们在getView中写的代码,现在需要放到buildView中了,然后我们去判断现在是不是往下滑动,如果是往下滑动,首先cancel掉所有item的动画,这样做的目的是防止在某个瞬间多个item执行动画,然后直接调用convertView.startAnimation来开始动画。不过,还记得我们在上面的一句话吗?
至于是不是到达底部了,交给getView去做!
我们看getView的代码里也没有关于解决这个问题的代码啊!对,这没有错,getView执行了,那肯定是新的item加入了,而且我们在getView中做了是不是往下滑动的判断了,所以这个问题自然就解决了!
ok,ok, 万事俱备了,下面就让我们开始使用一下吧,
先去无视MyAdapter的代码, 它肯定是继承了我们定义的BaseFlyAdapter, 我们通过setAnimation来设置了一个动画,我们先来看看这个动画怎么写的吧,
不多说,一个简单的translate动画。
最后,我们再来看看MyAdapter吧,其实和我们继承BaseAdapter一样只不过我们不需要书写getView的代码,而是放到buildView中,
好了,到现在你可以看一下效果啦,当然这里我们把动画的定义抽出来了,这样做的好处就是可以随意切换动画,现在我们修改动画为alpha动画,
而我们的代码不需要改变,再来看看效果,
很轻松,一个alpha的效果就完成了。就到这里吧。
代码下载,戳这里
在开始分享之前,先来看看我们需要做成什么效果吧,
恩,看到什么效果了吗?仔细看滑动过程中的底部,新加入的item会以一种动画的形式加入,马上,我们就来实现这种效果!
实现方式的选择
当我第一次看到这种效果的时候,我首先想到的是LayoutAnimation,不过很快就让我否决了,为什么呢?我们能的动画只是在新加入的item的起到效果,而其他的item是没有这个效果的,这种方式用
LayoutAnimation是做不到的, 那我们应该怎么实现呢?关键点就在动画在什么时候有效!前面我们说过很多次了,
新加入的item会以一种动画的形式加入
我们只要抓住这一点往下想,很快就能想到
Adapter的
getView上,在新item加入的时候,Adapter的getView必定是去执行的,我们沿着这个思路往下走,很快我们又遇到问题了,
我们怎么判断已经滑动到底部了?
很多人会不假思索的回答,这个问题容易! 这不和ListView的分页一样吗!当然不是了, ListView分页的底部是判断的数据集的最后一项,不太适用我们这里,而且纵观ListView的几个方法,我们并没有找到合适的方法去使用,所以,我们只能自己去判断了,怎么判断?还是在监听的
OnScrollListener里,在这里面判断是不是往下滑动的,至于是不是到达底部了,交给getView去做!所以我们还需要在Adapter中知道ListView的存在,并给他设置滑动监听。
假设,现在我们已经可以可以判断滑动到底部了,我们用一个状态变量
isScrollDown来表示,那是不是现在我们就可以在
getView里通过
isScrollDown来判断是否给
convertView一个动画呢?
基本的实现思路已经阐述完了,下面我们就来着手用代码来实现我们的思路,我们需要解决以下问题,
尽量将这些代码封装好,以避免每次使用的时候都copy一遍代码
具体用代码怎么判断ListView往下滑动
对于第一个问题,我们采用大多数情况下使用的方式,就是:
自定义一个抽象的Adapter,实现BaseAdapter中的getView方法,并定义一个buildView
来代替getView的功能。
这样做的好处就是,我们可以在getView中做我们想做的事,而不必在意convertView怎么形成。这也非常符合我们的需求,所以代码可以这么写,
public abstract class BaseFlyAdapter extends BaseAdapter { public View getView(int position, View convertView, ViewGroup parent) { View view = buildView(position, convertView, parent); return view; } public abstract View buildView(int position, View convertView, ViewGroup parent); }
上面说了,我们需要监听ListView的滑动,这里我们在BaseFlyAdapter中也一块搞定!那我们的BaseFlyAdapter还需要一个ListView,并给他设置
OnScrollListener,
public abstract class BaseFlyAdapter extends BaseAdapter { private ListView mListView; public void bindView(ListView listView) { mListView = listView; mListView.setOnScrollListener(mScrollListener); } private OnScrollListener mScrollListener = new OnScrollListener() { public void onScrollStateChanged(AbsListView view, int scrollState) { } public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { } }; ... }
准备好了这些,我们就来实现
如果判断往下滑动这个需求,先上代码,
public abstract class BaseFlyAdapter extends BaseAdapter { private ListView mListView; private boolean isScrollDown; // 是否往下滑动 private int mFirstPosition; // 第一个可见item的位置 private int mFirstTop; // 第一个可以item的top值 public void bindView(ListView listView) { mListView = listView; mListView.setOnScrollListener(mScrollListener); } private OnScrollListener mScrollListener = new OnScrollListener() { public void onScrollStateChanged(AbsListView view, int scrollState) { if(scrollState == OnScrollListener.SCROLL_STATE_IDLE) isScrollDown = false; } public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { View firstChild = view.getChildAt(0); if(firstChild == null) return; int top = firstChild.getTop(); isScrollDown = firstVisibleItem > mFirstPosition || mFirstTop > top; mFirstTop = top; mFirstPosition = firstVisibleItem; } }; }
具体的代码都是
mScrollListener中,首先来看看
onScrollStateChanged,这里面的代码很简单,就是在滑动停止的时候去恢复
isScrollDown变量。最重要的代码还是在
onScroll中。下面我们来具体看看这里面的实现。
首先我们获取ListView的第一个view——
firstChild,如果这里你不明白怎么回事的话,可以去看看ListView的复用机制,接着我们来获取到
firstChild的top值,这些都是为下面去判断是不是往下滑动做准备的,那怎么判断呢?
isScrollDown = firstVisibleItem > mFirstPosition || mFirstTop > top;
一个或的操作,这里要考虑两种情况,
新的item加入的时候,第一个item已经滑动出屏幕外。
当新的item加入,但第一个item还没滑动出屏幕外。
对于第一种情况,是常规的一种情况,我们直接通过判断第一个可见项,注意这里的第一个可见项是指在我们数据集中的,并且判断是不是大于我们之前保存的firstVisibleItem就ok, 可以看一下最后面的代码,我们去保存了firstVisibleItem和第一个View的top值。对于第二种情况,我们只需要判断View的top值是不是大于我们最后一次保存的值就ok。
ok,到现在为止,我们可以知道ListView是不是往下滑动了,下面就开始给新加入的item添加动画吧。为了灵活,我们将动画的定义放到外部,所以我们还需要给
BaseFlyAdapter一个方法去设置动画,
public abstract class BaseFlyAdapter extends BaseAdapter { private AnimationSet mAnimationSet; ... public void setAnimation(AnimationSet set) { mAnimationSet = set; } ... }
动画设置好了,我们最后就来看看在getView中怎么做吧。上面说了,动画的执行是在getView中,
public abstract class BaseFlyAdapter extends BaseAdapter { ... public View getView(int position, View convertView, ViewGroup parent) { View view = buildView(position, convertView, parent); if(isScrollDown && mAnimationSet != null) { cancelAnimation(); view.startAnimation(mAnimationSet); } return view; } private void cancelAnimation() { int count = mListView.getChildCount(); for(int i=0;i<count;i++) { mListView.getChildAt(i).clearAnimation(); } } }
首先调用buildView,以前我们在getView中写的代码,现在需要放到buildView中了,然后我们去判断现在是不是往下滑动,如果是往下滑动,首先cancel掉所有item的动画,这样做的目的是防止在某个瞬间多个item执行动画,然后直接调用convertView.startAnimation来开始动画。不过,还记得我们在上面的一句话吗?
至于是不是到达底部了,交给getView去做!
我们看getView的代码里也没有关于解决这个问题的代码啊!对,这没有错,getView执行了,那肯定是新的item加入了,而且我们在getView中做了是不是往下滑动的判断了,所以这个问题自然就解决了!
ok,ok, 万事俱备了,下面就让我们开始使用一下吧,
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final ListView listView = (ListView) findViewById(R.id.list); MyAdapter adapter = new MyAdapter(); adapter.bindView(listView); adapter.setAnimation((AnimationSet) AnimationUtils.loadAnimation(this, R.anim.anim)); listView.setAdapter(adapter); } }
先去无视MyAdapter的代码, 它肯定是继承了我们定义的BaseFlyAdapter, 我们通过setAnimation来设置了一个动画,我们先来看看这个动画怎么写的吧,
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" > <translate android:duration="500" android:fromYDelta="50%" android:toYDelta="0" /> </set>
不多说,一个简单的translate动画。
最后,我们再来看看MyAdapter吧,其实和我们继承BaseAdapter一样只不过我们不需要书写getView的代码,而是放到buildView中,
class MyAdapter extends BaseFlyAdapter { public int getCount() { return 100; } public Object getItem(int position) { return "hello"; } public long getItemId(int position) { return position; } @Override public View buildView(int position, View convertView, ViewGroup parent) { if(convertView == null) { convertView = View.inflate(parent.getContext(), R.layout.item, null); } return convertView; } }
好了,到现在你可以看一下效果啦,当然这里我们把动画的定义抽出来了,这样做的好处就是可以随意切换动画,现在我们修改动画为alpha动画,
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" > <alpha android:duration="500" android:fillAfter="true" android:fromAlpha="0.0" android:toAlpha="1.0"/> </set>
而我们的代码不需要改变,再来看看效果,
很轻松,一个alpha的效果就完成了。就到这里吧。
代码下载,戳这里
相关文章推荐
- 移动端兼容性处理1
- 什么是POJO模式
- 转 MySQL 日期类型详解
- 在ubuntu上建立一个nginx代理邮件服务器20150405
- Objective-C学习-KVC(键值编码)和KVO(键值观察)
- Hadoop笔记4--hdfs架构
- 零基础iOS之Json及XML数据解析2
- liunx定时执行任务命令 crontab使用
- virutalbox相关问题20150405
- Java实现的文件切割器和文件合并器代码
- 做递归题目时候的一个要点
- 编译原理及交叉编译
- Sudoku Solver
- ubuntu查找文件20150405
- .Net平台-MVP模式再探(二)
- MVC5+EF6 入门完整教程11--细说MVC中仓储模式的应用
- 零基础iOS之Json及XML数据解析
- Linux 下安装配置 JDK7
- Burp Suite说明文档(1)20150312
- 扩展:datagrid鼠标经过提示单元格内容