Android: получить высоту представления, прежде чем он будет нарисован
Для анимации мне нужно знать высоту из представления. Проблема заключается в том, что метод getHeight() всегда возвращает 0, если не отображен вид.
Так есть ли способ получить высоту, не рисуя ее?
В этом случае представление представляет собой LinearLayout.
EDIT:
Я пытаюсь адаптировать расширение Animation из https://github.com/Udinic/SmallExamples/blob/master/ExpandAnimationExample/src/com/udinic/expand_animation_example/ExpandAnimation.java
С его помощью я хочу расширить дополнительную информацию для элемента списка.
Я не смог добиться такого же эффекта через xml.
В настоящий момент анимация работает только тогда, когда вы знаете размер макета перед его рисованием.
Ответы
Ответ 1
Похоже, вы хотите получить высоту, но скрыть представление до того, как оно будет видимым.
Увидеть видимость в представлении, видимом или невидимом, для начала (только для создания высоты). Не беспокойтесь, мы изменим его на невидимый/ушли в код, как показано ниже:
private int mHeight = 0;
private View mView;
class...
// onCreate or onResume or onStart ...
mView = findViewByID(R.id.someID);
mView.getViewTreeObserver().addOnGlobalLayoutListener(
new OnGlobalLayoutListener(){
@Override
public void onGlobalLayout() {
// gets called after layout has been done but before display
// so we can get the height then hide the view
mHeight = mView.getHeight(); // Ahaha! Gotcha
mView.getViewTreeObserver().removeGlobalOnLayoutListener( this );
mView.setVisibility( View.GONE );
}
});
Ответ 2
У меня была аналогичная проблема с аналогичной ситуацией.
Мне пришлось создать аномалию, для которой мне нужна высота view
, которая зависит от анимации. Внутри этого view
, который является LinearLayout
, может быть дочерним видом типа TextView
. Это TextView
- это многострочная строка, и количество требуемых строк меняется.
Что бы я ни делал, я просто получил измеренную высоту для представления, как будто TextView
имеет только одну строку для заполнения. Неудивительно, что это отлично срабатывало каждый раз, когда текст был достаточно коротким для одной строки, но он не удался, когда текст был длиннее han on line.
Я рассмотрел этот ответ: fooobar.com/questions/18402/...
Но для меня это не сработало, потому что я не могу получить доступ к встроенному TextView
прямо отсюда. (Я мог бы повторить, хотя дерево дочерних представлений, хотя.)
Посмотрите на мой код, пока он работает:
view
- это представление, которое должно быть анимировано. Это LinearLayout
(Окончательное решение будет немного больше, чем сохранить здесь)
this
- это пользовательское представление, которое содержит view
и наследует от LinearLayout
тоже.
private void expandView( final View view ) {
view.setVisibility(View.VISIBLE);
LayoutParams parms = (LayoutParams) view.getLayoutParams();
final int width = this.getWidth() - parms.leftMargin - parms.rightMargin;
view.measure( MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
final int targetHeight = view.getMeasuredHeight();
view.getLayoutParams().height = 0;
Animation anim = new Animation() {
@Override
protected void applyTransformation( float interpolatedTime, Transformation trans ) {
view.getLayoutParams().height = (int) (targetHeight * interpolatedTime);
view.requestLayout();
}
@Override
public boolean willChangeBounds() {
return true;
}
};
anim.setDuration( ANIMATION_DURATION );
view.startAnimation( anim );
}
Это было почти так, но я сделал еще одну ошибку. Внутри иерархии представления есть два пользовательских представления, которые являются подклассами LinearLayout
, и их xml объединяется с тегом merge
в качестве корневого тега xml. В одном из этих тегов merge
я забыл установить атрибут android:orientation
в vertical
.
Это не слишком беспокоило самого макета, потому что в этом объединенном ViewGroup
был только один дочерний ViewGroup
, и поэтому я не мог на самом деле видеть неправильную ориентацию на экране. Но он был там и вроде бы немного сломал эту логику измерения компоновки.
В дополнение к вышесказанному может потребоваться избавиться от всех прокладок, связанных с LinearLayout
и подклассами в иерархии представлений. Заменяйте их по полям, даже если вам нужно обернуть еще один макет, чтобы он выглядел одинаково.
Ответ 3
Технически вы можете вызвать метод measure
на представлении, а затем получить его высоту через getMeasureHeight
. См. Это для получения дополнительной информации: https://developer.android.com/guide/topics/ui/how-android-draws.html. Вам нужно будет дать ему MeasureSpec
.
Но на самом деле размер представления зависит от его родительского макета, поэтому вы можете получить другой размер, чем когда он действительно нарисован.
Кроме того, вы можете попробовать использовать значения RELATIVE_TO_SELF
в ваших анимациях.
Ответ 4
Хорошо, что касается обновленного сообщения, вот что вам поможет:
Анимация # initialize. Вы должны просто добавить туда инициализацию вместо конструктора, и у вас будут все размеры, которые вам там нужны.
Ответ 5
Вы можете попробовать начать с видимого вида, а затем добавить что-то вроде этого:
view.post(new Runnable() {
@Override
public void run() {
// hide view here so that its height has been already computed
view.setVisibility(View.GONE);
}
});
Теперь, когда вы вызовеете view.getHeight(), он должен вернуть ожидаемую высоту.
Я не уверен, что это действительно хороший способ сделать это, но по крайней мере он должен работать.