【问题标题】:getmeasuredheight() and getmeasuredwidth() returns 0 after View.measure()getmeasuredheight() 和 getmeasuredwidth() 在 View.measure() 之后返回 0
【发布时间】:2014-08-17 07:13:16
【问题描述】:

在用view.measure() 测量具有恒定尺寸View 后,getMeasuredHeight()getMeasureWidth() 返回 0。

layout_view.xml,为创建视图而膨胀的布局

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="100dp"
    android:layout_height="100dp">
</FrameLayout>

测量尺寸的函数

public void measureView(Context context){
    LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View view = inflater.inflate(R.layout.layout_view,null,false);

    view.measure( View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);

    Log.d(TAG,"Error width : " + view.getMeasuredWidth());
    Log.d(TAG,"Error height : " + view.getMeasuredHeight());

}

【问题讨论】:

标签: android layout view


【解决方案1】:

当您在onCreate()onCreateView() 中调用view.getMeasuredWidth() 时,view 尚未绘制。所以你需要添加一个监听器,当view被绘制时会得到一个回调。就像我的代码中这样:

final ViewTreeObserver vto = view.getViewTreeObserver();
if (vto.isAlive()) {
    vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            int viewWidth = view.getMeasuredWidth();
            // handle viewWidth here...

            if (Build.VERSION.SDK_INT < 16) {
                vto.removeGlobalOnLayoutListener(this);
            } else {
                vto.removeOnGlobalLayoutListener(this);
            }
        }
    });
}

注意:移除监听器以获得更好的性能!

不要调用vto.removeOnGlobalLayoutListener(this) 来移除监听器。像这样称呼它:

vto.getViewTreeObserver()

【讨论】:

  • 我试过了,它似乎适用于所有测试用例,但现在我看到 getMeasuredWidth() 在生产中为某些用户返回 0 :(
  • 谢谢!我之前使用过OnPreDrawListener(但它似乎与某些设备 4.4.4 和 6.0.1 不兼容)。使用onGlobalLayout 并在height &gt; 0 正常工作时删除监听器。
  • 什么是v?它不知从何而来。
  • 出于某种原因,getMeasuredWidth仅在滚动发生后返回“正确”值。还有其他方法可以触发正确的测量吗?
【解决方案2】:

您是否正在测量onCreate() 中的视图。视图尚未绘制。您必须等到视图绘制后的一段时间才能对其进行测量。

对此的简单解决方案是将可运行文件发布到布局中。 runnable 将在布局发生后执行。

欲了解更多信息See this post

编辑 尝试改变

view.measure( View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);

view.measure( View.MeasureSpec.EXACTLY, View.MeasureSpec.EXACTLY);

【讨论】:

  • 我正在使用 onclick 方法测量视图。为避免您指出的问题,我使用view.measure() 明确测量视图
  • 我也试过了,但结果仍然为零
【解决方案3】:

试试这个方法,希望能帮助你解决问题。

view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
   @Override
   public void onGlobalLayout() {
     int width = view.getMeasuredWidth();
     int height = view.getMeasuredHeight();

   }
});

【讨论】:

    【解决方案4】:

    如果您的测量视图的可见性设置为消失,测量将返回 0。您可以将其设置为可见、测量,然后设置回消失,所有这些都来自代码。

    【讨论】:

    • 默认设置为可见
    【解决方案5】:

    您不能在measure 通话中直接使用View.MeasureSpec.*。而是先makeMeasureSpec(),然后用它来调用measure()

    final int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(ViewGroup.LayoutParams.WRAP_CONTENT/*can be match_parent or some exact value*/, View.MeasureSpec.UNSPECIFIED);
    final int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(ViewGroup.LayoutParams.WRAP_CONTENT/*can be match_parent or some exact value*/, View.MeasureSpec.UNSPECIFIED);
    view.measure(widthMeasureSpec, heightMeasureSpec);
    

    【讨论】:

    • 谢谢,但目前 Kotling 限制传递此值 (WRAP_CONTENT = -2 stackoverflow.com/a/53739033/2914140 帮助了onCreateView(),简称为 view.measure(0, 0)。在其他事件中,您应该使用getViewTreeObserver(),请参阅stackoverflow.com/questions/14592930/…
    • View.MeasureSpec.makeMeasureSpec(ViewGroup.LayoutParams.WRAP_CONTENT, View.MeasureSpec.UNSPECIFIED);不工作,它说Value must be ≥ 0 (was -2)
    【解决方案6】:

    以防万一有人在使用 ImageView 时遇到此问题:

    我注意到,如果您的 ImageView 没有设置“android:src”(即您动态更改它),它将始终从 getMeasuredWidth/Height 返回零。

    一个简单的解决方法是为视图设置一个占位符。

    【讨论】:

    • getHeight/getMeasuredHeight 在设置占位符后仍然给出 0
    【解决方案7】:

    您可以在onCreate/onCreateView 和其他事件中使用getViewTreeObserver

    fun setGlobalLayoutListener(view: View, method: () -> Unit) {
        val vto1 = view.viewTreeObserver
        if (vto1.isAlive) {
            vto1.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
                override fun onGlobalLayout() {
                    val vto2 = view.viewTreeObserver
                    if (vto2.isAlive) {
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                            vto2.removeOnGlobalLayoutListener(this)
                        } else {
                            @Suppress("DEPRECATION")
                            vto2.removeGlobalOnLayoutListener(this)
                        }
                        // Your actions are here:
                        method()
                    }
                }
            })
        }
    }
    

    并称它为:setGlobalLayoutListener(view) {updateUI(view)}

    我也试过

    view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
    

    然后在onCreateView()/onViewCreated() 中调用view.control.measuredWidth。但在某些模拟器(API 19)中,它返回了错误的结果。

    【讨论】:

      猜你喜欢
      • 2017-06-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-03
      • 1970-01-01
      • 1970-01-01
      • 2014-01-02
      相关资源
      最近更新 更多