在运行时确定 Android 视图的大小

我试图应用一个动画到我的 Android 应用程序中的一个视图后,我的活动被创建。为此,我需要确定视图的当前大小,然后设置一个动画,以从当前大小缩放到新的大小。这一部分必须在运行时完成,因为视图根据用户的输入可以扩展到不同的大小。我的布局是用 XML 定义的。

这似乎是一个容易的任务,有许多关于这个问题的所以问题,虽然没有解决我的问题,显然。也许我遗漏了一些显而易见的东西。我通过以下方式了解自己的观点:

ImageView myView = (ImageView) getWindow().findViewById(R.id.MyViewID);

这样工作得很好,但是当调用 getWidth()getHeight()getMeasuredWidth()getLayoutParams().width等时,它们都返回0。我还尝试在视图上手动调用 measure(),然后调用 getMeasuredWidth(),但是没有效果。

我尝试过调用这些方法,并在活动的 onCreate()onPostCreate()中的调试器中检查对象。如何在运行时计算出这个视图的确切尺寸?

179113 次浏览

在屏幕上实际显示视图之前,您是否调用了 getWidth()

新 Android 开发人员常犯的一个错误是使用宽度 以及视图在其构造函数中的高度。当视图的 构造函数,Android 还不知道视图的大小 所以大小被设置为零。实际的大小是在 布局阶段,发生在施工之后,但在任何事情之前 您可以使用 onSizeChanged()方法获得通知 值,或者可以使用 getWidth()和 后面的 getHeight()方法,例如在 onDraw()方法中。

根据@mbaird 的建议,我找到了一个可行的解决方案,即对 ImageView类进行子类化并重写 onLayout()。然后,我创建了一个观察者接口,我的活动实现了这个接口,并向类本身传递了一个引用,这允许它在活动实际完成大小调整时告诉它。

我不是100% 相信这是最好的解决方案(因此我还没有把这个答案标记为正确) ,但它确实有效,根据文档,这是第一次可以找到一个视图的实际大小。

如果 API < 11(API 11包含 View.OnLayoutChangedListener 特性) ,下面是通过覆盖视图获得布局的代码:

public class CustomListView extends ListView
{
private OnLayoutChangedListener layoutChangedListener;


public CustomListView(Context context)
{
super(context);
}


@Override
protected void onLayout(boolean changed, int l, int t, int r, int b)
{
if (layoutChangedListener != null)
{
layoutChangedListener.onLayout(changed, l, t, r, b);
}
super.onLayout(changed, l, t, r, b);
}


public void setLayoutChangedListener(
OnLayoutChangedListener layoutChangedListener)
{
this.layoutChangedListener = layoutChangedListener;
}
}
public interface OnLayoutChangedListener
{
void onLayout(boolean changed, int l, int t, int r, int b);
}

我也在 getMeasuredWidth()getMeasuredHeight()getHeight()getWidth()周围迷失了很长一段时间... ..。后来我发现在 onSizeChanged()中获取视图的宽度和高度是最好的方法... ..。通过重写 onSizeChanged(方法,可以动态地获取视图的 CURRENT 宽度和 CURRENT 高度。

可能需要看一下这里有一个复杂的代码片段。 新的博客文章: 如何在安卓系统中获得 customView (扩展视图)的宽度和高度维度(http://syedrakibalhasan.blogspot.com/2011/02/how-to-get-width-and-height- html”rel = “ nofollow”> http://syedrakibalhasan.blogspot.com/2011/02/how-to-get-width-and-height-dimensions.html

在视图中使用 ViewTreeObserver 等待第一个布局,只有在第一个布局之后,getWidth ()/getHeight ()/get拳头宽度()/get拳头宽度()/get拳头高度()才能正常工作。

ViewTreeObserver viewTreeObserver = view.getViewTreeObserver();
if (viewTreeObserver.isAlive()) {
viewTreeObserver.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
viewWidth = view.getWidth();
viewHeight = view.getHeight();
}
});
}

您可以检查 这个问题。您可以使用 View()方法。

这对我的 onClickListener有效:

yourView.postDelayed(new Runnable() {
@Override
public void run() {
yourView.invalidate();
System.out.println("Height yourView: " + yourView.getHeight());
System.out.println("Width yourView: " + yourView.getWidth());
}
}, 1);

根据具体情况,实际上有多种解决方案:

  1. 安全方法,将在绘制视图之前,在布局阶段完成之后工作:
public static void runJustBeforeBeingDrawn(final View view, final Runnable runnable) {
final OnPreDrawListener preDrawListener = new OnPreDrawListener() {
@Override
public boolean onPreDraw() {
view.getViewTreeObserver().removeOnPreDrawListener(this);
runnable.run();
return true;
}
};
view.getViewTreeObserver().addOnPreDrawListener(preDrawListener);
}

使用方法:

    ViewUtil.runJustBeforeBeingDrawn(yourView, new Runnable() {
@Override
public void run() {
//Here you can safely get the view size (use "getWidth" and "getHeight"), and do whatever you wish with it
}
});
  1. 在某些情况下,手动测量视图的大小就足够了:
view.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
int width=view.getMeasuredWidth();
int height=view.getMeasuredHeight();

如果你知道容器的大小:

    val widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(maxWidth, View.MeasureSpec.AT_MOST)
val heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(maxHeight, View.MeasureSpec.AT_MOST)
view.measure(widthMeasureSpec, heightMeasureSpec)
val width=view.measuredWidth
val height=view.measuredHeight
  1. 如果您有一个已经扩展的自定义视图,您可以通过“ on拳头”方法得到它的大小,但是我认为它只在某些情况下有效:
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
final int newHeight= MeasureSpec.getSize(heightMeasureSpec);
final int newWidth= MeasureSpec.getSize(widthMeasureSpec);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
  1. 如果你在 Kotlin 写作,你可以使用下一个函数,它在幕后的工作原理和我写的 abc 0一模一样:

     view.doOnPreDraw { actionToBeTriggered() }
    

请注意,您需要将此添加到 gradle (通过 这里找到) :

android {
kotlinOptions {
jvmTarget = "1.8"
}
}


implementation 'androidx.core:core-ktx:#.#'

使用下面的代码,它给出了视图的大小。

@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
Log.e("WIDTH",""+view.getWidth());
Log.e("HEIGHT",""+view.getHeight());
}

对我来说再合适不过了:

 protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
CTEditor ctEdit = Element as CTEditor;
if (ctEdit == null) return;
if (e.PropertyName == "Text")
{
double xHeight = Element.Height;
double aHaight = Control.Height;
double height;
Control.Measure(LayoutParams.MatchParent,LayoutParams.WrapContent);
height = Control.MeasuredHeight;
height = xHeight / aHaight * height;
if (Element.HeightRequest != height)
Element.HeightRequest = height;
}
}

您可以在屏幕上获得视图的位置和尺寸

 val viewTreeObserver: ViewTreeObserver = videoView.viewTreeObserver;


if (viewTreeObserver.isAlive) {
viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
//Remove Listener
videoView.viewTreeObserver.removeOnGlobalLayoutListener(this);


//View Dimentions
viewWidth = videoView.width;
viewHeight = videoView.height;


//View Location
val point = IntArray(2)
videoView.post {
videoView.getLocationOnScreen(point) // or getLocationInWindow(point)
viewPositionX = point[0]
viewPositionY = point[1]
}


}
});
}

在 Kotlin 的文件中,做相应的修改

 Handler().postDelayed({


Your Code


}, 1)

如果你需要知道一个视图的尺寸,你可以简单地调用 post ()在给定的视图,并发送一个 Runnable,执行任何你需要的。 这是一个比 ViewTreeObserver 和 globalLayout 更好的解决方案,因为它被反复调用,而不是一次。 这个 Runnsble 只执行一次,您将知道视图的大小。