Развернуть / свернуть Анимация: малая лага || MeasureSpec возвращает неверное значение

Я использую следующие два метода ( вдохновленные / скопированные здесь ), чтобы expand и collapse некоторые ScrollView в ScrollView , щелкнув «header» – 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 , height установлена ​​в 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; } 

Проблема здесь: все работает нормально – пока expand animation дойдет до последней строки текста – если на ней слишком мало characters , тогда она лагает , прыгает, взрывается? – однако вы хотите назвать его – до полного расширения.

Кажется, что Collapsing выглядит нормально.

Я попробовал другие значения Interpolator , другой множитель в методе computeDurationFromHeight .

Некоторые тесты:

    • 4 линии, на четвертой строчке все более 17 символов хорошо работает, меньше 18 символов, и он отстает.

    • 3 строки и неуместное количество символов на последней линии, работающей нормально.

    • Иногда animation работает при первом expand , но не на втором.

    • Кажется, что TextView вычисляется неправильно. С большим multiplier я видел, как какой-то text всплывал для <0.5s над следующим заголовком TextView
    • Удаление smoothScrollTo в expand ничего не меняет (кроме прокрутки, конечно ..)
    • Другие интерполяторы также имеют «икоту», но короче

    важный:

  • Некоторые записи в applyTransformation (см. Ниже) applyTransformation меня к сути, что я вижу, что final height печатается дважды – с разницей в 50 точек (пикселей? Dp?). //smoothly increasing height and then: final height = 202 height = 252 final height = 252 Пока я получаю targetHeight = 203 – поэтому height сначала вычисляется неправильно, но потом происходит какая-то магия?

  •  @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()); } } 

    Может ли кто-нибудь указать, что мне не хватает?

    Это может быть вызвано тем, что использование последнего элемента может вызвать прокрутку, поскольку высота макета увеличивается, поэтому «нажмите» дисплей вниз

    Попробуйте добавить FrameLayout внизу с высотой 20dp и попытайтесь наблюдать, если это имеет какое-либо значение

    Я на 99% уверен, что вам нужно изменить <item name="android:layout_height">0dp</item> (из анимированного TextView ) на wrap_content и установить его начальное состояние в GONE (так как это окончательное состояние После анимации коллапса).