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

2022-08-31 04:14:16

我正在动态地创建我的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);
}

任何帮助是值得赞赏的。


答案 1

基本问题是,您必须等待实际测量的绘制阶段(特别是对于像 或 这样的动态值),但通常此阶段尚未完成。因此,您需要一个解决方法来等待此阶段。对此有不同的可能的解决方案:wrap_contentmatch_parentonResume()

1. 侦听绘制/布局事件:视图树观察器

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()

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

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

例:

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

优势:ViewTreeObserver

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

引用:


3. 覆盖视图的布局方法

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

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. 检查是否已经通过布局阶段

如果在创建 ui 时多次执行代码,则可以使用以下支持 v4 lib 方法:

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

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

其他:获取静态定义的测量值

如果只需获取静态定义的高度/宽度就足够了,则可以使用以下命令执行此操作:

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

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

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

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


答案 2

我们可以使用

@Override
 public void onWindowFocusChanged(boolean hasFocus) {
  super.onWindowFocusChanged(hasFocus);
  //Here you can get the size!
 }

推荐