布局-Android:在绘制视图之前获取视图的高度

对于动画,我需要从View知道高度。 问题是,除非绘制了View,否则getHeight()方法始终返回0。那么有什么方法可以在不绘制高度的情况下获得高度吗?

在这种情况下,View是LinearLayout。

编辑:我尝试从[https://github.com/Udinic/SmallExamples/blob/master/ExpandAnimationExample/src/com/udinic/expand_animation_example/ExpandAnimation.java]改编扩展动画。

我想用它来扩展列表项的更多信息。我无法通过xml达到相同的效果。目前,只有在绘制前知道布局大小时,动画才起作用。

anonymous asked 2020-02-13T20:50:03Z
7个解决方案
124 votes

听起来好像您想获取高度,但在视图可见之前将其隐藏。

首先将视图中的可见性设置为可见或不可见(只是为了创建高度)。 不用担心,我们将在代码中将其更改为不可见/消失,如下所示:

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 );
        }

});
Jim Baca answered 2020-02-13T20:50:17Z
22 votes

我在类似情况下也遇到类似问题。

我必须创建一个动画,为此我需要LinearLayout的高度,该高度取决于动画。 在merge(即merge)中,可能是android:orientation类型的子视图。vertical是多行,实际需要的行数有所不同。

无论我做什么,我都只得到了视图的测量高度,好像LinearLayout仅有一行要填充。 难怪每次当文本恰好短于一行时,它都能很好地工作,但是当文本长于在线时,它就失败了。

我考虑了以下答案:[https://stackoverflow.com/a/6157820/854396]但这对我来说效果不佳,因为我无法直接从此处访问嵌入式LinearLayout。 (虽然我可以遍历子视图树)。

看一下我目前的代码:

LinearLayout是要动画的视图。 它是merge(最终的解决方案是在此处保存更多的类型)merge是一个自定义视图,其中包含android:orientation,并且也继承自vertical

   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,因此我在屏幕上实际看不到错误的方向。 但是在那里,有点打乱了这种布局测量逻辑。

除了上述内容之外,可能还需要摆脱与视图层次结构内的LinearLayouts和子类关联的所有填充。 即使必须环绕其他布局以使其看起来相同,也请以边距替换它们。

Hermann Klecker answered 2020-02-13T20:51:11Z
13 votes

从技术上讲,您可以在视图上调用RELATIVE_TO_SELF方法,然后通过getMeasureHeight获取其高度。有关更多信息,请参见此方法:[https://developer.android.com/guide/topics/ui/how-android-draws.html。 您将需要给它MeasureSpec

但实际上,视图的大小受其父级布局的影响,因此您可能会获得与实际绘制时不同的大小。

另外,您可以尝试在动画中使用RELATIVE_TO_SELF值。

Fixpoint answered 2020-02-13T20:51:41Z
4 votes
static void getMeasurments(View v) {

    v.measure(View.MeasureSpec.makeMeasureSpec(PARENT_VIEW.getWidth(), 
      View.MeasureSpec.EXACTLY),
         View.MeasureSpec.makeMeasureSpec(0, 
      View.MeasureSpec.UNSPECIFIED));

    final int targetHeight = v.getMeasuredHeight();
    final int targetWidth = v.getMesauredWidth();
}
Anubhav answered 2020-02-13T20:51:56Z
0 votes

好的,关于更新后的帖子,这将为您提供帮助:Animation#initialize方法。 您应该只在其中放置初始化而不是构造函数,然后在其中拥有所需的所有大小。

Fixpoint answered 2020-02-13T20:52:17Z
0 votes

如果父母没有确定尺寸,请自己测量:

这是kotlin扩展程序,可随时为您执行此操作:

fun View.getMeasurments(): Pair<Int, Int> {
    measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
    val width = measuredWidth
    val height = measuredHeight
    return width to height
}
j2emanue answered 2020-02-13T20:52:41Z
-6 votes

您可以尝试从可见的View开始,然后添加如下内容:

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()时,它应该返回您期望的高度。

我不确定这是否真的是一个好方法,但至少应该可以。

YuviDroid answered 2020-02-13T20:53:10Z
translate from https://stackoverflow.com:/questions/9575706/android-get-height-of-a-view-before-it%c2%b4s-drawn