View 的 getWidth() 和 getHeight() 返回 0

新手上路,请多包涵

我正在动态创建我的 android 项目中的所有元素。我正在尝试获取按钮的宽度和高度,以便可以旋转该按钮。我只是想学习如何使用 android 语言。但是,它返回 0。

我做了一些研究,发现它需要在 onCreate() 方法以外的地方完成。如果有人可以给我一个如何做的例子,那就太好了。

这是我当前的代码:

 package com.animation;

import android.app.Activity;
import android.os.Bundle;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.Button;
import android.widget.LinearLayout;

public class AnimateScreen extends Activity {

//Called when the activity is first created.
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    LinearLayout ll = new LinearLayout(this);

    LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
    layoutParams.setMargins(30, 20, 30, 0);

    Button bt = new Button(this);
    bt.setText(String.valueOf(bt.getWidth()));

    RotateAnimation ra = new RotateAnimation(0,360,bt.getWidth() / 2,bt.getHeight() / 2);
    ra.setDuration(3000L);
    ra.setRepeatMode(Animation.RESTART);
    ra.setRepeatCount(Animation.INFINITE);
    ra.setInterpolator(new LinearInterpolator());

    bt.startAnimation(ra);

    ll.addView(bt,layoutParams);

    setContentView(ll);
}

任何帮助表示赞赏。

原文由 ngreenwood6 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.4k
2 个回答

你打电话给 getWidth() 太早了。 UI 尚未在屏幕上调整大小和布局。

无论如何,我怀疑你是否想做你正在做的事情——被动画化的小部件不会改变它们的可点击区域,所以按钮仍然会响应原始方向的点击,不管它是如何旋转的。

话虽如此,您可以使用 维度资源 来定义按钮大小,然后从布局文件和源代码中引用该维度资源,以避免此问题。

原文由 CommonsWare 发布,翻译遵循 CC BY-SA 2.5 许可协议

基本问题是,您必须等待实际测量的绘图阶段(尤其是动态值,如 wrap_contentmatch_parent ),但通常这个阶段还没有完成最多 onResume() 。因此,您需要一种解决方法来等待此阶段。对此有不同的可能解决方案:

1.监听绘制/布局事件:ViewTreeObserver

ViewTreeObserver 会因不同的绘图事件而被触发。通常 OnGlobalLayoutListener 是您想要获得测量值的,因此监听器中的代码将在布局阶段之后调用,因此测量值已准备就绪:

 view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                view.getHeight(); //height is ready
            }
        });

注意:侦听器将立即被删除,否则它将在每个布局事件上触发。如果您必须支持 SDK Lvl < 16 的应用程序,请使用它来注销侦听器:

public void removeGlobalOnLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim)

2.在布局队列中添加一个runnable:View.post()

不是很出名,也是我最喜欢的解决方案。基本上只需将 View 的 post 方法与您自己的可运行对象一起使用。正如 Romain Guy 所述,这基本上是在视图的尺寸、布局等 之后 对您的代码进行排队:

UI 事件队列将按顺序处理事件。调用 setContentView() 后,事件队列将包含一条请求重新布局的消息,因此您发布到队列的任何内容都将在布局通过后发生

例子:

 final View view=//smth;
...
view.post(new Runnable() {
            @Override
            public void run() {
                view.getHeight(); //height is ready
            }
        });

优于 ViewTreeObserver 的优势:

  • 您的代码只执行一次,您不必在执行后禁用观察者,这可能很麻烦
  • 不太冗长的语法

参考:

3. 覆盖Views的onLayout方法

这仅在某些情况下实用,当逻辑可以封装在视图本身中时,否则这是一种非常冗长和繁琐的语法。

 view = new View(this) {
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        view.getHeight(); //height is ready
    }
};

另外请注意,onLayout 将被调用多次,因此请考虑您在该方法中所做的事情,或者在第一次后禁用您的代码

4.检查是否已经通过布局阶段

如果您在创建用户界面时有多次执行的代码,您可以使用以下支持 v4 库方法:

 View viewYouNeedHeightFrom = ...
...
if(ViewCompat.isLaidOut(viewYouNeedHeightFrom)) {
   viewYouNeedHeightFrom.getHeight();
}

如果视图自上次附加到窗口或从窗口分离以来至少经历过一种布局,则返回 true。

附加:获取静态定义的测量

如果只获得静态定义的高度/宽度就足够了,你可以这样做:

但请注意,这可能与绘制后的实际宽度/高度不同。 javadoc 更详细地描述了差异:

视图的大小用宽度和高度表示。一个视图实际上拥有两对宽度和高度值。

第一对称为测量宽度和测量高度。这些尺寸定义了视图在其父视图中的大小(有关更多详细信息,请参阅布局。)可以通过调用 getMeasuredWidth() 和 getMeasuredHeight() 获得测量尺寸。

第二对简称为宽度和高度,有时也称为绘图宽度和绘图高度。这些尺寸定义了屏幕上视图在绘制时和布局后的实际大小。这些值可能但不一定与测量的宽度和高度不同。宽度和高度可以通过调用getWidth() 和getHeight() 获得。

原文由 Patrick 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏