安卓项目实战之Activity启动过程中动态获取组件宽高的3种方式

前言

有时候我们需要在Activity启动的时候获取某一组件的宽或者是高用于动态的更改UI布局,但是这时候我们直接通过getWidth和getHeight方法获取是有问题的,如下:
我们在Activity的onCreate方法中调用如下的方法来获取组件的宽高:

/**
 * 在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);
    }

然而我们却发现日志中打印的结果宽和高均为0,
然后我们将上面的方法执行在某个按钮的点击事件之内,如下:

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

此时,我们可以看到Log日志中正常打印出了组件的宽和高。

原因分析

Activity界面的显示过程经过了:测量位置(onMeasure),测量大小(onLayout),绘制(onDraw)三个操作流程。而我们获取组件的宽高就是获取组件的大小,所以我们获取的代码必须要在组件执行完测量大小之后,这时候我们才能够正确的获取到组件的宽和高。

我们在Activity的onCreate和onResume方法调用textView.getHeight或者是textView.getWidth方法的时候,其组件并没有执行完绘制流程,因此此时获取到的组件的宽高都是默认的0,也就是无法获取组件的宽和高。

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

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

(一)为组件添加ViewTreeObserver.OnGlobalLayoutListener事件监听

/**
 * 为Activity的布局文件添加OnGlobalLayoutListener事件监听,onGlobalLayout内的代码会在View完成Layout过程后调用
 */
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);
           // 移除GlobalLayoutListener监听     
                   MainActivity.this.getWindow().getDecorView().getViewTreeObserver().removeOnGlobalLayoutListener(this);
            }
        });
    }

这里的onGlobalLayout方法会在Activity的组件执行完onLayout方法之后执行,这里的onLayout方法主要用于计算组件的宽高操作,这样当我们计算完组件的宽高之后再执行获取组件的宽高操作,自然能够获取到组件的宽度和高度。

(二)为组件添加ViewTreeObserver.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);
                // 移除OnPreDrawListener事件监听
                MainActivity.this.getWindow().getDecorView().getViewTreeObserver().removeOnPreDrawListener(this);
                return true;
            }
        });
    }

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

(三)使用View.post方法获取组件的宽高

这里的view的post方法底层使用的是Android的异步消息机制,runnable对象中的方法会在View的measure、layout等事件后触发,所以这时候也可以获取组件的宽高。

/**
 * 使用View的post方法获取组件的宽度和高度
 */
private void initViewHandler() {
        titleText.post(new Runnable() {
            @Override
            public void run() {
                int width = titleText.getWidth();
                int height = titleText.getHeight();

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

转载自:https://blog.csdn.net/qq_23547831/article/details/51764304 有删改。

猜你喜欢

转载自blog.csdn.net/gpf1320253667/article/details/83957858
今日推荐