美文网首页Android自定义ViewAndroid开发经验谈Android开发
在activity中获取view及view隐藏打开时正确的高度

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

作者: 锄禾少年不太帅 | 来源:发表于2017-12-06 15:24 被阅读24次

    在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的高度的时候,尽量不要用第一种方式,因为此方法只能测量出一行的高度。

    相关文章

      网友评论

        本文标题:在activity中获取view及view隐藏打开时正确的高度

        本文链接:https://www.haomeiwen.com/subject/juljvxtx.html