Activity中何时能拿到组件的宽高

        在日常Android开发中,你什么时候才能在Activity中准确拿到组件View的宽高呢?大部分情况下我们在onCreate()中就已经findViewById()了,那是不是只要在这之后就能准确拿到组件的宽高呢?

        我们写代码跑一下试试,我们分别在onCreate()结束时,onStart()开始和结束时,onResume()开始和结束时去尝试获取View的width和measuredWidth,看看到底能不能拿到宽高。

        由于页面布局就是个约束布局里面放着一个按钮,因此布局文件不贴了。

package com.openld.seniorstructure.testobtainviewwidth

import android.os.Bundle
import android.util.Log
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity
import com.openld.seniorstructure.R

class TestObtainViewWidthActivity : AppCompatActivity() {
    private lateinit var mBtn: Button

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_test_obtain_view_width)

        initWidgets()

        Log.d(
            ">>>>>>",
            "onCreate end: btn.width = ${mBtn.width}  btn.measuredWidth = ${mBtn.measuredWidth}"
        )
    }

    private fun initWidgets() {
        mBtn = findViewById(R.id.btn)
    }

    override fun onStart() {
        Log.d(
            ">>>>>>",
            "onStart start: btn.width = ${mBtn.width}  btn.measuredWidth = ${mBtn.measuredWidth}"
        )

        super.onStart()

        Log.d(
            ">>>>>>",
            "onStart end: btn.width = ${mBtn.width}  btn.measuredWidth = ${mBtn.measuredWidth}"
        )
    }

    override fun onResume() {
        Log.d(
            ">>>>>>",
            "onResume start: btn.width = ${mBtn.width}  btn.measuredWidth = ${mBtn.measuredWidth}"
        )

        super.onResume()

        Log.d(
            ">>>>>>",
            "onResume end: btn.width = ${mBtn.width}  btn.measuredWidth = ${mBtn.measuredWidth}"
        )
    }
}

        运行一下页面看下日志如下:

         啪啪打脸,可以毫无疑问地说,即便是在onResume()结束的时候,你直接通过view.getWidth()或者view.getMeasuredWidth()也是拿不到实际的组件宽高的。

        那怎么在Activity中去拿到组件的宽高呢?这里有两个思路,一个是在onCreate()中调用view.post()去拿。另一个是在onWindowFocusChanged()回调中去拿。

        我们先试一下post方式。

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_test_obtain_view_width)

        initWidgets()

        mBtn.post {
            Log.d(
                ">>>>>>",
                "onCreate 中调用mBtn.post  btn.width = ${mBtn.width}  btn.measuredWidth = ${mBtn.measuredWidth}"
            )
        }

        Log.d(
            ">>>>>>",
            "onCreate end: btn.width = ${mBtn.width}  btn.measuredWidth = ${mBtn.measuredWidth}"
        )
    }

         可以看到正确拿到了。断点看了下会走到postOnAniumation()方法,这个方法注释很关键。

public static void postOnAnimation(@NonNull View view, @NonNull Runnable action) {
        if (Build.VERSION.SDK_INT >= 16) {
            Api16Impl.postOnAnimation(view, action);
        } else {
            view.postDelayed(action, ValueAnimator.getFrameDelay());
        }
    }

Causes the Runnable to execute on the next animation time step. The runnable will be run on the user interface thread.
This method can be invoked from outside of the UI thread only when this View is attached to a window.

        意思是说只有View被真正附加到了window上才会执行,那拿到宽高就不足为奇了。

        我们再试一下onWindowFocusChanged()。

        可以看到同样能够正确拿到组件宽高。 可以看下方法注释,其实就是页面真正获取或失去了焦点会回调这个方法,那获取焦点的时候拿宽高当然是拿得到的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值