View获取宽高的方式及View.post为什么可以拿到View的宽高

1. view.post(Runnable)

public boolean post(Runnable action) {
        final AttachInfo attachInfo = mAttachInfo;
        //dispatchAttachedToWindow里赋值mAttachInfo,将view添加到window中
        if (attachInfo != null) {
            return attachInfo.mHandler.post(action);
        }

        // Postpone the runnable until we know on which thread it needs to run.
        // Assume that the runnable will be successfully placed after attach.
        getRunQueue().post(action);
        return true;
    }
void dispatchAttachedToWindow(AttachInfo info, int visibility) {
        mAttachInfo = info;
        //注意此处,view attach到Window后,会执行缓存的Runnable
		if (mRunQueue != null) {
            mRunQueue.executeActions(info.mHandler);
            mRunQueue = null;
        }
 }

2.当mAttachInfo为null时,会将Runnable进行缓存 getRunQueue()

public class HandlerActionQueue {
	// HandlerAction封装Runnable和delayTime
    private HandlerAction[] mActions;
    private int mCount;

    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) {
            // 此处大小为4,支持增长的的数组
                mActions = new HandlerAction[4];
            }
            mActions = GrowingArrayUtils.append(mActions, mCount, handlerAction);
            mCount++;
        }
    }
    //缓存的Runnable的执行
    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;
        }
    }
 }

3.dispatchAttachedToWindow(AttachInfo)掉用

public final class ViewRootImpl implements ViewParent,
        View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {
        final ViewRootHandler mHandler = new ViewRootHandler();
        
    public ViewRootImpl(Context context, Display display) {
		mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this,context);
	}
	private void performTraversals() {
		//host即为ViewRootImpl中的setView中的view
		host.dispatchAttachedToWindow(mAttachInfo, 0);
	}
}

4.都在performTraversals中怎么能保证一定是在View的绘制流程完成之后才去执行dispatchAttachedToWindow?

View的绘制操作其实也是一个Runnable对象,所以必须会执行完绘制这个Runnable后才会执行dispatchAttachedToWindow中添加的Runnable(因为dispatchAttachedToWindow是在绘制这个Runnable中执行的)

dispatchAttachedToWindow方法中会执行public void executeActions(Handler handler) {
//此处将缓存的Runnable的重新通过handler发送到MessageQueue中
}

5.获取View 宽高的方式

  1. onWindowFocusChanged方法
    Activity的窗口得到焦点时,View已经初始化完成,此时获取到的View的宽高是准确的
  2. View.post()来实现
    通过post可以将一个Runnable放置到消息队列中,等到Looper调用此Runnable时,View已经初始化完成。
  3. ViewTreeObserver的OnGlobalLayoutListener回调
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_get_height);
    textView = findViewById(R.id.tv);

    final ViewTreeObserver viewTreeObserver = textView.getViewTreeObserver();
    viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            viewTreeObserver.removeOnGlobalLayoutListener(this);
            Log.d("tv_width", "" + textView.getWidth());
            Log.d("tv_height", "" + textView.getHeight());
        }
    });
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值