ListView添加Item动画以及四种冲突情况的解决办法
来源:互联网 发布:局域网 封端口 编辑:程序博客网 时间:2024/06/08 16:30
1. 动画功能的基本实现
首先我们梳理一下需求
- 界面上有三个元素,一个开启动画按钮start,一个关闭动画按钮end,一个ListView展示数据
- ListView默认是GONE的
- 点击开启动画按钮前,需要先将ListView置为VISIBLE,然后再开启动画。开启之后默认展示第一项。
- 点击关闭动画按钮后,在动画执行结束后,将ListView置为GONE。
- 点击ListView的Item后,也执行第4步骤的关闭动画操作。
我们知道,ViewGroup的动画需要LayoutAnimationController来支持,那么ListView继承于ViewGroup,当然也是通过LayoutAnimationController来实现Item的动画。这里需要注意的是,怎么拿到ListView最后一项Item的动画结束后的监听回调呢?代码如下:
/** * Created by chenchen on 2016/11/25. */public class ListViewAnimationListener implements Animation.AnimationListener { private int count = 0; private ListView listView; private OnAnimationFinishListener listener; public ListViewAnimationListener(ListView listView, OnAnimationFinishListener listener) { this.listView = listView; this.listener = listener; } @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { // 没有子控件,则直接完成 if(listView.getChildCount() == 0){ if(listener != null){ listener.onFinish(); } }else{ count++; if(count == listView.getChildCount() && listener != null){ listener.onFinish(); reset(); } } } @Override public void onAnimationRepeat(Animation animation) { } public void reset(){ count = 0; } public interface OnAnimationFinishListener{ void onFinish(); }}
代码很少,可以看出具体的逻辑是:每次动画结束时使变量count自增,当count等于listView的getChildCount()时,我们认为所有的Item的动画结束了。至于为什么是getChildCount()而不是adapter的getCount()呢?我们知道ListView的缓存原理,内存中始终只有屏幕可见个Item,因此动画是实际作用于真实存在内存中的Item。
好了,接下来贴出全部代码,其他部分就很简单了。
首先是两个动画文件:
<!-- translate_in --><?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android"> <translate xmlns:android="http://schemas.android.com/apk/res/android" android:fromXDelta="-100%p" android:toXDelta="0%p" android:duration="100"/></set><!-- translate_out --><?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android"> <translate xmlns:android="http://schemas.android.com/apk/res/android" android:fromXDelta="0%p" android:toXDelta="-100%p" android:duration="100" /></set>
然后是ListView的item文件,很简单
<?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="wrap_content" android:gravity="center_vertical" android:orientation="horizontal"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@mipmap/ic_launcher" /> <TextView android:id="@+id/txt" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:textColor="@android:color/black" android:textSize="15sp" /></LinearLayout>
然后是activity_main.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" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="60dp" android:orientation="horizontal" android:paddingLeft="20dp" android:paddingRight="20dp" > <Button android:id="@+id/start" android:layout_width="0dp" android:layout_weight="1" android:layout_height="match_parent" android:gravity="center" android:text="开启列表动画" android:textSize="18sp" android:textColor="#333333" /> <Button android:id="@+id/end" android:layout_width="0dp" android:layout_weight="1" android:layout_height="match_parent" android:layout_marginLeft="20dp" android:gravity="center" android:text="关闭列表动画" android:textSize="18sp" android:textColor="#333333" /> </LinearLayout> <ListView android:id="@+id/listView" android:layout_width="match_parent" android:layout_height="match_parent" android:cacheColorHint="@android:color/transparent" android:listSelector="@android:color/transparent" android:divider="#f1f1f1" android:dividerHeight="1px" android:visibility="gone" /></LinearLayout>
最后是MainActivity文件
public class MainActivity extends Activity { private ListView listView; private MyAdapter adapter; //动画控制器,针对ViewGroup的动画 private LayoutAnimationController inAnimationController; private LayoutAnimationController outAnimationController; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initListView(); initBaseUI(); } private void initBaseUI() { findViewById(R.id.start).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { oepnAnim(); } }); findViewById(R.id.end).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { closeAnim(); } }); } private void initListView() { listView = (ListView) findViewById(R.id.listView); adapter = new MyAdapter(); listView.setAdapter(adapter); //设置点击监听器 listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { closeAnim(); } }); //入场动画 Animation inAnimation = AnimationUtils.loadAnimation(this, R.anim.translate_in); inAnimation.setFillAfter(true); inAnimationController = new LayoutAnimationController(inAnimation); inAnimationController.setOrder(LayoutAnimationController.ORDER_NORMAL); inAnimationController.setDelay(0.2f); //设置动画结束监听器 ListViewAnimationListener inAnimationListener = new ListViewAnimationListener(listView, new ListViewAnimationListener.OnAnimationFinishListener() { @Override public void onFinish() { } }); inAnimation.setAnimationListener(inAnimationListener); //出场动画 Animation outAnimation = AnimationUtils.loadAnimation(this, R.anim.translate_out); outAnimation.setFillAfter(true); outAnimationController = new LayoutAnimationController(outAnimation); outAnimationController.setOrder(LayoutAnimationController.ORDER_NORMAL); outAnimationController.setDelay(0.2f); //设置动画结束监听器 ListViewAnimationListener outAnimationListener = new ListViewAnimationListener(listView, new ListViewAnimationListener.OnAnimationFinishListener() { @Override public void onFinish() { listView.setVisibility(View.GONE); } }); outAnimation.setAnimationListener(outAnimationListener); } public class MyAdapter extends BaseAdapter{ @Override public int getCount() { return 30; } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = null; if(convertView == null){ convertView = View.inflate(MainActivity.this, R.layout.item, null); holder = new ViewHolder(convertView); convertView.setTag(holder); }else{ holder = (ViewHolder) convertView.getTag(); } holder.fillData(position); return convertView; } public class ViewHolder{ private TextView txt; public ViewHolder(View rootView) { txt = (TextView) rootView.findViewById(R.id.txt); } public void fillData(int position){ txt.setText("测试" + position); } } } private void oepnAnim(){ if(listView.getVisibility() == View.GONE){ //每次打开都在第一行 listView.setSelection(0); listView.setVisibility(View.VISIBLE); listView.setLayoutAnimation(inAnimationController); listView.startLayoutAnimation(); } } private void closeAnim(){ if(listView.getVisibility() == View.VISIBLE){ listView.setLayoutAnimation(outAnimationController); listView.startLayoutAnimation(); } }}
2. 解决动画之间的冲突
做了以上部分,你就以为能够交差了?No,还差的很远。不信?连续点两次开启动画试试?是不是觉得这样的代码提交上去会被喷?
我列举了以下需要优化的地方:
- 连续快速点击两次开启动画按钮
- 连续快速点击两次关闭动画按钮
- 连续快速点击两次ListView的item
- 快速先点击开启动画按钮,再点击关闭动画按钮
- 快速先点击关闭动画按钮,再点击开启动画按钮
- 快速先点击开启动画按钮,再点击ListView的item
- 快速先点击ListView的item,再点击开启动画按钮
- 快速先点击关闭动画按钮,再点击ListView的item
- 快速先点击ListView的item,再点击开启动画按钮
看到上述9种情况,是不是瞬间觉得蛋疼无比?其实我们可以总结出一条规律:
再开启动画的过程中,不允许再开启第二个动画,否则视觉上会很奇怪
那么如何解决这个问题呢?很简单,只需要给出两个布尔变量canOpenAnim和canCloseAnim,表示是否允许开启open动画和close动画,在开启动画时,首先判断canOpenAnim或canCloseAnim的值,然后将canOpenAnim和canCloseAnim都置为false,在动画的完成监听器中再将canOpenAnim和canCloseAnim都置为true。这样就可以避免两个动画同时开启的尴尬。下面给出具体的代码:
public class MainActivity extends Activity { private ListView listView; private MyAdapter adapter; //动画控制器,针对ViewGroup的动画 private LayoutAnimationController inAnimationController; private LayoutAnimationController outAnimationController; //控制解决连续多次动画的冲突 private boolean canOpenAnim = true; private boolean canCloseAnim = true; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initListView(); initBaseUI(); } private void initBaseUI() { findViewById(R.id.start).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { openAnim(); } }); findViewById(R.id.end).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { closeAnim(); } }); } private void initListView() { listView = (ListView) findViewById(R.id.listView); adapter = new MyAdapter(); listView.setAdapter(adapter); //设置点击监听器 listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { closeAnim(); } }); //入场动画 Animation inAnimation = AnimationUtils.loadAnimation(this, R.anim.translate_in); inAnimation.setFillAfter(true); inAnimationController = new LayoutAnimationController(inAnimation); inAnimationController.setOrder(LayoutAnimationController.ORDER_NORMAL); inAnimationController.setDelay(0.2f); //设置动画结束监听器 ListViewAnimationListener inAnimationListener = new ListViewAnimationListener(listView, new ListViewAnimationListener.OnAnimationFinishListener() { @Override public void onFinish() { canOpenAnim = true; canCloseAnim = true; } }); inAnimation.setAnimationListener(inAnimationListener); //出场动画 Animation outAnimation = AnimationUtils.loadAnimation(this, R.anim.translate_out); outAnimation.setFillAfter(true); outAnimationController = new LayoutAnimationController(outAnimation); outAnimationController.setOrder(LayoutAnimationController.ORDER_NORMAL); outAnimationController.setDelay(0.2f); //设置动画结束监听器 ListViewAnimationListener outAnimationListener = new ListViewAnimationListener(listView, new ListViewAnimationListener.OnAnimationFinishListener() { @Override public void onFinish() { canOpenAnim = true; canCloseAnim = true; listView.setVisibility(View.GONE); } }); outAnimation.setAnimationListener(outAnimationListener); } public class MyAdapter extends BaseAdapter{ @Override public int getCount() { return 30; } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = null; if(convertView == null){ convertView = View.inflate(MainActivity.this, R.layout.item, null); holder = new ViewHolder(convertView); convertView.setTag(holder); }else{ holder = (ViewHolder) convertView.getTag(); } holder.fillData(position); return convertView; } public class ViewHolder{ private TextView txt; public ViewHolder(View rootView) { txt = (TextView) rootView.findViewById(R.id.txt); } public void fillData(int position){ txt.setText("测试" + position); } } } private void openAnim(){ if(canOpenAnim && listView.getVisibility() == View.GONE){ //要将两个标记都置为false,在动画的结束监听器中置为true canOpenAnim = false; canCloseAnim = false; //每次打开都在第一行 listView.setSelection(0); listView.setVisibility(View.VISIBLE); listView.setLayoutAnimation(inAnimationController); listView.startLayoutAnimation(); } } private void closeAnim(){ if(canCloseAnim && listView.getVisibility() == View.VISIBLE){ //要将两个标记都置为false,在动画的结束监听器中置为true canOpenAnim = false; canCloseAnim = false; listView.setLayoutAnimation(outAnimationController); listView.startLayoutAnimation(); } }}
3. 动画与滑动时的冲突解决
当你弄完上面的代码之后,难道你以为就这么结束了?我还是要笑你太天真了。现在这样做:在点击开启动画的一瞬间,马上滑动ListView,此时是不是看见了很多Item是空白的?这是为什么呢?
我们知道ListView是有View的缓存的,在滚动的时候会自动将缓存的View进行再利用。此时开启动画是针对ListView内存中真实存在的View,也就是说在动画的时候再滑动,动画会与ListView的缓存策略相互冲突。主要有以下几种情况:
- 点击开启动画按钮时,马上滑动ListView
- 点击关闭动画按钮时,马上滑动ListView
- 点击ListView的item时,再马上滑动ListView
- 滑动ListView时,点击开启动画按钮
- 滑动ListView时,点击关闭动画按钮
- 滑动ListView时,再点击ListView的item
看见这么大一堆情况,是不是瞬间又懵逼了?不用怕,其实可以总结如下:
动画时要禁止ListView的滑动,滑动时要禁止ListView的动画
- 禁止ListView的滑动可以通过设置ListView的setEnable(false),在开启动画时setEnabled(false),在动画完毕时设置setEnabled(true)
- 滑动时禁止动画需要在OnScrollListener监听器回调中处理,当scrollState为SCROLL_STATE_IDLE时canOpenAnim和canCloseAnim设置为true,其他状态设置为false。
public class MainActivity extends Activity { private ListView listView; private MyAdapter adapter; //动画控制器,针对ViewGroup的动画 private LayoutAnimationController inAnimationController; private LayoutAnimationController outAnimationController; //控制解决连续多次动画的冲突 private boolean canOpenAnim = true; private boolean canCloseAnim = true; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initListView(); initBaseUI(); } private void initBaseUI() { findViewById(R.id.start).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { openAnim(); } }); findViewById(R.id.end).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { closeAnim(); } }); } private void initListView() { listView = (ListView) findViewById(R.id.listView); adapter = new MyAdapter(); listView.setAdapter(adapter); //设置点击监听器 listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { closeAnim(); } }); listView.setOnScrollListener(new AbsListView.OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { if(scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE){ //停止状态,允许开启关闭动画 canOpenAnim = true; canCloseAnim = true; }else{ canOpenAnim = false; canCloseAnim = false; } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { } }); //入场动画 Animation inAnimation = AnimationUtils.loadAnimation(this, R.anim.translate_in); inAnimation.setFillAfter(true); inAnimationController = new LayoutAnimationController(inAnimation); inAnimationController.setOrder(LayoutAnimationController.ORDER_NORMAL); inAnimationController.setDelay(0.2f); //设置动画结束监听器 ListViewAnimationListener inAnimationListener = new ListViewAnimationListener(listView, new ListViewAnimationListener.OnAnimationFinishListener() { @Override public void onFinish() { canOpenAnim = true; canCloseAnim = true; //恢复ListView的enabled属性 listView.setEnabled(true); } }); inAnimation.setAnimationListener(inAnimationListener); //出场动画 Animation outAnimation = AnimationUtils.loadAnimation(this, R.anim.translate_out); outAnimation.setFillAfter(true); outAnimationController = new LayoutAnimationController(outAnimation); outAnimationController.setOrder(LayoutAnimationController.ORDER_NORMAL); outAnimationController.setDelay(0.2f); //设置动画结束监听器 ListViewAnimationListener outAnimationListener = new ListViewAnimationListener(listView, new ListViewAnimationListener.OnAnimationFinishListener() { @Override public void onFinish() { canOpenAnim = true; canCloseAnim = true; //恢复ListView的enabled属性 listView.setEnabled(true); listView.setVisibility(View.GONE); } }); outAnimation.setAnimationListener(outAnimationListener); } public class MyAdapter extends BaseAdapter{ @Override public int getCount() { return 30; } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = null; if(convertView == null){ convertView = View.inflate(MainActivity.this, R.layout.item, null); holder = new ViewHolder(convertView); convertView.setTag(holder); }else{ holder = (ViewHolder) convertView.getTag(); } holder.fillData(position); return convertView; } public class ViewHolder{ private TextView txt; public ViewHolder(View rootView) { txt = (TextView) rootView.findViewById(R.id.txt); } public void fillData(int position){ txt.setText("测试" + position); } } } private void openAnim(){ if(canOpenAnim && listView.getVisibility() == View.GONE){ //要将两个标记都置为false,在动画的结束监听器中置为true canOpenAnim = false; canCloseAnim = false; //每次打开都在第一行 listView.setSelection(0); listView.setVisibility(View.VISIBLE); //设置ListView的enabled属性使不可滑动 listView.setEnabled(false); listView.setLayoutAnimation(inAnimationController); listView.startLayoutAnimation(); } } private void closeAnim(){ if(canCloseAnim && listView.getVisibility() == View.VISIBLE){ //要将两个标记都置为false,在动画的结束监听器中置为true canOpenAnim = false; canCloseAnim = false; //设置ListView的enabled属性使不可滑动 listView.setEnabled(false); listView.setLayoutAnimation(outAnimationController); listView.startLayoutAnimation(); } }}
4. 动画与ListView的缓存机制的冲突
当你完成了第3步,你是不是心里觉得这样总该差不多了吧?我只能告诉你快成功了,还有一个很关键的地方没有处理到。你也许想说,连滚动时的ListView的缓存机制都处理了,还能有什么情况?其实,滑动冲突只是缓存机制的一种情况,还有另外一种情况。这种情况出现在我项目中很长时间,一直没有找到对应的原因和解决办法。在一次偶然的机会我找到了原因,不看你肯定会后悔。
现在你这样做:首先点击开启动画按钮,将ListView展现出来,此时我的设备上展示了“测试0”到“测试23”一共24个Item,其中“测试23”只显示了部分。关键:现在往上滑动一点,让屏幕显示出“测试0”到“测试24”一共25个Item,其中“测试0”和“测试24”都是只显示了部分。你只需要保证滑动后的Item数会多一个就行。此时你点击关闭动画按钮,再点击开启动画按钮,往上滑动一点点,是不是发现了“测试24”这一项是一个空白呢?
为什么会这样呢?相信有的小伙伴儿已经心里有了答案。在关闭动画时,ListView有24项,在开启动画时,由于此时调用了setSession(0)方法,此时ListView只有23项,所以此时动画只针对这23项进行动画,而对第24项因为内部机制问题导致没有draw。
怎么解决呢?其实也是非常简单,在关闭动画开启前,手动再调用一次setSession(0),保证关闭动画和开启动画时,ListView的Item数是相同的就行。
因为改动比较小,只添加了一行代码,因此就只粘贴这一段方法就行了:
private void closeAnim(){ if(canCloseAnim && listView.getVisibility() == View.VISIBLE){ //要将两个标记都置为false,在动画的结束监听器中置为true canOpenAnim = false; canCloseAnim = false; //关闭动画时,保证此时的Item数与开启动画时相等,否则会产生最后一项不绘制的问题 listView.setSelection(0); //设置ListView的enabled属性使不可滑动 listView.setEnabled(false); listView.setLayoutAnimation(outAnimationController); listView.startLayoutAnimation(); }}
5. 点击耗时任务处理时与滑动的冲突
本来完成了第4步,的确算大功告成了,但是在一次偶然的机会,我又玩出了一种冲突情况,这种情况就非常复杂了。
当我点击了Item响应OnItemClick后,先调用setEnabled(false),然后开启关闭动画,然后在动画监听器回调中,在调用了setEnabled(true)时,此时如果我再滑动ListView,由于enabled为true,visibility为VISIBLE,因此是可以滑动的,但是因为会马上执行动画监听器回调的后续代码,也就是调用setVisibility(View.GONE),因此此时的滑动效果是看不见的,但是的确是在滑动。此时如果滑动刚好导致Item数多了一个,那么下次再开启打开动画时,会导致最后一项无法绘制的问题,原因第4步已经讲了。
也就是说,如果onItemClick比较耗时,此时点击一个item时,立刻使劲儿滑动ListView,会有一定几率导致下一次打开ListView时有一项无法绘制是空白项。
怎么解决呢?其实也很简单。一切都是在关闭动画监听器中设置了setEnabled(true)导致的,那么可以将这行代码注释掉,因为在开启动画监听器一定会调用setEnabled(true)。屏蔽掉在关闭动画后还有一定几率对ListView进行操作的情况。
//设置动画结束监听器ListViewAnimationListener outAnimationListener = new ListViewAnimationListener(listView, new ListViewAnimationListener.OnAnimationFinishListener() { @Override public void onFinish() { canOpenAnim = true; canCloseAnim = true; //关闭动画后不释放enabled,在开启动画后释放,否则会在点击后使劲儿滑动ListView, //会有一定几率造成ListView滑动,造成Item数多一个,导致ListView最后一项无法绘制// listView.setEnabled(true); listView.setVisibility(View.GONE); }});
6. 解决所有冲突的完整的Activity代码
public class MainActivity extends Activity { private ListView listView; private MyAdapter adapter; //动画控制器,针对ViewGroup的动画 private LayoutAnimationController inAnimationController; private LayoutAnimationController outAnimationController; //控制解决连续多次动画的冲突 private boolean canOpenAnim = true; private boolean canCloseAnim = true; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initListView(); initBaseUI(); } private void initBaseUI() { findViewById(R.id.start).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { openAnim(); } }); findViewById(R.id.end).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { closeAnim(); } }); } private void initListView() { listView = (ListView) findViewById(R.id.listView); adapter = new MyAdapter(); listView.setAdapter(adapter); //设置点击监听器 listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { closeAnim(); } }); listView.setOnScrollListener(new AbsListView.OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { if(scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE){ //停止状态,允许开启关闭动画 canOpenAnim = true; canCloseAnim = true; }else{ canOpenAnim = false; canCloseAnim = false; } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { } }); //入场动画 Animation inAnimation = AnimationUtils.loadAnimation(this, R.anim.translate_in); inAnimation.setFillAfter(true); inAnimationController = new LayoutAnimationController(inAnimation); inAnimationController.setOrder(LayoutAnimationController.ORDER_NORMAL); inAnimationController.setDelay(0.2f); //设置动画结束监听器 ListViewAnimationListener inAnimationListener = new ListViewAnimationListener(listView, new ListViewAnimationListener.OnAnimationFinishListener() { @Override public void onFinish() { canOpenAnim = true; canCloseAnim = true; //恢复ListView的enabled属性 listView.setEnabled(true); } }); inAnimation.setAnimationListener(inAnimationListener); //出场动画 Animation outAnimation = AnimationUtils.loadAnimation(this, R.anim.translate_out); outAnimation.setFillAfter(true); outAnimationController = new LayoutAnimationController(outAnimation); outAnimationController.setOrder(LayoutAnimationController.ORDER_NORMAL); outAnimationController.setDelay(0.2f); //设置动画结束监听器 ListViewAnimationListener outAnimationListener = new ListViewAnimationListener(listView, new ListViewAnimationListener.OnAnimationFinishListener() { @Override public void onFinish() { canOpenAnim = true; canCloseAnim = true; //关闭动画后不释放enabled,在开启动画后释放,否则会在点击后使劲儿滑动ListView, //会有一定几率造成ListView滑动,造成Item数多一个,导致ListView最后一项无法绘制// listView.setEnabled(true); listView.setVisibility(View.GONE); } }); outAnimation.setAnimationListener(outAnimationListener); } public class MyAdapter extends BaseAdapter{ @Override public int getCount() { return 30; } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = null; if(convertView == null){ convertView = View.inflate(MainActivity.this, R.layout.item, null); holder = new ViewHolder(convertView); convertView.setTag(holder); }else{ holder = (ViewHolder) convertView.getTag(); } holder.fillData(position); return convertView; } public class ViewHolder{ private TextView txt; public ViewHolder(View rootView) { txt = (TextView) rootView.findViewById(R.id.txt); } public void fillData(int position){ txt.setText("测试" + position); } } } private void openAnim(){ if(canOpenAnim && listView.getVisibility() == View.GONE){ //要将两个标记都置为false,在动画的结束监听器中置为true canOpenAnim = false; canCloseAnim = false; //每次打开都在第一行 listView.setSelection(0); listView.setVisibility(View.VISIBLE); //设置ListView的enabled属性使不可滑动 listView.setEnabled(false); listView.setLayoutAnimation(inAnimationController); listView.startLayoutAnimation(); } } private void closeAnim(){ if(canCloseAnim && listView.getVisibility() == View.VISIBLE){ //要将两个标记都置为false,在动画的结束监听器中置为true canOpenAnim = false; canCloseAnim = false; //关闭动画时,保证此时的Item数与开启动画时相等,否则会产生最后一项不绘制的问题 listView.setSelection(0); //设置ListView的enabled属性使不可滑动 listView.setEnabled(false); listView.setLayoutAnimation(outAnimationController); listView.startLayoutAnimation(); } }}
- ListView添加Item动画以及四种冲突情况的解决办法
- listView 的item添加动画
- ListView item的点击冲突解决办法
- listview的item动画
- Android为listview的item添加动画效果
- listview中添加Button后item不能点击的解决办法
- 菜单(四)给ListView的item添加上下文菜单
- 给Android ListView添加删除item动画
- 给Android ListView添加删除item动画
- OnGestureListener和listView以及GridView冲突的解决办法
- ListView的item删除动画
- ListView删除Item的动画
- ListView的item动画效果
- ListView控件的onItemClick事件和item中Button的onClick事件冲突的解决办法
- Listview、RecyclerView中的item中包含可以点击的控件,点击冲突解决办法
- Listview、RecyclerView中的item中包含可以点击的控件,点击冲突解决办法
- RecyclerView 动画 (添加、删除动画 以及 加载item 时的动画)
- ListView中的Item点击事件和子控件的冲突或者item点击没有反应的解决办法
- Windows系统优化(个人整理)
- 数值与string相互转换(C#)(转)
- JS FileReader 图片的本地预览
- HTML 中的空格
- 散列表的基本原理与实现
- ListView添加Item动画以及四种冲突情况的解决办法
- 工作线程数究竟要设置为多少
- HDU 2086:A!=? (数学推导)
- 520. Detect Capital
- 剑指offer面试题[35]-第一个只出现一次的字符
- 2017西安交大ACM小学期 刁钻的顾客[3进制+折半枚举]
- Java动态代理机制详解(JDK 和CGLIB,Javassist,ASM)
- c语言中的动态内存管理
- 系统吞吐量、TPS(QPS)、用户并发量、性能测试概念和公式