美文网首页Android自定义View
何时可以获取mTextViewHeight高度

何时可以获取mTextViewHeight高度

作者: 世道无情 | 来源:发表于2018-03-26 10:20 被阅读1次

    1. 说明


    下边我们看一个小示例,看下什么时候可以获取到mTextViewHeight高度,什么时候不能获取到。

    2. 代码如下

    public class MainActivity extends AppCompatActivity {
    
        private TextView text_view;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
    
            // 下边这个获取不到view的高度,因为参数3是null,即就是父布局是null,说明你还没有把activity_main添加到父布局中,所以不能获取到宽高
            View view = View.inflate(this, R.layout.activity_main, null);
    
    
            // 这个可以获取到宽高,因为 参数3ViewGroup表示父布局,下边代码就表示,你已经把activity_main布局添加到父布局中了,所以可以获取到宽高
    //        View view = View.inflate(this, R.layout.activity_main, ViewGroup);
    
    
            text_view = (TextView) findViewById(R.id.text_view);
            Log.e("TAG" , "height1 -> " + text_view.getMeasuredHeight()) ;   // 0
    
            text_view.post(new Runnable() {
                @Override
                public void run() {
                    Log.e("TAG" , "height2 -> " + text_view.getMeasuredHeight()) ;  // 高度:51
                }
            }) ;
        }
    
    
        @Override
        protected void onResume() {
            super.onResume();
            Log.e("TAG" , "height3 -> " + text_view.getMeasuredHeight()) ;  // 0
        }
    }
    

    View view = View.inflate(this, R.layout.activity_main, null)为什么获取不到高度?

    参数3表示父布局,而这里的参数3是null,表示没有把activity_main添加到父布局中,所以不能获取到宽高;

    View view = View.inflate(this, R.layout.activity_main, ViewGroup)为什么可以获取到高度?

    参数3表示父布局,这里的参数3是 ViewGroup,表示父布局,这里为了形象表示就直接把父布局写成了ViewGroup,其实只要是父布局就行。这里就表示把activity_main添加到父布局中,所以可以获取到高度;

    分析其余3个mTextViewHeight的高度:

    由以上可知:

    03-19 21:29:23.491 18696-18696/? E/TAG: height1 -> 0
    03-19 21:29:23.492 18696-18696/? E/TAG: height3 -> 0
    03-19 21:29:23.591 18696-18696/? E/TAG: height2 -> 51
    

    height1 = 0;height3 = 0 ;height2 = 51(高度)
    分析原因:
    我们需要知道,我们在onCreate()方法中只是调用了setContentView(),也需要知道setContentView()到底干了什么?
    在PhoneWindow中,setContentView只是new DecorView()

    之所以能够拿到控件的宽高,是因为调用了onMeasure()方法,而在我们之前写的那些自定义View效果的时候,其实都是在 onMeasure()方法中获取到宽高后,都会重新调用setMeasuredDimension(width , height);
    setContentView 只是创建DecorView,并且把我们的布局加载进DecorView,并没有调用onMeasure()方法;

    分析PhoneWindow的源码如下:

    @Override
        public void setContentView(int layoutResID) {
            // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
            // decor, when theme attributes and the like are crystalized. Do not check the feature
            // before this happens.
            if (mContentParent == null) {
                installDecor();
            } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
                mContentParent.removeAllViews();
            }
    
            if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
                final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                        getContext());
                transitionTo(newScene);
            } else {
                mLayoutInflater.inflate(layoutResID, mContentParent);
            }
            mContentParent.requestApplyInsets();
            final Callback cb = getCallback();
            if (cb != null && !isDestroyed()) {
                cb.onContentChanged();
            }
            mContentParentExplicitlySet = true;
        }
    

    只要installDecor()方法执行完,就会形成这样一个局面:


    图片.png
    onCreate()中为什么获取不到 mTextViewHeight 高度?

    因为在PhoneWindow中,setContentView()只是new DecorView(),然后把我们的布局加载到了DecorView(),其余什么都没做,也并没有调用onMeasure()方法,所以在onCreate()方法中不能获取到TextView的宽高;


    onResume()中为什么也获取不到 mTextViewHeight 高度?

    这个其实就涉及到Activity的启动流程的分析,通过下边对Activity启动流程的分析,即就是分析 ActivityThread源码,可以知道:
    Activity的启动流程是:
    先调用handleLaunchActivity(),在这个方法中调用performLaunchActivity(),在performLaunchActivity()中会调用onCreate() ->
    然后调用handleResumeActivity(),在这个方法中调用performResumeActivity() ->
    然后调用Activity的onResume() ->
    然后调用 wm.addView(decor , 1) ,这个时候才开始把我们的DecorView 加载到 WindowManager中,View的绘制流程在这个时候才刚刚开始,才开始onMeasure()(测量)、onLayout()(摆放)、onDraw()(绘制)draw()自己、draw()孩子;

    所以说View的绘制流程是在onResume()方法之后才开始,所以说在onResume()方法中也是不能获取 mTextViewHeight高度的,必须要等调用完onResume()之后,才可以获取宽高的。

    下边的text_view.post为什么可以获取到宽高?
    text_view.post(new Runnable() {
                @Override
                public void run() {
                    Log.e("TAG" , "height2 -> " + text_view.getMeasuredHeight()) ;  // 高度:51
                }
            }) ;
    

    源码分析:
    View中源码:

    public boolean post(Runnable action) {
            final AttachInfo attachInfo = mAttachInfo;
            if (attachInfo != null) {
                return attachInfo.mHandler.post(action);
            }
            getRunQueue().post(action);
            return true;
        }
    

    View中源码:

    public void post(Runnable action) {
            postDelayed(action, 0);
        }
    
        public void postDelayed(Runnable action, long delayMillis) {
            final HandlerAction handlerAction = new HandlerAction(action, delayMillis);
    
            synchronized (this) {
                if (mActions == null) {
                    mActions = new HandlerAction[4];
                }
                mActions = GrowingArrayUtils.append(mActions, mCount, handlerAction);
                mCount++;
            }
        }
    

    View中源码:

        /**
         * @param info the {@link android.view.View.AttachInfo} to associated with
         *        this view
         */
        void dispatchAttachedToWindow(AttachInfo info, int visibility) {
            mAttachInfo = info;
            if (mOverlay != null) {
                mOverlay.getOverlayView().dispatchAttachedToWindow(info, visibility);
            }
            mWindowAttachCount++;
            // We will need to evaluate the drawable state at least once.
            mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY;
            if (mFloatingTreeObserver != null) {
                info.mTreeObserver.merge(mFloatingTreeObserver);
                mFloatingTreeObserver = null;
            }
            // Transfer all pending runnables.
            if (mRunQueue != null) {
                mRunQueue.executeActions(info.mHandler);
                mRunQueue = null;
            }
            performCollectViewAttributes(mAttachInfo, visibility);
            onAttachedToWindow();
        }
    

    HandlerActionQueue源码:

    public void executeActions(Handler handler) {
            synchronized (this) {
                final HandlerAction[] actions = mActions;
                for (int i = 0, count = mCount; i < count; i++) {
                    final HandlerAction handlerAction = actions[i];
                    handler.postDelayed(handlerAction.action, handlerAction.delay);
                }
    
                mActions = null;
                mCount = 0;
            }
        }
    

    这里只是把Runnable保存到Queue中,什么都没干,run()方法会在dispatchAttachedToWindow()方法会在测量完毕然后调用executeActions()方法,即就是onMeasure()方法之后调用executeActions()方法,所以只要一调用text_view.post(new Runnable()) ,就马上可以获取宽高。

    相关文章

      网友评论

        本文标题:何时可以获取mTextViewHeight高度

        本文链接:https://www.haomeiwen.com/subject/ncafcftx.html