我有一项活动,其中我有3个按钮放在一起。我使用了Button的子类,它将调整按钮文本的大小以防止文本换行。我希望3个按钮共享相同的文本大小。为了做到这一点,我打算检测文本大小最小的按钮,并将其他2个按钮设置为该文本大小。
我遇到的问题是知道Activity何时完成其组件的布局,以便我可以可靠地知道文本的大小调整已经发生。从Android文档中可以看出生命周期中的最新通知是onResume(),但此时布局似乎尚未完成。有没有办法接收活动布局已完成的通知?
答案 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()
被调用时,布局被视为完成。这是当向用户呈现屏幕时。所以你可以盲目地用这个函数做按钮。