問題原因:view 從GONE 切換為Visible之后 會開啟異步消息通知view重繪蔬螟。所以此時立即獲取widht 與 measuredWidth 都是0
解決方法:
//xml 中我們設(shè)置view visible= GONE
view.setVisibility(View.VISIBLE);
//在消息隊列尾部 追加一個消息,setVisibility 這條消息結(jié)束后調(diào)用
view.post(new Runnable(){
view.getMeasuredWidth();
view.getWidth();
});
針對問題 源碼分析:
- 1.查看GONE
view.setVisibility()>setFlags()
/* Check if the GONE bit has changed */
if ((changed & GONE) != 0) {
needGlobalAttributesUpdate(false);
requestLayout();
...
}
- 查看 view.requestLayout()
public void requestLayout() {
···
//獲取viewRootIml.并調(diào)用requestLayoutDuringLayout(),待更新的view集合
ViewRootImpl viewRoot = getViewRootImpl();
if (viewRoot != null && viewRoot.isInLayout()) {
if (!viewRoot.requestLayoutDuringLayout(this)) {
return;
}
}
//向上傳遞
if (mParent != null && !mParent.isLayoutRequested()) {
mParent.requestLayout();
}
···
}
- view.requestLayout最終都是由 ViewRootImpl.requestLayout()來負責調(diào)度消息罪帖,在消息執(zhí)行線程中最終調(diào)用促煮,Measure,Layout整袁,Draw三個方法菠齿。
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
void scheduleTraversals() {
···
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
···
}
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
void doTraversal() {
···
performTraversals();
···
}
private void performTraversals() {
···
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
//內(nèi)執(zhí)行 mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
performLayout(lp, desiredWindowWidth, desiredWindowHeight);
//內(nèi)執(zhí)行 host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight()); host及mView
performDraw();
//內(nèi)執(zhí)行 drawSoftware()>mView.draw(canvas);
···
}
總結(jié):View從GONE切為VISIBLE后會 進行重繪。而重繪 與 立即獲取view 寬高的代碼實際上是 無時序的坐昙,這就解釋了偶爾能獲取偶爾不能绳匀。還是要看手機性能?
END
感謝以下博客分析
Android窗口機制(四)ViewRootImpl與View和WindowManager