一尘不染

Java-视图的getWidth()和getHeight()返回0

java

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

任何帮助表示赞赏。


阅读 849

收藏
2020-02-25

共2个答案

一尘不染

你打得getWidth()太早了。UI尚未调整大小并在屏幕上布置。

无论如何,我怀疑你是否想做自己正在做的事情—动画化的小部件不会更改其可点击区域,因此无论按钮如何旋转,按钮仍将响应原始方向的单击。

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

2020-02-25
一尘不染

基本问题是,你必须等待绘图阶段进行实际测量(尤其是使用诸如wrap_content或的动态值match_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.将可运行对象添加到布局队列:View.post()

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

UI事件队列将按顺序处理事件。调用setContentView()后,事件队列将包含一条消息,要求进行重新布局,因此你发布到队列中的所有内容都会在布局通过后发生

例:

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

相对于ViewTreeObserver:

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

参考文献:

https://stackoverflow.com/a/3602144/774398
https://stackoverflow.com/a/3948036/774398

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

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

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

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

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

如果只需要获取静态定义的高度/宽度,你可以使用以下方法执行此操作:

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

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

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

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

2020-02-25