getWidth()和getHeight()总是返回0。自定义视图

28
在一个Fragment中,我用一个包含多个子View的布局进行填充。我需要获取其中一个自定义View的尺寸(宽度和高度)。
在自定义View类内部很容易做到这一点。但是如果我尝试从Fragment中实现它,我总是得到0作为尺寸。
 public void onViewCreated(View view, Bundle savedInstanceState) {

    super.onViewCreated(view, savedInstanceState);
    View culoide = view.findViewWithTag(DRAW_AREA_TAG);
    Log.d("event", "culoide is: "+culoide.getWidth()); // always 0
}

我认为onViewCreated应该是获取它的正确位置,但是出了点问题。我在super.onViewCreated之前尝试过,在调试中看起来'findViewWithTag'找到了正确的视图,尝试了仅使用api 7 v4支持。

有任何帮助吗?

7个回答

47

为了获得getWidth()getHeight()的非零值,您必须等到第一次测量和布局之后。您可以使用ViewTreeObserver.OnGlobalLayoutListener来实现此目的。

public void onViewCreated(final View view, Bundle saved) {
    super.onViewCreated(view, saved);
    view.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
        public void onGlobalLayout() {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
              view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            } else {
              view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
            }

            // get width and height of the view
        }
    });
}

+1 谢谢 :);removeGlobalOnLayoutListener 今天已经被弃用了;但这已经是另一个问题了。 - quinestor
废弃的方法调用会转到新方法(实际上,我不知道仅因为名称而废弃是否值得),但我已经编辑了我的代码。 - Karakuri
1
或者只需覆盖 onSizeChanged() 方法。 - D-Dᴙum
在我的情况下,我想使用getWidth()来调整一些填充/边距。我无法覆盖onSizeChanged(),因为它在布局期间被调用,对填充/边距的更改不会被保留。OnGlobalLayoutListener在布局完成时触发,没有问题。 - mmvie
请在onDestroyView()中记得将mView=null。 - user2203031
你需要调用 view.getViewTreeObserver() 而不是将 observer 保存为变量。 - sagus_helgy

6
我倾向于为想要追踪自身的视图添加一个OnLayoutChangeListener
CustomView customView = ...

customView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
    @Override
    public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
        // Make changes
    }
});

如果您只想要初始布局,则可以在回调函数中删除侦听器。


3

使用ViewTreeObserver.OnGlobalLayoutListenerView.post(Runnable action)onWindowFocusChanged()并不是最好的解决方案。这篇文章(注:我是这篇文章的作者)解释了为什么,并提供了一个可行的解决方案,即使用基于View.OnLayoutChangeListenerdoOnLayout kotlin扩展函数。如果您想在Java中使用它,在文章中有一个指向doOnLayout源代码的链接,它非常简单,您也可以在Java中做类似的事情。


2

在您能够可靠地确定视图大小之前,必须等待调用onSizeChanged()方法。

当此视图的大小更改时,在布局期间调用此方法。 如果您刚刚添加到视图层次结构中,则会使用旧值调用您。


1

尝试调用

culoide.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);

首先,尝试使用 getWidth()getHeight()


0

尝试检查 onWindowFocusChanged,它应该具有有效的值:

public void onWindowFocusChanged (boolean hasFocus) { }

我曾经遇到过类似的问题,需要获取小部件的宽度和高度,这是我能够保证小部件报告其正确大小的函数。

0

这真的很痛苦,特别是因为你期望在片段生命周期中像 onViewCreated 这样的名称中视图已经准备好了。对我来说,像这样获取片段视图本身:

 override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)   
     getView()?.let{
                  it.doOnLayout{// do your UI work here }
                   }
    }

这可以确保fragments的getView方法已经完成了一次布局。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接