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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3779173/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 12:06:52  来源:igfitidea点击:

Determining the size of an Android view at runtime

androidandroid-view

提问by Nik Reiman

I am trying to apply an animation to a view in my Android app after my activity is created. To do this, I need to determine the current size of the view, and then set up an animation to scale from the current size to the new size. This part must be done at runtime, since the view scales to different sizes depending on input from the user. My layout is defined in XML.

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

This seems like an easy task, and there are lots of SO questions regarding this though none which solved my problem, obviously. So perhaps I am missing something obvious. I get a handle to my view by:

这似乎是一项简单的任务,并且有很多关于此的问题,但显然没有解决我的问题。所以也许我错过了一些明显的东西。我通过以下方式了解我的观点:

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

This works fine, but when calling getWidth(), getHeight(), getMeasuredWidth(), getLayoutParams().width, etc., they all return 0. I have also tried manually calling measure()on the view followed by a call to getMeasuredWidth(), but that has no effect.

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

I have tried calling these methods and inspecting the object in the debugger in my activity's onCreate()and in onPostCreate(). How can I figure out the exact dimensions of this view at runtime?

我曾尝试调用这些方法并在我的活动onCreate()onPostCreate(). 如何在运行时确定此视图的确切尺寸?

采纳答案by Nik Reiman

Based on @mbaird's advice, I found a workable solution by subclassing the ImageViewclass and overriding onLayout(). I then created an observer interface which my activity implemented and passed a reference to itself to the class, which allowed it to tell the activity when it was actually finished sizing.

根据@maird 的建议,我通过对ImageView类进行子类化并覆盖onLayout(). 然后我创建了一个观察者接口,我的活动实现了它,并将对自身的引用传递给类,这允许它在实际完成大小调整时告诉活动。

I'm not 100% convinced that this is the best solution (hence my not marking this answer as correct just yet), but it does work and according to the documentation is the first time when one can find the actual size of a view.

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

回答by Vikram Bodicherla

Use the ViewTreeObserver on the View to wait for the first layout. Only after the first layout will getWidth()/getHeight()/getMeasuredWidth()/getMeasuredHeight() work.

使用 View 上的 ViewTreeObserver 等待第一个布局。只有在第一个布局之后 getWidth()/getHeight()/getMeasuredWidth()/getMeasuredHeight() 才能工作。

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();
    }
  });
}

回答by android developer

There are actually multiple solutions, depending on the scenario:

实际上有多种解决方案,具体取决于场景:

  1. The safe method, will work just before drawing the view, after the layout phase has finished:
  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); 
}
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); 
}

Sample usage:

示例用法:

    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. On some cases, it's enough to measure the size of the view manually:
  1. 在某些情况下,手动测量视图的大小就足够了:
view.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
int width=view.getMeasuredWidth(); 
int height=view.getMeasuredHeight();
view.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
int width=view.getMeasuredWidth(); 
int height=view.getMeasuredHeight();

If you know the size of the container:

如果您知道容器的大小:

    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. if you have a custom view that you've extended, you can get its size on the "onMeasure" method, but I think it works well only on some cases :
  1. 如果您有一个已扩展的自定义视图,则可以通过“onMeasure”方法获取其大小,但我认为它仅适用于某些情况:
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);
}
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. If you write in Kotlin, you can use the next function, which behind the scenes works exactly like runJustBeforeBeingDrawnthat I've written:

    view.doOnPreDraw { actionToBeTriggered() }
    

    Note that you need to add this to gradle (found via here) :

    implementation 'androidx.core:core-ktx:#.#'
    
  1. 如果你用 Kotlin 编写,你可以使用 next 函数,它的幕后工作与runJustBeforeBeingDrawn我写的完全一样:

    view.doOnPreDraw { actionToBeTriggered() }
    

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

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

回答by Mark B

Are you calling getWidth()before the view is actually laid out on the screen?

您是否getWidth()在视图实际布置在屏幕上之前调用?

A common mistake made by new Android developers is to use the width and height of a view inside its constructor. When a view's constructor is called, Android doesn't know yet how big the view will be, so the sizes are set to zero. The real sizes are calculated during the layout stage, which occurs after construction but before anything is drawn. You can use the onSizeChanged()method to be notified of the values when they are known, or you can use the getWidth()and getHeight()methods later, such as in the onDraw()method.

新 Android 开发人员常犯的一个错误是在其构造函数中使用视图的宽度和高度。当调用视图的构造函数时,Android 尚不知道视图有多大,因此将大小设置为零。实际尺寸是在布局阶段计算的,该阶段发生在构建之后但在绘制任何东西之前。您可以使用该onSizeChanged()方法在已知值时通知它们,或者您可以稍后使用getWidth()getHeight()方法,例如在onDraw()方法中。

回答by gregm

Here is the code for getting the layout via overriding a view if API < 11 (API 11 includes the View.OnLayoutChangedListener feature):

如果 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);
}

回答by Macarse

You can check this question. You can use the View's post()method.

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

回答by Biro Csaba Norbert

This works for me in my onClickListener:

这在我的工作中对我有用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);

回答by Asif Patel

Use below code, it is give the size of view.

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

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

回答by Rakib

I was also lost around getMeasuredWidth()and getMeasuredHeight()getHeight()and getWidth()for a long time.......... later i found that getting the view's width and height in onSizeChanged()is the best way to do this........ you can dynamically get your CURRENT width and CURRENT height of your view by overriding the onSizeChanged() method.

我也失去了身边getMeasuredWidth(),并getMeasuredHeight()getHeight()getWidth()很长一段时间..........后来我发现,越来越视图的宽度和高度onSizeChanged()是做到这一点的最好办法........你可以动态通过覆盖onSizeChanged() 方法来获取视图的当前宽度和当前高度。

might wanna take a look at this which has an elaborate code snippet. New Blog Post: how to get width and height dimensions of a customView (extends View) in Android http://syedrakibalhasan.blogspot.com/2011/02/how-to-get-width-and-height-dimensions.html

可能想看看这个有一个精心设计的代码片段。新博文:如何在 Android 中获取自定义视图(扩展视图)的宽度和高度尺寸http://syedrakibalhasan.blogspot.com/2011/02/how-to-get-width-and-height-dimensions.html

回答by Hitesh Sahu

You can get both Position and Dimension of the view on screen

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

 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]
            }

        }
    });
}