码迷,mamicode.com
首页 > 其他好文 > 详细

github项目解析(八)-->Activity启动过程中获取组件宽高的三种方式

时间:2016-06-28 13:12:50      阅读:194      评论:0      收藏:0      [点我收藏+]

标签:

转载请标明出处:一片枫叶的专栏

上一个github小项目中我们介绍了防止按钮重复点击的小框架,其实现的核心逻辑是重写OnClickListener的onClick方法,添加防止重复点击的逻辑,即为第二次点击与第一次点击的时间间隔添加阙值,若第二次点击的时间间隔与第一次点击的时间间隔小于阙值,则此次点击无效,再次基础上我们又封装了点击组件验证网络Listener,点击组件验证是否登录Listener等,具体可参考: github项目解析(七)–>防止按钮重复点击

本文中我将介绍一下android中Activity启动时获取组件宽高的三种方式。我们知道,有时候我们需要在Activity启动的时候获取某一组件的宽或者是高用于动态的更改UI布局文件,但是这时候我们直接通过getWidth和getHeight方法获取是有问题的。为什么这么说呢?这里我们可以下一个测试的例子来验证一下:


问题:

  • 在Activity的启动流程中通过getWidht和getHeight方法获取组件的宽度和高度
/**
 * 在onCreate方法中调用,用于获取TextView的宽度和高度
 */
private void getTextHeightAndWidth() {
        // 我们定义的用于获取宽度和高度的组件
        titleText = (TextView) findViewById(R.id.text_title);

        int height = titleText.getHeight();
        int width = titleText.getWidth();

        Log.i(TAG, "height:" + height + "  " + "width:" + width);
    }

这段代码看似是正常没有问题的,但是我们将调用的代码写在onCreate方法的时候,执行这段代码之后,打印的结果:

06-26 20:12:15.356 19453-19453/uuch.com.android_viewheight I/MainActivity: height:0  width:0

咦?为什么打印的height和width都是0呢?我们在执行一遍呢?结果还是一样的,两个变量都是0,难道这段代码不能再onCreate方法中调用,那么我们试试在onResume方法中调用呢?

只能说然并卵,打印的结果依然是:

06-26 20:52:13.986 19453-19453/uuch.com.android_viewheight I/MainActivity: height:0  width:0

好吧,问题已经出来了,看样子我们是不能再onCreate方法或者是onResume方法中调用该方法获取组件的宽高的,但是这是为什么呢?平时我们都是通过这个方法来获取组件的宽高的,并且也没问题啊,比如我们将这个方法的调用逻辑写在按钮的点击事件之内呢?我们再来试试。

/**
 * 这里的button1是我们定义的Button组件,并且我们重写了Button的点击事件,在其中调用了获取组件宽高的方法
 */
button1 = (Button) findViewById(R.id.button1);
button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                getTextHeightAndWidth();
            }
        });

这样敲完代码之后,我们执行这段代码,界面入下图所示:
技术分享

那么我们的打印结果呢?

06-26 20:57:08.188 22648-22648/uuch.com.android_viewheight I/MainActivity: height:57  width:225

恩?这时候我们发现其打印出了组件的宽和高,那么为什么我们在Activity的onCreate、onResume方法中打印的时候,输出的组件宽高都是为0呢?


原因:

其实看过我以前写过的
android源码解析之(十四)–>Activity启动流程
android源码解析(十七)–>Activity布局加载流程
android源码解析(十八)–>Activity布局绘制流程
的同学应该对Activity的启动流程和其布局加载绘制流程不陌生,Activity的启动流程和Activity的布局文件加载绘制流程,其实没有相关的关系的,其实两个异步的加载流程,这样我们在Activity的onCreate和onResume方法调用textView.getHeight或者是textView.getWidth方法的时候,其组件并没有执行完绘制流程,因此此时获取到的组件的宽高都是默认的0,也就是无法获取组件的宽和高。

但是当我们将获取组件宽高的方法卸载按钮的点击事件的时候,由于此时按钮已经显示出来了,所以证明布局文件已经加载绘制完成,这时候点击组件执行组件的获取宽高方法,就能正常的获取到组件的宽和高了。

这也就是为什么我们在onCreate和onResume方法中调用获取组件宽高都是0,而在按钮的点击事件中获取的时候正常的原因了。


其他解决方案:

那么如果我们想在Activity的onCreate方法或者是onReusme方法获取组件的宽高怎么办呢?这里提供了以下的三种方式:

  • 重写Activity的onWindowFocusChanged方法
/**
 * 重写Acitivty的onWindowFocusChanged方法
 */ 
@Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        /**
         * 当hasFocus为true的时候,说明Activity的Window对象已经获取焦点,进而Activity界面已经加载绘制完成
         */
        if (hasFocus) {
            int widht = titleText.getWidth();
            int height = titleText.getHeight();
            Log.i(TAG, "onWindowFocusChanged width:" + widht + "   "
                            + "  height:" + height;
        }
    }


说明:

这样重写onWindowFocusChanged方法,当获取焦点的时候我们就可以通过getWidth和getHeight方法得到组件的宽和高了。但是这时候这个方法的逻辑可能会执行多次,也就是说只要我们的Activity的window对象获取了焦点就会执行该语句,所以我们需要做一些逻辑判断,让它在我们需要打印获取组件宽高的时候在执行。

  • 为组件添加OnGlobalLayoutListener事件监听
/**
 * 为Activity的布局文件添加OnGlobalLayoutListener事件监听,当回调到onGlobalLayout方法的时候我们通过getMeasureHeight和getMeasuredWidth方法可以获取到组件的宽和高
 */
private void initOnLayoutListener() {
        final ViewTreeObserver viewTreeObserver = this.getWindow().getDecorView().getViewTreeObserver();
        viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                Log.i(TAG, "开始执行onGlobalLayout().........");
                int height = titleText.getMeasuredHeight();
                int width = titleText.getMeasuredWidth();

                Log.i(TAG, "height:" + height + "   width:" + width);
            }
        });
    }

说明:

需要说明的是这里的onGlobalLayout方法会在Activity的组件执行完onLayout方法之后执行,这里的onLayout方法主要用于计算组件的宽高操作,具体可参考:android源码解析(十八)–>Activity布局绘制流程,这样当我们计算完组件的宽高之后再执行获取组件的宽高操作,自然能够获取到组件的宽度和高度。

  • 为组件添加OnPreDrawListener事件监听
/**
     * 初始化viewTreeObserver事件监听,重写OnPreDrawListener获取组件高度
     */
    private void initOnPreDrawListener() {
        final ViewTreeObserver viewTreeObserver = this.getWindow().getDecorView().getViewTreeObserver();
        viewTreeObserver.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            @Override
            public boolean onPreDraw() {
                Log.i(TAG, "开始执行onPreDraw().........");
                int height = titleText.getMeasuredHeight();
                int width = titleText.getMeasuredWidth();

                Log.i(TAG, "height:" + height + "   width:" + width);
                return true;
            }
        });
    }

说明:

需要说明的是这里的onPreDraw方法会在Activity的组件执行onDraw方法之前执行,熟悉我们Activity组件加载绘制流程的同学应该知道,这里的onDraw方法主要用于执行真正的绘制组件操作,而这时候我们已经计算出来了组件的位置,宽高等操作,这样之后再执行获取组件的宽高操作,自然能够获取到组件的宽度和高度。


其他说明:

需要说明的是如果对Acitivty的布局加载绘制流程比较了解的同学应该知道,界面的显示过程经过了:测量位置,测量大小,绘制,三个操作流程。而我们获取组件的宽高就是获取组件的大小,所以我们获取的代码必须要在组件执行完测量大小之后,而无论是我们添加的onWindowFocusChanged方法,onPreDrawListener监听,已经onGlobalLayoutListener监听其实都是在组件完成了测量大小之后执行了,因此这时候我们能够正确的获取到组件的宽和高。


总结:

  • 该类库主要是介绍了三种我们在Activity的启动过程中获取组件宽高的方式;

  • 通过重写onWidnowFocusChanged方法获取组件宽高的方式,可能会回调几次,这点需要我们注意;

  • 项目保存地址:android-viewheight,欢迎star和follow


另外对github项目,开源项目解析感兴趣的同学可以参考我的:
github项目解析(一)–>上传android项目至github
github项目解析(二)–>将Android项目发布至JCenter代码库
github项目解析(三)–>android内存泄露监测之leakcanary
github项目解析(四)–>动态更改TextView的字体大小
github项目解析(五)–>android日志框架
github项目解析(六)–>自定义实现ButterKnife框架
github项目解析(七)–>防止按钮重复点击

github项目解析(八)-->Activity启动过程中获取组件宽高的三种方式

标签:

原文地址:http://blog.csdn.net/qq_23547831/article/details/51764304

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!