活动生命周期 - 接收布局完成的通知

时间:2011-07-06 11:58:40

标签: android user-interface android-activity

我有一项活动,其中我有3个按钮放在一起。我使用了Button的子类,它将调整按钮文本的大小以防止文本换行。我希望3个按钮共享相同的文本大小。为了做到这一点,我打算检测文本大小最小的按钮,并将其他2个按钮设置为该文本大小。

我遇到的问题是知道Activity何时完成其组件的布局,以便我可以可靠地知道文本的大小调整已经发生。从Android文档中可以看出生命周期中的最新通知是onResume(),但此时布局似乎尚未完成。有没有办法接收活动布局已完成的通知?

11 个答案:

答案 0 :(得分:28)

我使用Tree Observers做了类似的事情。您可能需要稍微调整它以找到它应该附加的视图,但是一旦设置了视图,这将会触发。从那里,您可以获得文本的大小,并进行所需的任何更改。

mTestButton.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        // make sure it is not called anymore 
        mTestButton.getViewTreeObserver().removeGlobalOnLayoutListener(this);

        float size = mTestButton.getTextSize();
    }
});


编辑:
#removeGlobalOnLayoutListener方法已被弃用,但仍然有效。要同时使用新方法和旧方法,请参阅this stackoverflow answer

答案 1 :(得分:2)

据我所知,没有事件或事情告诉你所有东西都被加载了。你可能做的是在oncreate方法结束时启动一个AsyncTask,它运行时你的上一个视图的宽度是0.加载布局时,视图将具有实际大小而不是0,所以你知道它已加载。在ASyncTask的回调中,您可以计算最小的按钮并确定fontsize。

答案 2 :(得分:1)

Activity生命周期回调方法及其窗口/布局本质上没有链接。但是,只要您在调用Button后操纵它们,就可以保证setContentView存在。

答案 3 :(得分:0)

也许您可以在按钮(或包含按钮的视图组)上设置OnLayoutChangeListener并在那里重新调整字体大小?我不确定在布局更改生效之前或之后是否会调用它...

答案 4 :(得分:0)

您可以尝试覆盖Activity.onWindowFocusChanged(boolean),以便在活动可见时可靠地接收通知。然后,您可以假设布局已完成。使用此方法可能遇到的一个问题是,用户可以看到“活动”,因此如果调整了按钮文本的大小,则用户可以看到大小的变化。

答案 5 :(得分:0)

Android会在two steps中进行布局,测量和布局。因为您只需要按钮的大小,所以可以使用getMeasuredWidth而不是getWidth,因为这可以提前使用。

我建议您使用LinearLayout而不是手动尝试定义按钮的宽度。确保指定了android:weightSum,特别是如果你要使用非全宽度布局。

<LinearLayout 
    ...
    android:orientation="horizontal"
    android:weightSum="3"
    >
    <Button 
        ...
        android:layout_weight="1"
        />
    <Button 
        ...
        android:layout_weight="1"
        />
    <Button 
        ...
        android:layout_weight="1"
        />
</LinearLayout>

答案 6 :(得分:0)

为了知道视图的布局何时完成,也许我会在我的活动的onCreate()方法中给它一个runnable,然后从View.onSizeChanged()调用这个runnable。 它应该看起来像

public void onCreate() {
    view.setLayoutRunnable(new Runnable() {
    @Override
    public void run() {
        //do layout stuff...
    }
});

然后在您的视图中执行以下操作。

public Runnable myRunnable;
public void setLayoutRunnable(Runnable runner) {
    myRunnable = runner;
}

@Override
public void onSizeChanged(int w, int h, int oldw, int oldh) {
    if (w > 0 && h > 0 && (w != oldw || h != oldh)) {
        if (myRunnable!= null) 
            myRunnable.run();
    }
}

希望这有帮助。

答案 7 :(得分:0)

我正在动态绘制图像,并希望通过LinearLayout设置ImageViews的大小,然后使用这些大小。因此,我需要在布局完成后创建图像。

我在onCreate的末尾使用了View.post(Runnable),然后在Runnable中创建了图像。我实验了一下,发现onStart,onResume和onPostResume在布局之前发生(ImageView宽度为0)。发布的Runnable在所有这些之后执行,并且在布局之后,因为已经设置了宽度。

public void run() {
    // acquire the ImageView
    if (image.getWidth() == 0)
        image.post( this );

    else {
        // create the images, initialize the ImageViews etc.
    }
}

发布的Runnable可能会在启动过程后发布到UI线程中。 ImageViews将请求布局,并在Runnable之后发布请求。为了以防万一,我检查宽度是否已设置并重新发布Runnable(如果没有)。初始化完成后,Runnable不会再次发布。

答案 8 :(得分:-1)

当我尝试制作水平堆叠的按钮时,我只给它们layout_parent的layout_width但是给它们layout_weight为1。

这样他们都会尝试占用父布局均匀分布的空间。

示例代码将是这样的,我希望它有所帮助:

<LinearLayout 
    android:id="@+id/buttons"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    >
    <Button 
        android:id="@+id/okButton"
        android:layout_height="wrap_content" 
        android:layout_width="wrap_content"
        android:text="OK"
        android:layout_weight="1"
        />
    <Button 
        android:id="@+id/cancelButton"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content" 
        android:text="Cancel"
        android:layout_weight="1"
        />
</LinearLayout>

-serkan

答案 9 :(得分:-1)

您可以使用iswindow()。覆盖它。它将在onPause()之前调用。

答案 10 :(得分:-2)

根据活动生命周期,当onResume()被调用时,布局被视为完成。这是当向用户呈现屏幕时。所以你可以盲目地用这个函数做按钮。