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

时间:2012-03-05 23:29:21

标签: android layout view height

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

在这种情况下,View是一个LinearLayout。

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

调整展开动画

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

8 个答案:

答案 0 :(得分:121)

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

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

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

});

答案 1 :(得分:21)

我遇到类似情况的类似问题。

我必须创建一个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 );
   }

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

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

答案 2 :(得分:12)

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

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

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

答案 3 :(得分:4)

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

答案 4 :(得分:1)

虽然this answer最初似乎可以正常工作,但最终我注意到它弄乱了正在测量的视图。 我通过传递父视图来修复它。

/**
 * class to map width and height values.
 */
data class Point(val width: Int, val height: Int)

/**
 * Measures the view and returns the width and height.
 */
fun View.getMeasurements(parent: View): Point {
    measure(View.MeasureSpec.makeMeasureSpec(parent.width, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(parent.height, View.MeasureSpec.UNSPECIFIED))

    return Point(measuredWidth, measuredHeight)
}

我还创建了一个数据类,使值所代表的内容更具可读性。 您现在可以像这样访问结果值

child.getMeasurements(parent).width

或这个

child.getMeasurements(parent).height

答案 5 :(得分:0)

好的,关于更新的帖子,这里有什么可以帮到你: Animation#initialize方法。你应该把初始化放在那里而不是构造函数,你将拥有你需要的所有大小。

答案 6 :(得分:0)

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

以下是Kotlin扩展程序,可始终为您完成:

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

答案 7 :(得分:-6)

你可以尝试从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()时,它应该返回你期望的高度。

我不确定这是不是一个好方法,但至少它应该有用。