ngr*_*od6 487 java getter android android-layout
我动态地在我的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);
}
Run Code Online (Sandbox Code Playgroud)
任何帮助表示赞赏.
pat*_*ckf 765
基本问题是,您必须等待实际测量的绘制阶段(特别是动态值,如wrap_content或match_parent),但通常此阶段尚未完成onResume().所以你需要一个等待这个阶段的解决方法.有一个不同的可能的解决方案:
ViewTreeObserver会因不同的绘图事件而被触发.通常,OnGlobalLayoutListener您可以获得测量结果,因此在布局阶段之后将调用侦听器中的代码,因此测量结果已准备就绪:
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
view.getHeight(); //height is ready
}
});
Run Code Online (Sandbox Code Playgroud)
注意:将立即删除侦听器,否则将触发每个布局事件.如果您必须支持SDK Lvl <16,请使用此方法取消注册侦听器:
public void removeGlobalOnLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim)
不太知名和我最喜欢的解决方案.基本上只需使用View的post方法和您自己的runnable.这基本上是在视图的度量,布局等之后将代码排队,如Romain Guy所述:
UI事件队列将按顺序处理事件.在调用setContentView()之后,事件队列将包含一条要求重新布局的消息,因此在布局通过后,您发送到队列的任何内容都会发生
例:
final View view=//smth;
...
view.post(new Runnable() {
@Override
public void run() {
view.getHeight(); //height is ready
}
});
Run Code Online (Sandbox Code Playgroud)
优势超过ViewTreeObserver:
参考文献:
这在逻辑可以封装在视图本身中的某些情况下才是实用的,否则这是一种非常冗长和繁琐的语法.
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
}
};
Run Code Online (Sandbox Code Playgroud)
还要注意,onLayout会被多次调用,所以要考虑你在方法中做了什么,或者在第一次之后禁用你的代码
如果您在创建UI时有多次执行代码,则可以使用以下支持v4 lib方法:
View viewYouNeedHeightFrom = ...
...
if(ViewCompat.isLaidOut(viewYouNeedHeightFrom)) {
viewYouNeedHeightFrom.getHeight();
}
Run Code Online (Sandbox Code Playgroud)
如果视图自上次附加到窗口或从窗口分离以来已经通过至少一个布局,则返回true.
如果只需要获得静态定义的高度/宽度就足够了,你可以这样做:
但请注意,这可能与绘图后的实际宽度/高度不同.javadoc完美地描述了这种差异:
视图的大小用宽度和高度表示.视图实际上具有两对宽度和高度值.
第一对称为测量宽度和测量高度.这些维度定义了视图在其父级中的大小(有关更多详细信息,请参阅布局.)可以通过调用getMeasuredWidth()和getMeasuredHeight()来获取测量的维度.
第二对简称为宽度和高度,有时也称为绘图宽度和绘图高度.这些尺寸定义了屏幕上,绘图时和布局后视图的实际大小.这些值可以但不必与测量的宽度和高度不同.可以通过调用getWidth()和getHeight()来获得宽度和高度.
San*_*ana 261
我们可以用
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
//Here you can get the size!
}
Run Code Online (Sandbox Code Playgroud)
Com*_*are 184
你打电话getWidth()太早了.UI尚未调整大小并在屏幕上显示.
我怀疑你想要做你正在做的事情,无论如何 - 动画小工具不会改变它们的可点击区域,因此按钮仍然会响应原始方向的点击,无论它如何旋转.
话虽这么说,您可以使用维度资源来定义按钮大小,然后从布局文件和源代码中引用该维度资源,以避免此问题.
Tim*_*tin 107
我使用这个解决方案,我认为它比onWindowFocusChanged()更好.如果打开DialogFragment,然后旋转手机,只有当用户关闭对话框时才会调用onWindowFocusChanged):
yourView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
// Ensure you call it only once :
yourView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
// Here you can get the size :)
}
});
Run Code Online (Sandbox Code Playgroud)
编辑:由于不推荐使用removeGlobalOnLayoutListener,您现在应该:
@SuppressLint("NewApi")
@SuppressWarnings("deprecation")
@Override
public void onGlobalLayout() {
// Ensure you call it only once :
if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
yourView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
else {
yourView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
// Here you can get the size :)
}
Run Code Online (Sandbox Code Playgroud)
小智 75
正如Ian在这个Android开发者线程中所述:
无论如何,交易是在构造所有元素并将其添加到父视图之后,窗口内容的布局发生 .它必须是这种方式,因为直到你知道View包含哪些组件,它们包含什么,等等,你就没有明智的方法可以解决它.
最重要的是,如果在构造函数中调用getWidth()等,它将返回零.过程是在构造函数中创建所有视图元素,然后等待View的onSizeChanged()方法被调用 - 这是当你第一次找到你的实际大小时,所以当你设置GUI元素的大小时.
也要注意onSizeChanged()有时会被调用参数为零 - 检查这种情况,并立即返回(因此在计算布局时不要除以零).一段时间后,将使用真实值调用它.
小智 64
如果您需要在屏幕上显示某个小部件的宽度之前获取其宽度,则可以使用getMeasuredWidth()或getMeasuredHeight().
myImage.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
int width = myImage.getMeasuredWidth();
int height = myImage.getMeasuredHeight();
Run Code Online (Sandbox Code Playgroud)
Aya*_*fov 20
我宁愿使用OnPreDrawListener()而不是addOnGlobalLayoutListener(),因为它是早先调用的.
view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener()
{
@Override
public boolean onPreDraw()
{
if (view.getViewTreeObserver().isAlive())
view.getViewTreeObserver().removeOnPreDrawListener(this);
// put your code here
return true;
}
});
Run Code Online (Sandbox Code Playgroud)
Vla*_*lad 18
AndroidX 有多个扩展功能可以帮助你完成这类工作,里面 androidx.core.view
为此,您需要使用 Kotlin。
最适合这里的是doOnLayout:
在布局此视图时执行给定的操作。如果视图已经布局并且还没有请求布局,则将立即执行该操作,否则将在下一次布局视图之后执行该操作。
该动作只会在下一个布局上被调用一次,然后被删除。
在你的例子中:
bt.doOnLayout {
val ra = RotateAnimation(0,360,it.width / 2,it.height / 2)
// more code
}
Run Code Online (Sandbox Code Playgroud)
依赖: androidx.core:core-ktx:1.0.0
Kotlin扩展程序,用于观察全局布局,并在动态准备好高度时执行给定的任务。
用法:
view.height { Log.i("Info", "Here is your height:" + it) }
Run Code Online (Sandbox Code Playgroud)
实现方式:
fun <T : View> T.height(function: (Int) -> Unit) {
if (height == 0)
viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
viewTreeObserver.removeOnGlobalLayoutListener(this)
function(height)
}
})
else function(height)
}
Run Code Online (Sandbox Code Playgroud)
如果您使用的是RxJava和RxBindings,则使用一根衬板。没有样板的类似方法。如蒂姆·奥丁(Tim Autin)的回答一样,这也解决了黑客抑制警告的问题。
RxView.layoutChanges(yourView).take(1)
.subscribe(aVoid -> {
// width and height have been calculated here
});
Run Code Online (Sandbox Code Playgroud)
就是这个。即使从未调用,也无需取消订阅。
也许这对某人有帮助:
为View类创建扩展函数
文件名:ViewExt.kt
fun View.afterLayout(what: () -> Unit) {
if(isLaidOut) {
what.invoke()
} else {
viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
viewTreeObserver.removeOnGlobalLayoutListener(this)
what.invoke()
}
})
}
}
Run Code Online (Sandbox Code Playgroud)
然后可以将其用于任何视图:
view.afterLayout {
do something with view.height
}
Run Code Online (Sandbox Code Playgroud)
发生这种情况是因为视图需要更多时间来膨胀。因此,不要在主线程上调用view.width和view.height,您应该使用view.post { ... }来确保您view已经膨胀。在科特林:
view.post{width}
view.post{height}
Run Code Online (Sandbox Code Playgroud)
在 Java 中,您还可以调用 a 中的getWidth()和getHeight()方法Runnable并传递Runnabletoview.post()方法。
view.post(new Runnable() {
@Override
public void run() {
view.getWidth();
view.getHeight();
}
});
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
301043 次 |
| 最近记录: |