Android涓璙iew缁樺埗娴佺▼鍒嗘瀽
鍒涘缓Window
鍦ˋctivity鐨刟ttach鏂规硶涓€氳繃璋冪敤PolicyManager.makeNewWindo鍒涘缓Window,灏嗕竴涓猇iew add鍒癢indowManager鏃讹紝WindowManagerImpl鍒涘缓涓€涓猇iewRoot鏉ョ鐞嗚绐楀彛鐨勬牴View銆傚苟閫氳繃ViewRoot.setView鏂规硶鎶婅View浼犵粰ViewRoot銆?/span>
final void attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token, int ident, Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, NonConfigurationInstances lastNonConfigurationInstances, Configuration config) { attachBaseContext(context); mFragments.attachActivity(this, mContainer, null); mWindow = PolicyManager.makeNewWindow(this); mWindow.setCallback(this); mWindow.getLayoutInflater().setPrivateFactory(this);
鍒涘缓DecorView
DecorView涓烘暣涓猈indow鐣岄潰鐨勬渶椤跺眰View銆?br>
Activity涓殑Window瀵硅薄甯垜浠垱寤轰簡涓€涓狿honeWindow鍐呴儴绫籇ecorView锛堢埗绫讳负FrameLayout锛夌獥鍙i《灞傝鍥撅紝鐒跺悗閫氳繃LayoutInflater灏唜ml鍐呭甯冨眬瑙f瀽鎴怴iew鏍戝舰缁撴瀯娣诲姞鍒癉ecorView椤跺眰瑙嗗浘涓璱d涓篶ontent鐨凢rameLayout鐖跺鍣ㄤ笂闈€侫ctivity鐨刢ontent鍐呭甯冨眬鏈€缁堜細娣诲姞鍒癉ecorView绐楀彛椤跺眰瑙嗗浘涓婇潰銆?/span>
protected boolean initializePanelDecor(PanelFeatureState st) { st.decorView = new DecorView(getContext(), st.featureId); st.gravity = Gravity.CENTER | Gravity.BOTTOM; st.setStyle(getContext()); return true; }
鍒涘缓ViewRoot骞跺叧鑱擵iew
WindowManagerImpl淇濆瓨DecorView鍒癿Views锛屽垱寤哄搴旂殑ViewRoot锛?br>
ViewRoot鐢ㄤ簬绠$悊绐楀彛鐨勬牴View锛屽苟鍜実lobal window manger杩涜浜や簰銆俈iewRoot涓湁涓€涓猲ested class锛?W锛學鏄竴涓狟inder瀛愮被锛岀敤浜庢帴鏀秅lobal window manager鐨勫悇绉嶆秷鎭紝 濡傛寜閿秷鎭紝 瑙︽懜娑堟伅绛夈€?ViewRoot鏈変竴涓猈绫诲瀷鐨勬垚鍛榤Window锛孷iewRoot鍦–onstructor涓垱寤轰竴涓猈鐨刬nstance骞惰祴鍊肩粰mWindow銆?ViewRoot鏄疕andler鐨勫瓙绫伙紝 W浼氶€氳繃Looper鎶婃秷鎭紶閫掔粰ViewRoot銆?ViewRoot鍦╯etView鏂规硶涓妸mWindow浼犵粰sWindowSession銆?br>
public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) { if (view == null) { throw new IllegalArgumentException("view must not be null"); } if (display == null) { throw new IllegalArgumentException("display must not be null"); } if (!(params instanceof WindowManager.LayoutParams)) { throw new IllegalArgumentException("Params must be WindowManager.LayoutParams"); } final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params; if (parentWindow != null) { parentWindow.adjustLayoutParamsForSubWindow(wparams); } ViewRootImpl root; View panelParentView = null; synchronized (mLock) { // Start watching for system property changes. if (mSystemPropertyUpdater == null) { mSystemPropertyUpdater = new Runnable() { @Override public void run() { synchronized (mLock) { for (ViewRootImpl viewRoot : mRoots) { viewRoot.loadSystemProperties(); } } } }; SystemProperties.addChangeCallback(mSystemPropertyUpdater); } int index = findViewLocked(view, false); if (index >= 0) { throw new IllegalStateException("View " + view + " has already been added to the window manager."); } // If this is a panel window, then find the window it is being // attached to for future reference. if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW && wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) { final int count = mViews != null ? mViews.length : 0; for (int i=0; i<count; i++) { if (mRoots[i].mWindow.asBinder() == wparams.token) { panelParentView = mViews[i]; } } } root = new ViewRootImpl(view.getContext(), display); view.setLayoutParams(wparams); if (mViews == null) { index = 1; mViews = new View[1]; mRoots = new ViewRootImpl[1]; mParams = new WindowManager.LayoutParams[1]; } else { index = mViews.length + 1; Object[] old = mViews; mViews = new View[index]; System.arraycopy(old, 0, mViews, 0, index-1); old = mRoots; mRoots = new ViewRootImpl[index]; System.arraycopy(old, 0, mRoots, 0, index-1); old = mParams; mParams = new WindowManager.LayoutParams[index]; System.arraycopy(old, 0, mParams, 0, index-1); } index--; mViews[index] = view; mRoots[index] = root; mParams[index] = wparams; } // do this last because it fires off messages to start doing things try { root.setView(view, wparams, panelParentView); } catch (RuntimeException e) { // BadTokenException or InvalidDisplayException, clean up. synchronized (mLock) { final int index = findViewLocked(view, false); if (index >= 0) { removeViewLocked(index, true); } } throw e; } }
ViewRoot鏄疓UI绠$悊绯荤粺涓嶨UI鍛堢幇绯荤粺涔嬮棿鐨勬ˉ姊侊紝闇€瑕佹敞鎰忓畠骞朵笉鏄竴涓猇iew绫诲瀷锛屻€?br> 瀹冪殑涓昏浣滅敤濡備笅锛?br> 1銆佸悜DecorView鍒嗗彂鏀跺埌鐨勭敤鎴峰彂璧风殑event浜嬩欢锛屽鎸夐敭锛岃Е灞忥紝杞ㄨ抗鐞冪瓑浜嬩欢锛?br> 2銆佷笌WindowManagerService浜や簰锛屽畬鎴愭暣涓狝ctivity鐨凣UI鐨勭粯鍒躲€?br>
View缁樺埗鍩烘湰娴佺▼
杩欓噷鍏堢粰鍑篈ndroid绯荤粺View鐨勭粯鍒舵祦绋嬶細渚濇鎵цView绫婚噷闈㈢殑濡備笅涓変釜鏂规硶锛?br> measure(int ,int) :娴嬮噺View鐨勫ぇ灏?br> layout(int ,int ,int ,int) 锛氳缃瓙View鐨勪綅缃?br> draw(Canvas) 锛氱粯鍒禫iew鍐呭鍒癈anvas鐢诲竷涓?br>
鏁翠釜View鏍戠殑缁樺浘娴佺▼鏄湪ViewRoot.java绫荤殑performTraversals()鍑芥暟灞曞紑鐨勶紝璇ュ嚱鏁板仛鐨勬墽琛岃繃绋嬪彲绠€鍗曟鍐典负鏍规嵁涔嬪墠璁剧疆鐨勭姸鎬侊紝鍒ゆ柇鏄惁闇€瑕侀噸鏂拌绠楄鍥惧ぇ灏?measure)銆佹槸鍚﹂噸鏂伴渶瑕佸畨缃鍥剧殑浣嶇疆(layout)銆佷互鍙婃槸鍚﹂渶瑕侀噸缁?(draw)
mesarue()娴嬮噺杩囩▼
涓昏浣滅敤锛氫负鏁翠釜View鏍戣绠楀疄闄呯殑澶у皬锛屽嵆璁剧疆瀹為檯鐨勯珮(mMeasuredHeight)鍜屽(mMeasureWidth)锛屾瘡涓猇iew鐨勬帶浠剁殑瀹為檯瀹介珮閮芥槸鐢辩埗瑙嗗浘鍜屾湰韬鍥惧喅瀹氱殑銆?br> 鍏蜂綋鐨勮皟鐢ㄥ涓嬶細
ViewRootImpl 鐨刾erformTraversals鏂规硶涓紝璋冪敤measureHierarchy锛岀劧鍚庤皟鐢╬erformMeasure
private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) { Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure"); try { mView.measure(childWidthMeasureSpec, childHeightMeasureSpec); } finally { Trace.traceEnd(Trace.TRACE_TAG_VIEW); } }ViewRoot鏍瑰璞″湴灞炴€View(鍏剁被鍨嬩竴鑸负ViewGroup绫诲瀷)璋冪敤measure()鏂规硶鍘昏绠梀iew鏍戠殑澶у皬锛屽洖璋?
View/ViewGroup瀵硅薄鐨刼nMeasure()鏂规硶锛岃鏂规硶瀹炵幇鐨勫姛鑳藉涓嬶細
1銆佽缃湰View瑙嗗浘鐨勬渶缁堝ぇ灏忥紝璇ュ姛鑳界殑瀹炵幇閫氳繃璋冪敤setMeasuredDimension()鏂规硶鍘昏缃疄闄呯殑楂? (mMeasuredHeight)鍜屽(mMeasureWidth)
2銆佸鏋滆View瀵硅薄鏄釜ViewGroup绫诲瀷锛岄渶瑕侀噸鍐檕nMeasure()鏂规硶锛屽鍏跺瓙瑙嗗浘杩涜閬嶅巻鐨刴easure()杩囩▼銆?br> 瀵规瘡涓瓙瑙嗗浘鐨刴easure()杩囩▼锛屾槸閫氳繃璋冪敤鐖剁被ViewGroup.java绫婚噷鐨刴easureChildWithMargins()鏂规硶鍘诲疄鐜帮紝璇ユ柟娉曞唴閮ㄥ彧鏄畝鍗曞湴璋冪敤浜哣iew瀵硅薄鐨刴easure()鏂规硶銆?br> 鏁翠釜measure璋冪敤娴佺▼灏辨槸涓爲褰㈢殑閫掑綊杩囩▼
measure()鏂规硶涓や釜鍙傛暟閮芥槸鐖禫iew浼犻€掕繃鏉ョ殑锛屼篃灏辨槸浠h〃浜嗙埗view鐨勮鏍笺€備粬鐢变袱閮ㄥ垎缁勬垚锛岄珮2浣嶈〃绀篗ODE锛屽畾涔夊湪MeasureSpec绫伙紙View鐨勫唴閮ㄧ被锛変腑锛屾湁涓夌绫诲瀷锛孧easureSpec.EXACTLY琛ㄧず纭畾澶у皬锛?MeasureSpec.AT_MOST琛ㄧず鏈€澶уぇ灏忥紝 MeasureSpec.UNSPECIFIED涓嶇‘瀹氥€備綆30浣嶈〃绀簊ize锛屼篃灏辨槸鐖禫iew鐨勫ぇ灏忋€傚浜庣郴缁焀indow绫荤殑DecorVIew瀵硅薄Mode涓€鑸兘涓篗easureSpec.EXACTLY 锛岃€宻ize鍒嗗埆瀵瑰簲灞忓箷瀹介珮銆傚浜庡瓙View鏉ヨ澶у皬鏄敱鐖禫iew鍜屽瓙View鍏卞悓鍐冲畾鐨勩€?/span>
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); }
protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) { boolean optical = isLayoutModeOptical(this); if (optical != isLayoutModeOptical(mParent)) { Insets insets = getOpticalInsets(); int opticalWidth = insets.left + insets.right; int opticalHeight = insets.top + insets.bottom; measuredWidth += optical ? opticalWidth : -opticalWidth; measuredHeight += optical ? opticalHeight : -opticalHeight; } mMeasuredWidth = measuredWidth; mMeasuredHeight = measuredHeight; mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET; }
layout甯冨眬杩囩▼
涓昏浣滅敤 锛氫负灏嗘暣涓牴鎹瓙瑙嗗浘鐨勫ぇ灏忎互鍙婂竷灞€鍙傛暟灏哣iew鏍戞斁鍒板悎閫傜殑浣嶇疆涓娿€?br> 鍏蜂綋鐨勮皟鐢ㄥ涓嬶細ViewRootImpl 鐨刾erformTraversals鏂规硶涓紝璋冪敤performLayout
private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth, int desiredWindowHeight) { mLayoutRequested = false; mScrollMayChange = true; mInLayout = true; final View host = mView; if (DEBUG_ORIENTATION || DEBUG_LAYOUT) { Log.v(TAG, "Laying out " + host + " to (" + host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")"); } Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout"); try { host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight()); mInLayout = false; int numViewsRequestingLayout = mLayoutRequesters.size(); if (numViewsRequestingLayout > 0) { // requestLayout() was called during layout. // If no layout-request flags are set on the requesting views, there is no problem. // If some requests are still pending, then we need to clear those flags and do // a full request/measure/layout pass to handle this situation. ArrayList<View> validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, false); if (validLayoutRequesters != null) { // Set this flag to indicate that any further requests are happening during // the second pass, which may result in posting those requests to the next // frame instead mHandlingLayoutInLayoutRequest = true; // Process fresh layout requests, then measure and layout int numValidRequests = validLayoutRequesters.size(); for (int i = 0; i < numValidRequests; ++i) { final View view = validLayoutRequesters.get(i); Log.w("View", "requestLayout() improperly called by " + view + " during layout: running second layout pass"); view.requestLayout(); } measureHierarchy(host, lp, mView.getContext().getResources(), desiredWindowWidth, desiredWindowHeight); mInLayout = true; host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight()); mHandlingLayoutInLayoutRequest = false; // Check the valid requests again, this time without checking/clearing the // layout flags, since requests happening during the second pass get noop'd validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, true); if (validLayoutRequesters != null) { final ArrayList<View> finalRequesters = validLayoutRequesters; // Post second-pass requests to the next frame getRunQueue().post(new Runnable() { @Override public void run() { int numValidRequests = finalRequesters.size(); for (int i = 0; i < numValidRequests; ++i) { final View view = finalRequesters.get(i); Log.w("View", "requestLayout() improperly called by " + view + " during second layout pass: posting in next frame"); view.requestLayout(); } } }); } } } } finally { Trace.traceEnd(Trace.TRACE_TAG_VIEW); } mInLayout = false; }host.layout()寮€濮媀iew鏍戠殑甯冨眬锛岀户鑰屽洖璋冪粰View/ViewGroup绫讳腑鐨刲ayout()鏂规硶銆傚叿浣撴祦绋嬪涓?
1 銆乴ayout鏂规硶浼氳缃View瑙嗗浘浣嶄簬鐖惰鍥剧殑鍧愭爣杞达紝鍗砿Left锛宮Top锛宮Left锛宮Bottom(璋冪敤setFrame()鍑芥暟鍘诲疄鐜?锛屾帴涓嬫潵鍥炶皟onLayout()鏂规硶(濡傛灉璇iew鏄疺iewGroup瀵硅薄锛岄渶瑕佸疄鐜拌鏂规硶锛屽姣忎釜瀛愯鍥捐繘琛屽竷灞€)銆?
2銆佸鏋滆View鏄釜ViewGroup绫诲瀷锛岄渶瑕侀亶鍘嗘瘡涓瓙瑙嗗浘chiildView锛岃皟鐢ㄨ瀛愯鍥剧殑layout()鏂规硶鍘昏缃畠鐨勫潗鏍囧€笺€?
protected void onLayout(boolean changed, int left, int top, int right, int bottom) { }
public void layout(int l, int t, int r, int b) { int oldL = mLeft; int oldT = mTop; int oldB = mBottom; int oldR = mRight; boolean changed = isLayoutModeOptical(mParent) ? setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b); if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) { onLayout(changed, l, t, r, b); mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED; ListenerInfo li = mListenerInfo; if (li != null && li.mOnLayoutChangeListeners != null) { ArrayList<OnLayoutChangeListener> listenersCopy = (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone(); int numListeners = listenersCopy.size(); for (int i = 0; i < numListeners; ++i) { listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB); } } } mPrivateFlags &= ~PFLAG_FORCE_LAYOUT; }
draw()缁樺浘杩囩▼
ViewRootImpl 鐨刾erformTraversals鏂规硶涓紝璋冪敤浜唌View鐨刣raw鏂规硶 mView.draw()寮€濮嬬粯鍒讹紝draw()鏂规硶瀹炵幇鐨勫姛鑳藉涓嬶細1 銆佺粯鍒惰View鐨勮儗鏅?br> 2 銆佷负鏄剧ず娓愬彉妗嗗仛涓€浜涘噯澶囨搷浣?
3銆佽皟鐢╫nDraw()鏂规硶缁樺埗瑙嗗浘鏈韩 (姣忎釜View閮介渶瑕侀噸杞借鏂规硶锛孷iewGroup涓嶉渶瑕佸疄鐜拌鏂规硶)
4銆佽皟鐢╠ispatchDraw ()鏂规硶缁樺埗瀛愯鍥?濡傛灉璇iew绫诲瀷涓嶄负ViewGroup锛屽嵆涓嶅寘鍚瓙瑙嗗浘锛屼笉闇€瑕侀噸杞借鏂规硶)
鍊煎緱璇存槑鐨勬槸锛孷iewGroup绫诲凡缁忎负鎴戜滑閲嶅啓浜哾ispatchDraw ()鐨勫姛鑳藉疄鐜帮紝搴旂敤绋嬪簭涓€鑸笉闇€瑕侀噸鍐欒鏂规硶锛屼絾鍙互閲嶈浇鐖剁被鍑芥暟瀹炵幇鍏蜂綋鐨勫姛鑳姐€?br> dispatchDraw()鏂规硶鍐呴儴浼氶亶鍘嗘瘡涓瓙瑙嗗浘锛岃皟鐢╠rawChild()鍘婚噸鏂板洖璋冩瘡涓瓙瑙嗗浘鐨刣raw()鏂规硶銆?br> 5銆佺粯鍒舵粴鍔ㄦ潯
鍒锋柊瑙嗗浘
Android涓疄鐜皏iew鐨勬洿鏂版湁涓や釜鏂规硶锛屼竴涓槸invalidate锛屽彟涓€涓槸postInvalidate锛屽叾涓墠鑰呮槸鍦║I绾跨▼鑷韩涓娇鐢紝鑰屽悗鑰呭湪闈濽I绾跨▼涓娇鐢ㄣ€?nbsp;requestLayout()鏂规硶 锛氫細瀵艰嚧璋冪敤measure()杩囩▼ 鍜?layout()杩囩▼ 銆?br> 璇存槑锛氬彧鏄View鏍戦噸鏂板竷灞€layout杩囩▼鍖呮嫭measure()鍜宭ayout()杩囩▼锛屼笉浼氳皟鐢╠raw()杩囩▼锛屼絾涓嶄細閲嶆柊缁樺埗
浠讳綍瑙嗗浘鍖呮嫭璇ヨ皟鐢ㄨ€呮湰韬€?br>
涓€鑸紩璧穒nvalidate()鎿嶄綔鐨勫嚱鏁板涓嬶細
1銆佺洿鎺ヨ皟鐢╥nvalidate()鏂规硶锛岃姹傞噸鏂癲raw()锛屼絾鍙細缁樺埗璋冪敤鑰呮湰韬€?br> 2銆乻etSelection()鏂规硶 锛氳姹傞噸鏂癲raw()锛屼絾鍙細缁樺埗璋冪敤鑰呮湰韬€?br> 3銆乻etVisibility()鏂规硶 锛?褰揤iew鍙鐘舵€佸湪INVISIBLE杞崲VISIBLE鏃讹紝浼氶棿鎺ヨ皟鐢╥nvalidate()鏂规硶锛岀户鑰岀粯鍒惰View銆?br> 4 銆乻etEnabled()鏂规硶 锛?璇锋眰閲嶆柊draw()锛屼絾涓嶄細閲嶆柊缁樺埗浠讳綍瑙嗗浘鍖呮嫭璇ヨ皟鐢ㄨ€呮湰韬€?br>
鍐呭鍙傝€冩簮鐮侊紝鍊熼壌浜嗙綉涓婄殑涓€浜涘垎鏋愩€?/span>
娆㈣繋鎵弿浜岀淮鐮侊紝鍏虫敞鍏紬璐﹀彿
更多相关文章
- 代码中设置drawableleft
- android 3.0 隐藏 系统标题栏
- Android开发中activity切换动画的实现
- Android(安卓)学习 笔记_05. 文件下载
- Android中直播视频技术探究之—摄像头Camera视频源数据采集解析
- 技术博客汇总
- android 2.3 wifi (一)
- AndRoid Notification的清空和修改
- Android中的Chronometer