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

ano*_*ous 48 height layout android view

对于动画,我需要知道视图的高度.问题是,除非绘制View,否则getHeight()方法总是返回0.那么有没有办法获得高度而不绘制它?

在这种情况下,View是LinearLayout.

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

有了它,我想为列表项扩展一些更多的信息.我无法通过xml实现相同的效果.目前,当您在绘制之前知道布局大小时,动画才会起作用.

Jim*_*aca 124

听起来你想要获得高度,但在视图可见之前隐藏视图.

将视图中的可见性设置为可见或不可见(仅为创建高度).不要担心我们会将其更改为不可见/在代码中消失,如下所示:

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

});
Run Code Online (Sandbox Code Playgroud)

  • 谢谢,它的确有效!只需添加一点:removeGlobalOnLayoutListener()自API级别16以来已被弃用,它被removeOnGlobalLayoutListener()取代 (12认同)
  • 感谢这个提示,它运作良好.注意,removeOnGlobalLayoutListener的参数名称是"受害者"这一事实非常棒. (2认同)
  • 这并不总是有效 - 首先,视图会在消失前闪烁,这对UI不利.其次,如果您启动应用程序并立即切换到另一个应用程序,则无论出于何种原因,高度似乎都无法正确计算. (2认同)

Her*_*ker 24

我遇到了类似情况的类似问题.

我必须创建一个anmiation,我要求它的高度view受动画影响.在其中view,这LinearLayout可能是类型的子视图TextView.这TextView是多行,实际需要的行数不同.

无论我做了什么,我只是得到了视图的测量高度,好像TextView只有一条线要填充.难怪每次文本发生的时间足够短,只有一行,但是当文本在线上时,它就失败了.

我考虑过这个答案:https://stackoverflow.com/a/6157820/854396 但是那个对我来说效果不好,因为我无法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 );
   }
Run Code Online (Sandbox Code Playgroud)

这几乎是它,但我犯了另一个错误.在视图层次结构中,涉及两个自定义视图,它们是子类,LinearLayout并且它们的xml与merge标记合并为xml根标记.在其中一个merge标签中,我忽略了将android:orientation属性设置为vertical.这对于布局本身并没有太多麻烦,因为在这个合并ViewGroup中只有一个孩子ViewGroup,因此我实际上无法在屏幕上看到错误的方向.但它就在那里,有点破坏了这种布局测量逻辑.

除了上述内容之外,可能还需要删除与LinearLayout视图层次结构中的s和子类关联的所有填充.用边距替换它们,即使你必须在它周围包裹另一个布局以使它看起来一样.


Fix*_*int 14

从技术上讲,您可以measure在视图上调用方法,然后通过它获取高度getMeasureHeight.有关详细信息,请参阅此处:https://developer.android.com/guide/topics/ui/how-android-draws.html.你需要给它一个MeasureSpec.

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

此外,您可以尝试RELATIVE_TO_SELF在动画中使用值.

  • 这个答案是正确的答案,但缺乏代码是减少赞成票的简单原因。 (2认同)

Anu*_*hav 8

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();
}
Run Code Online (Sandbox Code Playgroud)

  • 虽然此解决方案有效(至少对我而言),请解释代码的作用以及下次为什么。 (3认同)
  • PARENT_VIEW 是什么? (2认同)

j2e*_*nue 7

如果父级无法确定其大小,请自行测量:

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

fun View.getMeasurments(): Pair<Int, Int> {
    measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
    val width = measuredWidth
    val height = measuredHeight
    return width to height
}
Run Code Online (Sandbox Code Playgroud)