前一阵子由于做项目的需要,老大让expandlistview加如一个伸缩的动画,就是点击一个group的时候它的分组要向下慢慢的移动,类似都向下挤的效果,搜遍了百度,都说重写expandlistview,可都没说怎么写,无奈只有google,完美的解决了这个问题,下面是代码,

public class AnimatedExpandableListView extends ExpandableListView {/** A detailed explanation for how this class works:* * Animating the ExpandableListView was no easy task. The way that this* class does it is by exploiting how an ExpandableListView works.* * Normally when {@link ExpandableListView#collapseGroup(int)} or * {@link ExpandableListView#expandGroup(int)} is called, the view toggles * the flag for a group and calls notifyDataSetChanged to cause the ListView* to refresh all of it's view. This time however, depending on whether a* group is expanded or collapsed, certain childViews will either be ignored* or added to the list.* * Knowing this, we can come up with a way to animate our views. For * instance for group expansion, we tell the adapter to animate the* children of a certain group. We then expand the group which causes the* ExpandableListView to refresh all views on screen. The way that * ExpandableListView does this is by calling getView() in the adapter.* However since the adapter knows that we are animating a certain group,* instead of returning the real views for the children of the group being * animated, it will return a fake dummy view. This dummy view will then* draw the real child views within it's dispatchDraw function. The reason* we do this is so that we can animate all of it's children by simply * animating the dummy view. After we complete the animation, we tell the* adapter to stop animating the group and call notifyDataSetChanged. Now* the ExpandableListView is forced to refresh it's views again, except this* time, it will get the real views for the expanded group.* * So, to list it all out, when {@link #expandGroupWithAnimation(int)} is* called the following happens:* * 1. The ExpandableListView tells the adapter to animate a certain group.* 2. The ExpandableListView calls expandGroup.* 3. ExpandGroup calls notifyDataSetChanged.* 4. As an result, getChildView is called for expanding group.* 5. Since the adapter is in "animating mode", it will return a dummy view.* 6. This dummy view draws the actual children of the expanding group.* 7. This dummy view's height is animated from 0 to it's expanded height.* 8. Once the animation completes, the adapter is notified to stop*    animating the group and notifyDataSetChanged is called again.* 9. This forces the ExpandableListView to refresh all of it's views again.* 10.This time when getChildView is called, it will return the actual*    child views. *    * For animating the collapse of a group is a bit more difficult since we* can't call collapseGroup from the start as it would just ignore the* child items, giving up no chance to do any sort of animation. Instead* what we have to do is play the animation first and call collapseGroup* after the animation is done.* * So, to list it all out, when {@link #collapseGroupWithAnimation(int)} is* called the following happens:* * 1. The ExpandableListView tells the adapter to animate a certain group.* 2. The ExpandableListView calls notifyDataSetChanged.* 3. As an result, getChildView is called for expanding group.* 4. Since the adapter is in "animating mode", it will return a dummy view.* 5. This dummy view draws the actual children of the expanding group.* 6. This dummy view's height is animated from it's current height to 0.* 7. Once the animation completes, the adapter is notified to stop*    animating the group and notifyDataSetChanged is called again.* 8. collapseGroup is finally called.* 9. This forces the ExpandableListView to refresh all of it's views again.* 10.This time when the ListView will not get any of the child views for *    the collapsed group.*/private static final String TAG = AnimatedExpandableListAdapter.class.getSimpleName();/*** The duration of the expand/collapse animations*/private static final int ANIMATION_DURATION = 300;private AnimatedExpandableListAdapter adapter;public AnimatedExpandableListView(Context context) {super(context);}public AnimatedExpandableListView(Context context, AttributeSet attrs) {super(context, attrs);}public AnimatedExpandableListView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);}/*** @see ExpandableListView#setAdapter(ExpandableListAdapter)*/public void setAdapter(ExpandableListAdapter adapter) {super.setAdapter(adapter);// Make sure that the adapter extends AnimatedExpandableListAdapterif(adapter instanceof AnimatedExpandableListAdapter) {this.adapter = (AnimatedExpandableListAdapter) adapter;this.adapter.setParent(this);} else {throw new ClassCastException(adapter.toString() + " must implement AnimatedExpandableListAdapter");}}/*** Expands the given group with an animation.* @param groupPos The position of the group to expand* @return  Returns true if the group was expanded. False if the group was*          already expanded.*/public boolean expandGroupWithAnimation(int groupPos) {int groupFlatPos = getFlatListPosition(getPackedPositionForGroup(groupPos));if (groupFlatPos != -1) {int childIndex = groupFlatPos - getFirstVisiblePosition();if (childIndex < getChildCount()) {// Get the view for the group is it is on screen...View v = getChildAt(childIndex);if (v.getBottom() >= getBottom()) {// If the user is not going to be able to see the animation// we just expand the group without an animation.// This resolves the case where getChildView will not be// called if the children of the group is not on screen// We need to notify the adapter that the group was expanded// without it's knowledgeadapter.notifyGroupExpanded(groupPos);return expandGroup(groupPos);}}}// Let the adapter know that we are starting the animation...adapter.startExpandAnimation(groupPos, 0);// Finally call expandGroup (note that expandGroup will call// notifyDataSetChanged so we don't need to)return expandGroup(groupPos);}/*** Collapses the given group with an animation.* @param groupPos The position of the group to collapse* @return  Returns true if the group was collapsed. False if the group was*          already collapsed.*/public boolean collapseGroupWithAnimation(int groupPos) {int groupFlatPos = getFlatListPosition(getPackedPositionForGroup(groupPos));if (groupFlatPos != -1) {int childIndex = groupFlatPos - getFirstVisiblePosition();if (childIndex >= 0 && childIndex < getChildCount()) {// Get the view for the group is it is on screen...View v = getChildAt(childIndex);if (v.getBottom() >= getBottom()) {// If the user is not going to be able to see the animation// we just collapse the group without an animation.// This resolves the case where getChildView will not be// called if the children of the group is not on screenreturn collapseGroup(groupPos);}} else {// If the group is offscreen, we can just collapse it without an// animation...return collapseGroup(groupPos);}}// Get the position of the firstChild visible from the top of the screenlong packedPos = getExpandableListPosition(getFirstVisiblePosition());int firstChildPos = getPackedPositionChild(packedPos);int firstGroupPos = getPackedPositionGroup(packedPos);// If the first visible view on the screen is a child view AND it's a// child of the group we are trying to collapse, then set that// as the first child position of the group... see// {@link #startCollapseAnimation(int, int)} for why this is necessaryfirstChildPos = firstChildPos == -1 || firstGroupPos != groupPos ? 0 : firstChildPos;// Let the adapter know that we are going to start animating the // collapse animation.adapter.startCollapseAnimation(groupPos, firstChildPos);// Force the listview to refresh it's viewsadapter.notifyDataSetChanged();return isGroupExpanded(groupPos);}private int getAnimationDuration() {return ANIMATION_DURATION;}/*** Used for holding information regarding the group.*/private static class GroupInfo {boolean animating = false;boolean expanding = false;int firstChildPosition;/*** This variable contains the last known height value of the dummy view.* We save this information so that if the user collapses a group* before it fully expands, the collapse animation will start from the* CURRENT height of the dummy view and not from the full expanded * height.*/int dummyHeight = -1;}/*** A specialized adapter for use with the AnimatedExpandableListView. All* adapters used with AnimatedExpandableListView MUST extend this class.*/public static abstract class AnimatedExpandableListAdapter extends BaseExpandableListAdapter {private SparseArray<GroupInfo> groupInfo = new SparseArray<GroupInfo>();private AnimatedExpandableListView parent;private static final int STATE_IDLE = 0;private static final int STATE_EXPANDING = 1;private static final int STATE_COLLAPSING = 2;private void setParent(AnimatedExpandableListView parent) {this.parent = parent;}public int getRealChildType(int groupPosition, int childPosition) {return 0;}public int getRealChildTypeCount() {return 1;}public abstract View getRealChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent);public abstract int getRealChildrenCount(int groupPosition);private GroupInfo getGroupInfo(int groupPosition) {GroupInfo info = groupInfo.get(groupPosition);if (info == null) {info = new GroupInfo();groupInfo.put(groupPosition, info);}return info;}public void notifyGroupExpanded(int groupPosition) {GroupInfo info = getGroupInfo(groupPosition);info.dummyHeight = -1;}private void startExpandAnimation(int groupPosition, int firstChildPosition) {GroupInfo info = getGroupInfo(groupPosition);info.animating = true;info.firstChildPosition = firstChildPosition;info.expanding = true;}private void startCollapseAnimation(int groupPosition, int firstChildPosition) {GroupInfo info = getGroupInfo(groupPosition);info.animating = true;info.firstChildPosition = firstChildPosition;info.expanding = false;}private void stopAnimation(int groupPosition) {GroupInfo info = getGroupInfo(groupPosition);info.animating = false;}/*** Override {@link #getRealChildType(int, int)} instead.*/@Overridepublic final int getChildType(int groupPosition, int childPosition) {GroupInfo info = getGroupInfo(groupPosition);if (info.animating) {// If we are animating this group, then all of it's children // are going to be dummy views which we will say is type 0.return 0;} else {// If we are not animating this group, then we will add 1 to// the type it has so that no type id conflicts will occur// unless getRealChildType() returns MAX_INTreturn getRealChildType(groupPosition, childPosition) + 1;}}/*** Override {@link #getRealChildTypeCount()} instead.*/@Overridepublic final int getChildTypeCount() {// Return 1 more than the childTypeCount to account for DummyViewreturn getRealChildTypeCount() + 1;}/*** Override {@link #getChildView(int, int, boolean, View, ViewGroup)} instead.*/@Overridepublic final View getChildView(final int groupPosition, int childPosition, boolean isLastChild, View convertView, final ViewGroup parent) {final GroupInfo info = getGroupInfo(groupPosition);if (info.animating) {// If this group is animating, return the a DummyView...if (convertView == null) {convertView = new DummyView(parent.getContext());convertView.setLayoutParams(new AbsListView.LayoutParams(LayoutParams.MATCH_PARENT, 0));}if (childPosition < info.firstChildPosition) {// The reason why we do this is to support the collapse// this group when the group view is not visible but the // children of this group are. When notifyDataSetChanged// is called, the ExpandableListView tries to keep the // list position the same by saving the first visible item// and jumping back to that item after the views have been// refreshed. Now the problem is, if a group has 2 items// and the first visible item is the 2nd child of the group// and this group is collapsed, then the dummy view will be // used for the group. But now the group only has 1 item // which is the dummy view, thus when the ListView is trying// to restore the scroll position, it will try to jump to // the second item of the group. But this group no longer// has a second item, so it is forced to jump to the next// group. This will cause a very ugly visual glitch. So// the way that we counteract this is by creating as many// dummy views as we need to maintain the scroll position// of the ListView after notifyDataSetChanged has been // called.convertView.getLayoutParams().height = 0;return convertView;}final ExpandableListView listView = (ExpandableListView) parent;final DummyView dummyView = (DummyView) convertView;// Clear the views that the dummy view draws.dummyView.clearViews();// Set the style of the dividerdummyView.setDivider(listView.getDivider(), parent.getMeasuredWidth(), listView.getDividerHeight());// Make measure specs to measure child viewsfinal int measureSpecW = MeasureSpec.makeMeasureSpec(parent.getWidth(), MeasureSpec.EXACTLY);final int measureSpecH = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);int totalHeight = 0;int clipHeight = parent.getHeight();final int len = getRealChildrenCount(groupPosition);for (int i = info.firstChildPosition; i < len; i++) {View childView = getRealChildView(groupPosition, i, (i == len - 1), null, parent);childView.measure(measureSpecW, measureSpecH);totalHeight += childView.getMeasuredHeight();if (totalHeight < clipHeight) {// we only need to draw enough views to fool the user...dummyView.addFakeView(childView);} else {dummyView.addFakeView(childView);// if this group has too many views, we don't want to // calculate the height of everything... just do a light // approximation and breakint averageHeight = totalHeight / (i + 1);totalHeight += (len - i - 1) * averageHeight;break;}}Object o;int state = (o = dummyView.getTag()) == null ? STATE_IDLE : (Integer) o;if (info.expanding && state != STATE_EXPANDING) {ExpandAnimation ani = new ExpandAnimation(dummyView, 0, totalHeight, info);ani.setDuration(this.parent.getAnimationDuration());ani.setAnimationListener(new AnimationListener() {@Overridepublic void onAnimationEnd(Animation animation) {stopAnimation(groupPosition);notifyDataSetChanged();dummyView.setTag(STATE_IDLE);}@Overridepublic void onAnimationRepeat(Animation animation) {}@Overridepublic void onAnimationStart(Animation animation) {}});dummyView.startAnimation(ani);dummyView.setTag(STATE_EXPANDING);} else if (!info.expanding && state != STATE_COLLAPSING) {if (info.dummyHeight == -1) {info.dummyHeight = totalHeight;}ExpandAnimation ani = new ExpandAnimation(dummyView, info.dummyHeight, 0, info);ani.setDuration(this.parent.getAnimationDuration());ani.setAnimationListener(new AnimationListener() {@Overridepublic void onAnimationEnd(Animation animation) {stopAnimation(groupPosition);listView.collapseGroup(groupPosition);notifyDataSetChanged();info.dummyHeight = -1;dummyView.setTag(STATE_IDLE);}@Overridepublic void onAnimationRepeat(Animation animation) {}@Overridepublic void onAnimationStart(Animation animation) {}});dummyView.startAnimation(ani);dummyView.setTag(STATE_COLLAPSING);}return convertView;} else {return getRealChildView(groupPosition, childPosition, isLastChild, convertView, parent);}}@Overridepublic final int getChildrenCount(int groupPosition) {GroupInfo info = getGroupInfo(groupPosition);if (info.animating) {return info.firstChildPosition + 1;} else {return getRealChildrenCount(groupPosition);}}}private static class DummyView extends View {private List<View> views = new ArrayList<View>();private Drawable divider;private int dividerWidth;private int dividerHeight;public DummyView(Context context) {super(context);}public void setDivider(Drawable divider, int dividerWidth, int dividerHeight) {this.divider = divider;this.dividerWidth = dividerWidth;this.dividerHeight = dividerHeight;divider.setBounds(0, 0, dividerWidth, dividerHeight);}/*** Add a view for the DummyView to draw.* @param childView View to draw*/public void addFakeView(View childView) {childView.layout(0, 0, getWidth(), getHeight());views.add(childView);}@Overrideprotected void onLayout(boolean changed, int left, int top, int right, int bottom) {super.onLayout(changed, left, top, right, bottom);final int len = views.size();for(int i = 0; i < len; i++) {View v = views.get(i);v.layout(left, top, right, bottom);}}public void clearViews() {views.clear();}@Overridepublic void dispatchDraw(Canvas canvas) {canvas.save();divider.setBounds(0, 0, dividerWidth, dividerHeight);final int len = views.size();for(int i = 0; i < len; i++) {View v = views.get(i);v.draw(canvas);canvas.translate(0, v.getMeasuredHeight());divider.draw(canvas);canvas.translate(0, dividerHeight);}canvas.restore();}}private static class ExpandAnimation extends Animation { private int baseHeight;private int delta;private View view;private GroupInfo groupInfo;private ExpandAnimation(View v, int startHeight, int endHeight, GroupInfo info) {baseHeight = startHeight;delta = endHeight - startHeight;view = v;groupInfo = info;view.getLayoutParams().height = startHeight;view.requestLayout();}@Overrideprotected void applyTransformation(float interpolatedTime, Transformation t) {super.applyTransformation(interpolatedTime, t);if (interpolatedTime < 1.0f) {int val = baseHeight + (int) (delta * interpolatedTime);view.getLayoutParams().height = val;groupInfo.dummyHeight = val;view.requestLayout();} else {int val = baseHeight + delta;view.getLayoutParams().height = val;groupInfo.dummyHeight = val;view.requestLayout();}}}
}

在mainactivity中实现这个方法

  listView.setOnGroupClickListener(new OnGroupClickListener() {@Overridepublic boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {// We call collapseGroupWithAnimation(int) and// expandGroupWithAnimation(int) to animate group // expansion/collapse.if (listView.isGroupExpanded(groupPosition)) {listView.collapseGroupWithAnimation(groupPosition);} else {listView.expandGroupWithAnimation(groupPosition);}return true;}});

这样就可以解决expandlistiew没有动画的问题了

下载连接 http://download.csdn.net/detail/a403991842/7655937

expandlistview 加伸缩的动画相关推荐

  1. WPF 加载等待动画

    WPF 加载等待动画 原文:WPF 加载等待动画 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/qq_29844879/article/detail ...

  2. ios 旋转加载gif_加载GIF动画方法 iOS

    方法一 使用UIWebView _codeStr为gif网址      如果是本地的gif可以直接使用dataWithContentsOfFile方法 NSData *data = [NSData d ...

  3. CSharpGL(50)使用Assimp加载骨骼动画

    CSharpGL(50)使用Assimp加载骨骼动画 在(http://ogldev.atspace.co.uk/www/tutorial38/tutorial38.html)介绍了C++用Asism ...

  4. html 载入中,用纯CSS实现加载中动画效果

    今天要介绍的是用简单的CSS--只用CSS,不用Gif--制作"加载中-"动画效果.先看看效果: 上面的这个加载中效果,以前是用gif动图实现的,但随着CSS的进步,CSS动画功能 ...

  5. 加载数据时,页面显示正在加载的动画,支持移动端

    最近在使用ionic3做一个移动端APP,在用户网络环境差的时候,查询数据会比较慢,这个时候需要模拟其他成熟的APP给页面上加入一个加载的动画.由于一开始我不知道ionic3本身已经提供了一套组件,所 ...

  6. android刷新时的圆形动画_Android自定义加载圈动画效果

    本文实例为大家分享了Android自定义加载圈动画展示的具体代码,供大家参考,具体内容如下 实现如下效果: 该效果图主要有3个动画: 1.旋转动画 2.聚合动画 3.扩散动画 以上3个动画都是通过Va ...

  7. WBLoadingIndicatorView(加载等待动画)

    中文说明 基于CALayer封装加载等待动画,目前支持6种类型动画: typedef NS_ENUM(NSInteger, WBLoadingAnimationType) { WBLoadingAni ...

  8. html间隔代码_HTML+CSS基础入门开发,经典Loading加载缩放动画特效

    大家好,本篇文章分享经典Loading加载缩放动画特效,欢迎参考和指正. 效果图: Loading加载缩放动画特效 HTML代码: CSS代码: 知识点: animation:是CSS3的动画属性,这 ...

  9. PhP加载时显示动画,在ajax请求完之前的loading加载的动画效果实现

    这篇文章给大家介绍的内容是关于在ajax请求完之前的loading加载的动画效果实现,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 很多时候我们需要引入框架来开发项目,这时我们可能会 ...

最新文章

  1. NIO详解(十二):AsynchronousFileChannel详解
  2. 0-2岁的app开发人员必读,Android开发APP前的准备事项
  3. Hibernate--使用xml配置映射关系
  4. SBO错误提示总帐科目缺失解决方法
  5. 启动TOMCAT报错 java.util.zip.ZipException: invalid LOC header (bad signature)
  6. 数据库基础入门知识总结
  7. 论文笔记 - 《Deep Learning》(Yann LeCun Yoshua Bengio Geoffrey Hinton)经典
  8. python实现高级计算器_Python实现的复杂的计算器的代码
  9. cad一键卸载工具叫什么_CAD专用卸载修复工具,一键完全彻底卸载删除CAD软件的专用卸载工具...
  10. 金字塔图表 html,Highcharts 柱形图(柱状图及条形图)之 金字塔图 演示
  11. 试题B:灭鼠先锋[博弈]
  12. Autojs: 坚果云文本文件上传/下载
  13. 架构设计文档模板之1:备选方案模板
  14. 20210323 美团后台开发实习一面(快驴)
  15. 软件测试行业就业前景到底怎么样?
  16. c++海岛战争(无关机代码)
  17. 温度传感器DS18B20应用
  18. 【题解】少女觉 (2019.08.12纪中【NOIP提高组】模拟 B 组T1)贪心
  19. 发票账单很多?python助你批量完成数据提取
  20. Oracle删除索引 判断,Oracle索引(index)的分类、建立与删除

热门文章

  1. python给word添加水印_python 批量给 word,excel,ppt 或 pdf 文件添加水印
  2. 聊一聊微信小程序包内容
  3. 【软件工程综合实践】简单工厂模式之蛋糕店(完整代码)
  4. 云和数据第六届中国创业者大会英雄云集 继续点燃创业者心中热火
  5. EP2嵌入式宏空间坐标数量
  6. 私域运营_技巧全套攻略(共207份)
  7. 从键盘输入一个月号(1-12),并显示该月号的英文名称
  8. 软件推荐【2016-3-12 17:28:46】
  9. applyhatch无法识别
  10. edge浏览器 开启java_Selenium+java - Edge浏览器启动