(4.1.6.1)getMeasuredHeight()与getHeight的区别

本文详细解析了Android中View的高度获取方法getHeight()与getMeasuredHeight()的区别。探讨了这两种方法的具体应用场景,以及它们在View生命周期中的调用时机。通过源码分析,揭示了这两种方法返回值的真正含义。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前提知识点:
1. 在一个类初始化时,即在构造函数当中是得不到View的实际大小的。getWidth()和getMeasuredWidth()得到的结果都是0,但是可以从onDraw()方法或者dispatchDraw()方法里面获得。可以通过调用invalidate()来执行onDraw()和dispatchDraw()方法。
2. 这两个方法所得到的结果的单位是像素即pixel

我们分析下这两个方法的不同,先看官方文档:

这里写图片描述

  • getHeight 表示的是 View实际绘制出来的的大小
  • getMeasuredHeight()是实际View的大小,也就是在父容器在计算当前view大小时,当前View的OnMeasure中设置的大小,与屏幕无关,与父容器大小无关
  • getMeasuredHeight()与getHeight()并没有直接关系,但是我们在layout的时候一般会遵循一定的原则

getMeasuredHeight取出的就是setMeasuredDimension的值

当然,上述其实只是一个概念,我们进一步的研究下,按照我们一个自定义View的过程中,我们会在onMeasure(int widthMeasureSpec, int heightMeasureSpec)方法中完成测量后,必须调用View#setMeasuredDimension(int measuredWidth, int measuredHeight):

    protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) {
        boolean optical = isLayoutModeOptical(this);
        if (optical != isLayoutModeOptical(mParent)) {
            Insets insets = getOpticalInsets();
            int opticalWidth  = insets.left + insets.right;
            int opticalHeight = insets.top  + insets.bottom;

            measuredWidth  += optical ? opticalWidth  : -opticalWidth;
            measuredHeight += optical ? opticalHeight : -opticalHeight;
        }
        setMeasuredDimensionRaw(measuredWidth, measuredHeight);
    }

其最终调用:

    private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) {
        mMeasuredWidth = measuredWidth;
        mMeasuredHeight = measuredHeight;

        mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET;
    }

而我们getMeasuredHeight()取出来的就是mMeasuredHeight :

    public final int getMeasuredHeight() {
        return mMeasuredHeight & MEASURED_SIZE_MASK;
    }

getHeight 取出的是父布局在绘制当前View的onLayout()中调用child.Layout(。。。)传入的参数

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        Log.e("test", "MyViewGroup.onLayout  left = " + l + "  top = " + t + "  right = " + r + "  bottom = " + b);
        View view = getChildAt(0);
        int d = 200;
        d = -d;
//        d = t;
//        view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());

        l = -100 + new Random().nextInt(100);
        t = 0;
        r = view.getMeasuredWidth() - 100;
        b = view.getMeasuredHeight() - 100;
        //view.getHeight= t- b;
        view.layout(l, t, r, b);
    }
  public void layout(int l, int t, int r, int b) {
        if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) {
            onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec);
            mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
        }

        int oldL = mLeft;
        int oldT = mTop;
        int oldB = mBottom;
        int oldR = mRight;

        boolean changed = isLayoutModeOptical(mParent) ?
                setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);

        if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {
            onLayout(changed, l, t, r, b);
            mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED;

            ListenerInfo li = mListenerInfo;
            if (li != null && li.mOnLayoutChangeListeners != null) {
                ArrayList<OnLayoutChangeListener> listenersCopy =
                        (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone();
                int numListeners = listenersCopy.size();
                for (int i = 0; i < numListeners; ++i) {
                    listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB);
                }
            }
        }

        mPrivateFlags &= ~PFLAG_FORCE_LAYOUT;
        mPrivateFlags3 |= PFLAG3_IS_LAID_OUT;
    }

我们来看看getHeight():

    public final int getHeight() {
        return mBottom - mTop;
    }
<think>好的,我现在要解决用户的问题:如何正确使用mRecyclerView.getHeight()来获取RecyclerView的高度。首先,我需要回顾一下Android中View的测量机制。RecyclerView作为ViewGroup的一种,其高度可能受到布局流程的影响,比如在Activity生命周期中,如果过早调用getHeight(),可能还未完成测量,导致返回0。 接下来,用户提到他们已经在布局文件中正确设置了RecyclerView,并且引用了相关的代码,比如通过findViewById获取实例,设置了LayoutManager等。这说明他们的基本配置是正确的。但问题出现在何时获取高度。这时候需要考虑View的生命周期,特别是onCreate方法中可能无法立即获取正确的尺寸,因为此时View还未被测量。 然后,我需要思考正确的获取时机。通常,在onWindowFocusChanged方法中,当窗口获得焦点时,View已经完成布局,这时候调用getHeight()可以得到正确的高度。另外,使用ViewTreeObserver的OnGlobalLayoutListener也是一个可行的方法,它会在布局变化时回调,确保在布局完成后获取高度。 此外,用户可能遇到动态改变RecyclerView内容的情况,比如数据更新后需要重新获取高度。这时候可能需要再次监听布局变化,或者在数据更新后手动触发测量。 还要注意,如果在子线程中直接调用getHeight()可能会有问题,需要确保在主线程中操作。同时,如果RecyclerView的布局参数设置为wrap_content,可能需要确保内容已经加载完成,否则高度可能不准确。 最后,需要检查用户是否正确添加了依赖库,如引用[4]中的recyclerview-v7库,确保RecyclerView本身能够正常工作。如果有其他布局问题,比如父容器的约束不正确,也可能影响高度的获取,需要综合考虑。</think>### 如何正确获取 RecyclerView 的高度? #### 1. 直接调用 `getHeight()` 的限制 在 `onCreate()` 或 `onResume()` 中直接调用 `mRecyclerView.getHeight()` 可能返回 `0`,因为此时视图尚未完成测量和布局。例如: ```java // onCreate() 中直接调用会失效 int height = mRecyclerView.getHeight(); // 可能返回 0 ``` #### 2. 正确获取高度的三种方法 **方法一:使用 `ViewTreeObserver` 监听布局完成** ```java mRecyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { // 确保移除监听避免重复调用 mRecyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this); int height = mRecyclerView.getHeight(); Log.d("RecyclerViewHeight", "Height: " + height); } }); ``` *原理*:在视图树完成布局后触发回调,此时可获取准确高度[^3]。 **方法二:在 `onWindowFocusChanged` 中获取** ```java @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); if (hasFocus) { int height = mRecyclerView.getHeight(); Log.d("RecyclerViewHeight", "Height: " + height); } } ``` *适用场景*:适用于需要窗口焦点稳定后的场景(如对话框)。 **方法三:手动触发测量** ```java mRecyclerView.post(new Runnable() { @Override public void run() { int widthSpec = View.MeasureSpec.makeMeasureSpec(mRecyclerView.getWidth(), View.MeasureSpec.EXACTLY); int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); mRecyclerView.measure(widthSpec, heightSpec); int height = mRecyclerView.getMeasuredHeight(); } }); ``` *注意*:此方法强制测量视图,适用于动态内容变化的场景[^2]。 #### 3. 常见问题排查 - **布局未完成**:确保在 `RecyclerView.setAdapter()` 和 `RecyclerView.setLayoutManager()` 之后获取高度 - **动态数据加载**:若数据异步加载,需在数据填充完成后重新获取高度 - **布局参数冲突**:检查 XML 中是否设置了 `android:layout_height="wrap_content"` 或固定值
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值