在activity中获取view及view隐藏打开时正确的高度

在activity中获取view的高度这个问题网上有很多答案,常见的有如下4种:

第一种:

  int w = View.MeasureSpec.makeMeasureSpec(0,
                    View.MeasureSpec.UNSPECIFIED);
            int h = View.MeasureSpec.makeMeasureSpec(0,
                    View.MeasureSpec.UNSPECIFIED);
            llYjsmView.measure(w, h);
            int height = llYjsmView.getMeasuredHeight();
            int width = llYjsmView.getMeasuredWidth();
            LogUtils.e("height==" + height);
            LogUtils.e("width==" + width);

这种方法就是直接测量,得到view的高度或者宽度,这里makeMeasureSpec的第二个参数只能用View.MeasureSpec.UNSPECIFIED(未指定尺寸),如果用另外两种EXACTLY(精确尺寸)、AT_MOST(最大尺寸)则获取到的高度和宽度就都是0。

注意:这种测量方法在测量textview的时候只会测量出一行的高度,就算你view上显示的是两行,但是他测出来的高度永远只是一行,但是宽度却很长,比如这样:

    tvHeight==53
    tvWidth==7650

所以在使用此方法测量的textview的时候需要注意一下

第二种:


    ViewTreeObserver vto = tvTest.getViewTreeObserver();
   vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
      @Override
      public boolean onPreDraw() {
        int height = tvTest.getMeasuredHeight();
        int width = tvTest.getMeasuredWidth();
        System.out.println("height" + height);
        System.out.println("width" + width);
        return true;
      }
 
    });

这种方法听说会执行多次,但我没有测试。

第三种:

    ViewTreeObserver observer1 = llYjsmView.getViewTreeObserver();
        observer1.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                llYjsmView.getViewTreeObserver().removeGlobalOnLayoutListener(this);//移除监听,避免重复监听
                llYjsmHeight = llYjsmView.getMeasuredHeight();//获文本高度
                //获取高度后要进行的操作就在这里执行,在外面可能onGlobalLayout还没有执行而获取不到height
                LogUtils.e("onGlobalLayout:llYjsmView===》height====" + llYjsmHeight); 
            }
        });
        

这种方法和第二种差不多,但他是全局监听的,不过要注意的是这个方法的触发条件是在view的layout发生变化的时候才会触发,比如gone、visible。

第四种:

  tvTest.post(new Runnable() {
 
      @Override
      public void run() {
             width=tvTest.getWidth();
             height=tvTest.getHeight();
      }
    });
    

这种方法比较简单,也比较好记。

第五种:

  viewTest=  new View(this){
            @Override
            public void layout(int l, int t, int r, int b) {
                super.layout(l, t, r, b);
                int height = viewTest.getHeight();
            }
        };

这种方法不常用,一般在特殊位置下使用。

好了,介绍了以上五种获取view高度的办法,接下来就说说我遇到的问题吧。

业务逻辑是这样的,布局开始是隐藏的,在获取数据后设置在textview上,点击按钮展开(需要动画),由于这个动画需要一个高度,所以我开始就直接使用方法一测量出高度后放上去,结果就发现他测量的结果永远是固定的,即在xml布局中给的初始值。于是我换第二种、第三种、第四种方法测量,结果发现测量出来的值都只是初始值。

解决办法

我的xml布局是这样的:

   <LinearLayout
                android:id="@+id/ll_yjsm_view"
                android:visibility="gone"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical">
              <TextView
                    android:id="@+id/tv_yjsm"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginBottom="@dimen/dp_10"
                    android:layout_marginLeft="@dimen/dp_10"
                    android:lineSpacingExtra="@dimen/dp_5"
                    android:textColor="@color/c_66"
                    android:textSize="@dimen/sp_13" />
 
   </LinearLayout>
   

可以看到我的布局默认是隐藏的,在点击事件触发的时候动画展开此布局,而textview是自适应的。所以需要测量整个linearLayou的高度。我在获取数据成功后设置在页面上是这样做的:

 tvYjsm.setText(policyDesc);
 ViewTreeObserver observer1 = llYjsmView.getViewTreeObserver();
        observer1.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                llYjsmView.getViewTreeObserver().removeGlobalOnLayoutListener(this);//避免重复监听
                llYjsmHeight = llYjsmView.getMeasuredHeight();//获文本高度
                //获取高度后要进行的操作就在这里执行,在外面可能onGlobalLayout还没有执行而获取不到height
                LogUtils.e("onGlobalLayout:llYjsmView===》height====" + llYjsmHeight);
          //测量成果后回归原始状态,
                llYjsmView.setVisibility(View.GONE);

            }
        });
        //此处布局需要打开触发布局变化监听,用于测量
        llYjsmView.setVisibility(View.VISIBLE);

可以看到在吧内容设置上去后我是手动visible打开了这个布局,这样就能触发布局的变化监听,然后去测量实际的高度,由于设计要求是默认关闭的,所以在测量完成后再关闭布局,把获取到的高度全局保存,这样就得到了view的实际高度。

一开始我是用第一种方式获取的,然而每次都是一行的固定的高度,用其他几种也都是固定值,因为我的布局默认是关闭的。

总结:

使用以上方式测量高度的时候,需要注意布局的初始状态,如果初始状态是gone的时候,在动态设置内容成功后需要先打开布局,然后再去测量,测量完成后再关闭,这样测量出来的高度就是真实的高度。另外需要注意的一点是在测量textview的高度的时候,尽量不要用第一种方式,因为此方法只能测量出一行的高度。

    原文作者:至死仍是少年心
    原文地址: https://www.jianshu.com/p/91af78bfae10
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞