używam poniżej dwóch metod (inspired/copied from here) do expand
i collapse
niektóre TextViews
w ScrollView
klikając na „nagłówku” - TextView
.Expand/Collapse Animacja: Małe opóźnienie || MeasureSpec zwraca błędną wartość
Pseudo struktura układ:
<ScrollView>
<LinearLayout>
<LinearLayout>
<!-- some other stuff here -->
</LinearLayout>
<TextView "header1"/>
<View "fancydivider"/>
<TextView "content1">
<TextView "header2"/>
<View "fancydivider"/>
<TextView "content2">
</LinearLayout>
</ScrollView>
Przegroda jest prosty View
, height
zestaw do 1dp
. Na treści TextViews
styl obejmuje:
<item name="android:layout_height">0dp</item>
<item name="android:layout_width">match_parent</item>
i pewien margines & wyściółkę.
Metody tutaj:
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;
}
Problem tutaj: Wszystko działa poprawnie - aż expand animation
osiągnie ostatnią linię tekstu - jeśli istnieje zbyt mało characters
na nim, to pozostaje, skoki, wybucha? - jakkolwiek chcesz to nazwać - aż do pełnego rozwinięcia.
Collapsing
wydaje się działać dobrze.
Próbowałem innych wartości Interpolator
, innego mnożnika w metodzie computeDurationFromHeight
.
Niektóre badania:
4 linie, na czwartej linii wszystkiego więcej niż 17 znaków działa dobrze, mniej niż 18 znaków i to tyle.
3 linie i nieistotna ilość znaków na ostatniej linii działającej poprawnie.
czasami
animation
działa na pierwszymexpand
, ale nie na drugim.- Wygląda na to, że
TextView
zostanie obliczony nieprawidłowo. Z wysokimmultiplier
Widziałem niektóretext
plopping się na < 0,5s ciągu następnego nagłówkaTextView
- usuwając
smoothScrollTo
wexpand
niczego nie zmienia (oprócz przewijania oczywiście ..) - inne interpolatorami również „czkawki” , ale krótszy
- niektóre Logowanie
applyTransformation
(patrz poniżej) mnie do t Wskazuje, że widzę, żefinal height
jest drukowany dwa razy z dokładnością do 50 punktów (piksele? dp?) różnica.//smoothly increasing height and then:
final height = 202 height = 252 final height = 252
Podczas gdy otrzymamtargetHeight = 203
- więcheight
zostanie najpierw błędnie obliczony, ale potem pojawia się jakaś magia?
ważne:
@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());
}
}
Czy ktoś może wskazać, co mi brakuje?
Czy istnieje powód, dla którego sprawdzasz, czy interpolowany czas = 1, a następnie ustawiasz wysokość na WRAP_CONTENT? Czemu to robić? Dlaczego po prostu nie powiedzieć, że wysokość jest zawsze równa interpolatedTime * targetHeight? Kiedy interpolowany czas = 1, wtedy wysokość będzie celować w miarę pożądanego poziomu. Myślę, że ustawienie wysokości WRAP_CONTENT na końcu jest przyczyną jąkania. –
Wziąłem tę linię z powyższej odpowiedzi - jeśli używam tylko "interpolatedTime * celHeight", ostatnia linia nie jest drukowana w ogóle. Już odkryłem, że problem jest spowodowany błędnym obliczeniem 'height' ..:/ – yennsarah
' v.requestLayout(); 'sprawia, że widok rodzica wywołania metody() i wszystkie dzieci są ponownie układ. Kolejne połączenia mogą prowadzić do opóźnień. Próba animowania wartości Rect zamiast parametrów układu. –