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

任何帮助都是感激的。


当前回答

这是因为视图需要更多的时间来膨胀。所以不用调用view。宽度和视图。主线程上的高度,你应该使用视图。Post{…}以确保你的观点已经被夸大了。在芬兰湾的科特林:

view.post{width}
view.post{height}

在Java中,您还可以在Runnable中调用getWidth()和getHeight()方法,并将Runnable传递给view.post()方法。

view.post(new Runnable() {
        @Override
        public void run() {
            view.getWidth(); 
            view.getHeight();
        }
    });

其他回答

如果你使用RxJava & RxBindings,一行。类似的方法没有样板。这也解决了蒂姆·奥廷(Tim Autin)的回答中隐藏警告的问题。

RxView.layoutChanges(yourView).take(1)
      .subscribe(aVoid -> {
           // width and height have been calculated here
      });

就是它了。不需要取消订阅,即使从未调用。

基本的问题是,你必须等待实际测量的绘制阶段(特别是像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使用这个来注销监听器:

removeGlobalOnLayoutListener (ViewTreeObserver)OnGlobalLayoutListener受害者)


2. 添加一个可运行对象到布局队列:

不是很有名,也是我最喜欢的解决方案。基本上只需要使用视图的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.覆盖视图的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时执行了多次,你可以使用下面的support v4 lib方法:

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

如果视图自创建以来至少经历过一次布局,则返回true 最后附着在窗户上或从窗户上分离的。

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

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

View.getMeasuredWidth () View.getMeasuredHeigth ()

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

The size of a view is expressed with a width and a height. A view actually possess two pairs of width and height values. The first pair is known as measured width and measured height. These dimensions define how big a view wants to be within its parent (see Layout for more details.) The measured dimensions can be obtained by calling getMeasuredWidth() and getMeasuredHeight(). The second pair is simply known as width and height, or sometimes drawing width and drawing height. These dimensions define the actual size of the view on screen, at drawing time and after layout. These values may, but do not have to, be different from the measured width and height. The width and height can be obtained by calling getWidth() and getHeight().

这是因为视图需要更多的时间来膨胀。所以不用调用view。宽度和视图。主线程上的高度,你应该使用视图。Post{…}以确保你的观点已经被夸大了。在芬兰湾的科特林:

view.post{width}
view.post{height}

在Java中,您还可以在Runnable中调用getWidth()和getHeight()方法,并将Runnable传递给view.post()方法。

view.post(new Runnable() {
        @Override
        public void run() {
            view.getWidth(); 
            view.getHeight();
        }
    });

我们可以用

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

如果需要在屏幕上显示某个小部件之前获取它的宽度,可以使用getMeasuredWidth()或getMeasuredHeight()。

myImage.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
int width = myImage.getMeasuredWidth();
int height = myImage.getMeasuredHeight();