Github项目
git@github.com:tjerkw/Android-SlideExpandableListView.git
最近项目中有一个列表展示的效果,ExpandableListView的样式,但是要求列表展开关闭的时候有滑动效果,貌似ExpandableListView实现起来比较麻烦,开始时参考了git@github.com:idunnololz/AnimatedExpandableListView.git
这个项目,但是效果并不理想,于是使用了本文开篇的项目。下面对这个动画源码分析一下,加深理解。
1. 项目结构
类图如下:
结构很简单,一个自定义的ListView
和一个自定义的ListAdapter
,view
部分绑定按钮的事件,adapter
部分生成view,主要功能在AbstractSlideExpandableListAdapter
类中实现。
sample截图:
点击More
按钮的时候,内容部分会进行平移的折叠或者显示。
2. 动画实现部分
动画部分在ExpandCollapseAnimation
中实现
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);
if (interpolatedTime < 1.0f) {
if(mType == EXPAND) {
mLayoutParams.bottomMargin = -mEndHeight + (int) (mEndHeight * interpolatedTime);
} else {
mLayoutParams.bottomMargin = - (int) (mEndHeight * interpolatedTime);
}
Log.d("ExpandCollapseAnimation", "anim height " + mLayoutParams.bottomMargin);
mAnimatedView.requestLayout();
} else {
if(mType == EXPAND) {
mLayoutParams.bottomMargin = 0;
mAnimatedView.requestLayout();
} else {
mLayoutParams.bottomMargin = -mEndHeight;
mAnimatedView.setVisibility(View.GONE);
mAnimatedView.requestLayout();
}
}
}
mEndHeight
在构造时初始化,是滑动动画控件的高度。本质是通过不断变化目标view的bottomMargin
属性来实现动画效果,若是collapse
,动画完成后(interpolatedTime
变为1时)将控件隐藏。
3. 动画的触发
动画通过点击More
按钮触发,按钮的事件绑定在AbstractSlideExpandableListAdapter
文件中,在getView
时进行绑定。
关键代码
target.setAnimation(null);
int type = target.getVisibility() == View.VISIBLE ? ExpandCollapseAnimation.COLLAPSE : ExpandCollapseAnimation.EXPAND;
// remember the state
if (type == ExpandCollapseAnimation.EXPAND) {
openItems.set(position, true);
} else {
openItems.set(position, false);
}
// check if we need to collapse a different view
if (type == ExpandCollapseAnimation.EXPAND) {
if (lastOpenPosition != -1 && lastOpenPosition != position) {
if (lastOpen != null) {
animateView(lastOpen, ExpandCollapseAnimation.COLLAPSE);
notifiyExpandCollapseListener(ExpandCollapseAnimation.COLLAPSE, lastOpen, lastOpenPosition);
}
openItems.set(lastOpenPosition, false);
}
lastOpen = target;
lastOpenPosition = position;
} else if (lastOpenPosition == position) {
lastOpenPosition = -1;
}
animateView(target, type);
notifiyExpandCollapseListener(type, target, position);
-
View lastOpen
用来记录上次打开的view对象。 -
int lastOpenPosition
记录上次打开的view的position
。 -
BitSet openItems
用来记录当前打开的view的position
。 -
animateView(View targt, int type)
在target
上根据type
执行动画,打开或关闭。
打开时首先检查是否有其他的项目已经打开,如果有则先关闭已经打开的。然后在当前view上执行动画。