Determining the size of an Android view at runtime

前端 未结 12 1740
陌清茗
陌清茗 2020-11-22 09:59

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

相关标签:
12条回答
  • 2020-11-22 10:22

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

    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();
        }
      });
    }
    
    0 讨论(0)
  • 2020-11-22 10:24

    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]
                }
    
            }
        });
    }
    
    0 讨论(0)
  • 2020-11-22 10:25

    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:
    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:
    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 :
    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 runJustBeforeBeingDrawn that I've written:

       view.doOnPreDraw { actionToBeTriggered() }
      

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

    android {
        kotlinOptions {
            jvmTarget = "1.8"
        }
    }
    
    implementation 'androidx.core:core-ktx:#.#'
    
    0 讨论(0)
  • 2020-11-22 10:29

    Based on @mbaird's advice, I found a workable solution by subclassing the ImageView class 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.

    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.

    0 讨论(0)
  • 2020-11-22 10:29

    works perfekt for me:

     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;
            }
        }
    
    0 讨论(0)
  • 2020-11-22 10:30

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

    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.

    0 讨论(0)
提交回复
热议问题