android动态测量控件

在Android开发中,为了适配,通常不使用具体数值设置View的宽高。本文探讨了如何动态获取View的实际宽度和高度,区分了`view.getMeasuredHeight()`和`view.getHeight()`的区别,并详细介绍了四种测量方法:主动请求测量、使用OnPreDrawListener、OnGlobalLayoutListener以及OnLayoutChangeListener。这些方法在不同阶段执行,适用于不同场景,需要注意它们的执行时机和可能存在的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

android动态测量控件

  • 通常在实际开发中,为了适配,我们会把View设置为match_parent或者wrap_content、又或者是设置weight权重来分配宽高,而不是使用具体值。那么就出现一个问题了,如果动态测量View的实际宽高。
  • 测量宽高的API:android提供了两个API来动态获取View的高:

    view.getMeasuredHeight()
    view.getHeight()
    

    那么这两个API的区别是什么呢?

    • 简单来说就是:
      view.getMeasuredHeight() 是由view中的测量方法赋值的,这个值包含了隐藏的高度(比如一个view部分超出屏幕,他也会计算出来)。
      view.getHeight() 由view的底部位置减去顶部位置,即实际显示的View的高度,不包含隐藏了的高度。
      如果是在View的onMeasure方法后执行上面两个方法,会发现可以得到正确的高度,但是如果是在onCreate等方法中执行就会发现返回的值不正确或者为0,这是为什么呢?
      • 这是因为View的onMeasure()方法在Activity的onCreate();onResume()方法之后执行,此时还没有测量出实际的宽高,还没有进行绘制,所以调用上述的两个API会出现值为0或者数值错误的情况。
  • 测量方法:

    • 1 : 主动请求测量:

      view.measure(0, 0);  
      view.getMeasuredWidth();
      view.getMeasuredHeight();
      
      • 说明:
        onMeasure传入的两个参数是由父控件的大小,
        也可以使用 View.MeasureSpec.makeMeasureSpec(0,mode);设置值
        其中mode可以选择

        MeasureSpec.UNSPECIFIED 未指定尺寸,比如listview中尺寸由父控件决定
        MeasureSpec.EXACTLY 适合match_parent或者具体值
        MeasureSpec.AT_MOST 适合wrap_content不确定值
        
      • 注意:
        这种方法不一定能测出正确的值,因为onMesure会多次调用(由于onMesure自上而下,父控件如果对于子控件的宽高不满意,即如子控件没有限制宽高,父控件会重新调用onMesure重新测量),所以测量结果不一定正确。
    • 2 :使用OnPreDrawListener

      ViewTreeObserver observer = view.getViewTreeObserver();  
           observer.addOnPreDrawListener(new OnPreDrawListener() {  
               @Override  
               public boolean onPreDraw() {  
                      view.getViewTreeObserver().removeOnPreDrawListener(this);
                      int height = view.getMeasuredHeight();  
                      int width = view.getMeasuredWidth();  
                      return true;  
              }  
          });
      
      • 说明:
        这个是异步解决方法,在onDraw之前执行,onDraw方法执行在onMeasure之后,所以这个监听器可以解决动态获取的问题。
      • 注意:
        onPreDraw方法只有return true才会生效,由于onDraw会在view绘制时调用,所以可能会调用多次,务必调用removeOnPreDrawListener方法,防止执行效率问题。onDraw会多次执行,每次view出现都会调用,但onLayout不会,测量后会被记录下来。
    • 3.使用OnGlobalLayoutListener

      ViewTreeObserver observer = view.getViewTreeObserver();  
              observer.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {  
                  @Override  
                  public void onGlobalLayout() {  
                      view.getViewTreeObserver().removeGlobalOnLayoutListener(this);  
                      int height = img.getWidth();  
                      int width = img.getHeight();
              }  
      });  
      
    • 说明:
      这个也是异步解决方法,在全局onLayout触发时执行。

    • 注意:
      这个方法有一定不确定性,而且onLayout执行第一次的数值不一定正确。

    • 4.使用OnLayoutChangeListener

      view.addOnLayoutChangeListener(new OnLayoutChangeListener() {
          @Override
          public void onLayoutChange(View v, int left, int top, int right,
              int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
      
          }
      
      });
      
      • 说明:这个方法OnLayout时调用,而且只有改变时才会触发。
      • 注意:这个方法要求API level 11
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值