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

时间:2010-09-23 14:02:48

标签: android

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

这似乎是一件容易的事,虽然没有一个能解决我的问题,但很多问题都存在。所以也许我错过了一些明显的东西。我通过以下方式处理了我的观点:

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

这样做很好,但是在调用getWidth()getHeight()getMeasuredWidth()getLayoutParams().width等时,它们都返回0.我还尝试手动调用{{ 1}}在视图上跟随调用measure(),但这没有效果。

我尝试调用这些方法并在我的活动getMeasuredWidth()onCreate()中检查调试器中的对象。如何在运行时确定此视图的确切尺寸?

13 个答案:

答案 0 :(得分:173)

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

答案 1 :(得分:51)

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

  1. 在布局阶段结束后,安全方法将在绘制视图之前工作:
  2. 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. 在某些情况下,手动测量视图的大小就足够了:
    2. 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. 如果你有一个自定义视图,你可以在“onMeasure”方法上获得它的大小,但我认为它只适用于某些情况:
      2. 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写作,你可以使用下一个函数,它在幕后的工作方式与我写的runJustBeforeBeingDrawn完全相同:

          view.doOnPreDraw { actionToBeTriggered() }
          

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

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

答案 2 :(得分:19)

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

  

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

答案 3 :(得分:17)

基于@ mbaird的建议,我通过继承ImageView类并覆盖onLayout()找到了一个可行的解决方案。然后我创建了一个我的活动实现的观察器接口,并将对它自己的引用传递给了类,这允许它在实际完成大小调整时告诉活动。

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

答案 4 :(得分:10)

以下是通过覆盖视图来获取布局的代码,如果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);
}

答案 5 :(得分:6)

您可以查看this question。您可以使用View的{​​{3}}方法。

答案 6 :(得分:5)

这适用于我的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);

答案 7 :(得分:4)

我也在getMeasuredWidth()getMeasuredHeight() getHeight()以及getWidth()长时间迷路..........后来我发现得到了view onSizeChanged()中的视图宽度和高度是执行此操作的最佳方式........您可以通过覆盖onSizeChanged()方法动态获取视图的CURRENT宽度和CURRENT高度。< / p>

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

答案 8 :(得分:4)

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

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

答案 9 :(得分:0)

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

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

        }
    });
}

答案 10 :(得分:0)

在Kotlin文件中,进行相应更改

 Handler().postDelayed({

           Your Code

        }, 1)

答案 11 :(得分:0)

如果您需要在绘制后立即知道 View 的尺寸,您可以简单地在给定的 View 上调用 post() 并发送一个 Runnable 来执行您需要的任何内容。 它是比 ViewTreeObserver 和 globalLayout 更好的解决方案,因为它被重复调用而不仅仅是一次。 这个 Runnsble 只会执行一次,你就会知道视图的大小。

答案 12 :(得分:-1)

对我来说是完美的:

 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;
        }
    }
相关问题