我使用以下两种方法(
inspired/copied from here)通过点击“标题”-TextView来展开和折叠ScrollView中的一些TextView.
伪布局结构:
<ScrollView> <LinearLayout> <LinearLayout> <!-- some other stuff here --> </LinearLayout> <TextView "header1"/> <View "fancydivider"/> <TextView "content1"> <TextView "header2"/> <View "fancydivider"/> <TextView "content2"> </LinearLayout> </ScrollView>
Divider是一个简单的View,heightset为1dp. content-TextViews的内容包括:
<item name="android:layout_height">0dp</item> <item name="android:layout_width">match_parent</item>
和一些保证金填充.
方法:
public static void expand(final View v) { //v.measure(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT); int matchParentMeasureSpec = View.MeasureSpec.makeMeasureSpec(((View) v.getParent()).getWidth(),View.MeasureSpec.EXACTLY); int wrapContentMeasureSpec = View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED); v.measure(matchParentMeasureSpec,wrapContentMeasureSpec); final int targetHeight = v.getMeasuredHeight(); // Older versions of android (pre API 21) cancel animations for views with a height of 0. v.getLayoutParams().height = 1; v.setVisibility(View.VISIBLE); Animation a = new Animation() { @Override protected void applyTransformation(float interpolatedTime,Transformation t) { v.getLayoutParams().height = interpolatedTime == 1 ? ViewGroup.LayoutParams.WRAP_CONTENT : (int) (targetHeight * interpolatedTime); scrollView.smoothScrollTo(0,(int) (targetHeight * interpolatedTime)); v.requestLayout(); } @Override public boolean willChangeBounds() { return true; } }; a.setInterpolator(easeInOutQuart); a.setDuration(computeDurationFromHeight(v)); v.startAnimation(a); } public static void collapse(final View v) { final int initialHeight = v.getMeasuredHeight(); Animation a = new Animation() { @Override protected void applyTransformation(float interpolatedTime,Transformation t) { if (interpolatedTime == 1) { v.setVisibility(View.GONE); } else { v.getLayoutParams().height = initialHeight - (int) (initialHeight * interpolatedTime); v.requestLayout(); } } @Override public boolean willChangeBounds() { return true; } }; a.setInterpolator(easeInOutQuart); a.setDuration(computeDurationFromHeight(v)); v.startAnimation(a); } private static int computeDurationFromHeight(View view) { // 1dp/ms * multiplier return (int) (view.getMeasuredHeight() / view.getContext().getResources().getDisplayMetrics().density) * 4; }
问题在这里:一切正常 – 直到展开动画到达文本的最后一行 – 如果它的字符太少,那么它滞后,跳跃,爆炸? – 但是您要调用它 – 直到完全展开.
崩溃似乎工作正常.
我尝试过其他Interpolator值,方法computeDurationFromHeight中的另一个乘数.
一些测试:
> 4行,第四行全部17个以上的字符工作正常,少于18个字符,并且滞后.
> 3行和不相关的字数在最后一行工作正常.
>有时动画首先展开,但不是第二次.
>看来,TextView的计算错误.有一个高乘数,我看到一些文本翻转起来,在下一个标题TextView中0.5s
>在expand中删除smoothScrollTo不会改变任何东西(除了滚动当然..)
>其他内插器也有“打嗝”,但更短
重要:
>一些登录applyTransformation(见下文)让我指出,我看到最后的高度打印了两次 – 只有50点(像素?dp?)的差异. //顺利增加高度然后:
最终高度= 202高度= 252最终高度= 252当我得到targetHeight = 203 – 所以高度先计算错误,但是然后一些魔法发生?
@Override protected void applyTransformation(float interpolatedTime,Transformation t) { v.getLayoutParams().height = interpolatedTime == 1 ? ViewGroup.LayoutParams.WRAP_CONTENT : (int) (targetHeight * interpolatedTime); v.requestLayout(); scrollView.smoothScrollTo(0,interpolatedTime == 1 ? v.getHeight() : (int) (targetHeight * interpolatedTime)); Log.d("Anim","height = " + v.getHeight()); if (interpolatedTime == 1){ Log.d("Anim","final height = " + v.getHeight()); } }
有人可以指出我失踪了吗?