Я использую следующие два метода (вдохновленные/скопированные здесь) в expand
и collapse
некоторые TextViews
в 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
(см. ниже) привели меня к сути, что я вижу, что 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());
}
}
Может ли кто-нибудь указать, что мне не хватает?