Android 簡單解讀了ViewStub的代碼和注釋,其他的不想多說

ViewStub應(yīng)用的場景比較少兴泥,以前用過幾次工育。時(shí)間一長又忘記了,很是苦惱搓彻。

于是把ViewStub的源碼過了一遍如绸,詳細(xì)說明了每行代碼的含義和目的嘱朽,翻譯了源碼中的注釋。

自己動眼看看吧怔接,你懂得搪泳。再多說就畫蛇添足了。

道士扼脐,請:



package?android.view;

import?android.annotation.IdRes;

import?android.annotation.LayoutRes;

import?android.content.Context;

import?android.content.res.TypedArray;

import?android.graphics.Canvas;

import?android.util.AttributeSet;

import?android.widget.RemoteViews.RemoteView;

import?com.android.internal.R;

import?java.lang.ref.WeakReference;

/**

*?ViewStub是一個(gè)不可見的岸军,0?size的View,它可以在運(yùn)行時(shí)加載一個(gè)布局瓦侮,即懶加載艰赞。

*?當(dāng)ViewStub設(shè)置為可見(visible),或者調(diào)用了ViewStub的inflate()方法時(shí)肚吏,

*?其android:layout屬性所關(guān)聯(lián)的layout文件才會被加載和生成view對象方妖。

*?此時(shí),當(dāng)前ViewStub所在的位置會被其加載的子布局霸占替換须喂;并且當(dāng)前ViewStub對象會從其父容器中移除吁断。

*?這也就是為什么ViewStub只能inflate()一次的原因。inflate一次后坞生,ViewStub對象都沒有了仔役,還怎么inflate()第二次?

*

*?下面這句話注意了:

*?被ViewStub加載的View是己,替換了ViewStub的存在又兵,當(dāng)然是添加到了ViewStub的父容器中,即原ViewStub的爸爸成了ViewStub加載的View的爸爸卒废。

*?并且在ViewStub上設(shè)置的layout參數(shù)沛厨,會轉(zhuǎn)移給ViewStub加載的View身上。

*?同樣的摔认,你也可以在ViewStub的android:inflatedId屬性上設(shè)置id逆皮,當(dāng)其加載布局時(shí),會直接把id重新設(shè)置到加載的布局根上参袱。

*?如果沒設(shè)置android:inflatedId屬性电谣,那待加載的布局根還是用以前的id屬性,沒有拉到抹蚀。

*

*?舉個(gè)栗子:

*

*

*

*android:inflatedId="@+id/這個(gè)id會在運(yùn)行時(shí)加載中剿牺,設(shè)置到下面aaaaa布局的根屬性上"

*android:layout="@layout/aaaaa,即稍后會加載且替換當(dāng)前ViewStub的布局"

*android:layout_width="120dp"

*android:layout_height="40dp"/>

*

*

*?如上面的代碼环壤,當(dāng)aaaaa布局加載后晒来,你可以使用inflatedId屬性值(即id值)找到aaaaa對象

*?或者用aaaaa內(nèi)部的根布局id找到aaaaa對象。

*

*?下面ViewStub的代碼:

*

*?????ViewStubstub=?(ViewStub)?findViewById(R.id.viewStub的id);

*?????Viewinflated=stub.inflate();

*

*

*?當(dāng)inflate()方法被調(diào)用后郑现,當(dāng)前的ViewStub將會被加載的布局替換湃崩,并且返回值為加載的布局對象荧降。

*

*?注意下面兩個(gè)屬性的定義:

*?@attr?ref?android.R.styleable#ViewStub_inflatedId?給待加載的布局設(shè)置id,也可以不設(shè)置竹习,用布局內(nèi)部設(shè)置的id值

*?@attr?ref?android.R.styleable#ViewStub_layout?待加載的布局

*/

@RemoteView

public?final?class?ViewStub?extends?View?{

private?int?mInflatedId;

private?int?mLayoutResource;

private?WeakReferencemInflatedViewRef;

private?LayoutInflater?mInflater;

private?OnInflateListener?mInflateListener;

public?ViewStub(Context?context)?{

this(context,?0);

}

/**

*?使用給定的待加載的布局文件創(chuàng)建一個(gè)ViewStub對象誊抛。

*

*?@param?context?The?application's?environment.

*?@param?layoutResource?The?reference?to?a?layout?resource?that?will?be?inflated.

*/

public?ViewStub(Context?context,?@LayoutRes?int?layoutResource)?{

this(context,?null);

mLayoutResource=layoutResource;

}

public?ViewStub(Context?context,?AttributeSet?attrs)?{

this(context,?attrs,?0);

}

public?ViewStub(Context?context,?AttributeSet?attrs,?int?defStyleAttr)?{

this(context,?attrs,?defStyleAttr,?0);

}

public?ViewStub(Context?context,?AttributeSet?attrs,?int?defStyleAttr,?int?defStyleRes)?{

super(context);

final?TypedArraya=context.obtainStyledAttributes(attrs,

R.styleable.ViewStub,?defStyleAttr,?defStyleRes);

mInflatedId=a.getResourceId(R.styleable.ViewStub_inflatedId,?NO_ID);

mLayoutResource=a.getResourceId(R.styleable.ViewStub_layout,?0);

mID=a.getResourceId(R.styleable.ViewStub_id,?NO_ID);

a.recycle();

//注意,ViewStub永遠(yuǎn)是隱藏的整陌,不會展示任何UI信息拗窃,且不占位

setVisibility(GONE);

setWillNotDraw(true);

}

/**

*?返回待加載的布局的id,如果沒有設(shè)置(即保持布局內(nèi)部根屬性上設(shè)置的id)則返回NO_ID

*

*?@return?A?positive?integer?used?to?identify?the?inflated?view?or

*?????????{@link?#NO_ID}?if?the?inflated?view?should?keep?its?id.

*

*?@see?#setInflatedId(int)

*?@attr?ref?android.R.styleable#ViewStub_inflatedId

*/

@IdRes

public?int?getInflatedId()?{

return?mInflatedId;

}

/**

*?Defines?the?id?taken?by?the?inflated?view.?If?the?inflated?id?is

*?{@link?View#NO_ID},?the?inflated?view?keeps?its?original?id.

*

*?@param?inflatedId?A?positive?integer?used?to?identify?the?inflated?view?or

*???????????????????{@link?#NO_ID}?if?the?inflated?view?should?keep?its?id.

*

*?@see?#getInflatedId()

*?@attr?ref?android.R.styleable#ViewStub_inflatedId

*/

@android.view.RemotableViewMethod

public?void?setInflatedId(@IdRes?int?inflatedId)?{

mInflatedId=inflatedId;

}

/**

*?獲取待加載的布局資源

*

*?@return?The?layout?resource?identifier?used?to?inflate?the?new?View.

*

*?@see?#setLayoutResource(int)

*?@see?#setVisibility(int)

*?@see?#inflate()

*?@attr?ref?android.R.styleable#ViewStub_layout

*/

@LayoutRes

public?int?getLayoutResource()?{

return?mLayoutResource;

}

/**

*?代碼形式設(shè)置待加載的布局資源

*

*?@param?layoutResource?A?valid?layout?resource?identifier?(different?from?0.)

*

*?@see?#getLayoutResource()

*?@see?#setVisibility(int)

*?@see?#inflate()

*?@attr?ref?android.R.styleable#ViewStub_layout

*/

@android.view.RemotableViewMethod

public?void?setLayoutResource(@LayoutRes?int?layoutResource)?{

mLayoutResource=layoutResource;

}

/**

*?Set?{@link?LayoutInflater}?to?use?in?{@link?#inflate()},?or?{@code?null}

*?to?use?the?default.

*/

public?void?setLayoutInflater(LayoutInflater?inflater)?{

mInflater=inflater;

}

/**

*?Get?current?{@link?LayoutInflater}?used?in?{@link?#inflate()}.

*/

public?LayoutInflater?getLayoutInflater()?{

return?mInflater;

}

@Override

protected?void?onMeasure(int?widthMeasureSpec,?int?heightMeasureSpec)?{

//設(shè)置當(dāng)前ViewStub的寬高都為0泌辫,即不可見了

setMeasuredDimension(0,?0);

}

@Override

public?void?draw(Canvas?canvas)?{

//無繪制

}

@Override

protected?void?dispatchDraw(Canvas?canvas)?{

//也不調(diào)用子孩子的繪制

}

/**

*?When?visibility?is?set?to?{@link?#VISIBLE}?or?{@link?#INVISIBLE},

*?{@link?#inflate()}?is?invoked?and?this?StubbedView?is?replaced?in?its?parent

*?by?the?inflated?layout?resource.?After?that?calls?to?this?function?are?passed

*?through?to?the?inflated?view.

*

*?@param?visibility?One?of?{@link?#VISIBLE},?{@link?#INVISIBLE},?or?{@link?#GONE}.

*

*?@see?#inflate()

*/

@Override

@android.view.RemotableViewMethod

public?void?setVisibility(int?visibility)?{

//判斷mInflatedViewRef對象是否為null随夸,即判斷是否調(diào)用過下面的inflate()函數(shù)

if?(mInflatedViewRef?!=?null)?{

//已經(jīng)加載過view,直接獲取震放。

Viewview=mInflatedViewRef.get();

if?(view?!=?null)?{

//直接設(shè)置view的可見性即可宾毒,此時(shí)跟ViewStub沒什么關(guān)系了。ViewStub已經(jīng)從父容器中移除了

view.setVisibility(visibility);

}?else?{

throw?new?IllegalStateException("setVisibility?called?on?un-referenced?view");

}

}?else?{

super.setVisibility(visibility);

if?(visibility==?VISIBLE?||visibility==?INVISIBLE)?{

//如果設(shè)置了ViewStub為可見殿遂,或者占位的話诈铛,則觸發(fā)下面的inflate()函數(shù)

//注意,有了mInflatedViewRef的判斷墨礁,inflate()函數(shù)是不會調(diào)用第二次的幢竹。

//當(dāng)調(diào)用了一次inflate()函數(shù)后,當(dāng)前ViewStub對象沒有父容器了恩静,然而在調(diào)用inflate()會報(bào)異常的焕毫。

inflate();

}

}

}

/**

*?Inflates?the?layout?resource?identified?by?{@link?#getLayoutResource()}

*?and?replaces?this?StubbedView?in?its?parent?by?the?inflated?layout?resource.

*

*?@return?The?inflated?layout?resource.

*

*/

public?View?inflate()?{

//獲取到當(dāng)前ViewStub對象的父容器

final?ViewParentviewParent=getParent();

//判斷父容器是否為null

if?(viewParent?!=?null?&&?viewParent?instanceof?ViewGroup)?{

//判斷是否給ViewStub指定了android:layout=""屬性,即待加載的布局

if?(mLayoutResource?!=?0)?{

final?ViewGroupparent=?(ViewGroup)?viewParent;

final?LayoutInflater?factory;

if?(mInflater?!=?null)?{

factory=mInflater;

}?else?{

factory=LayoutInflater.from(mContext);

}

//加載指定的資源文件驶乾,注意三個(gè)參數(shù)的含義

//可參考:http://blog.csdn.net/fesdgasdgasdg/article/details/72870280

final?Viewview=factory.inflate(mLayoutResource,?parent,

false);

//如果設(shè)置了android:inflatedId=""屬性值邑飒,則把設(shè)置的id值賦給被加載的布局

if?(mInflatedId?!=?NO_ID)?{

view.setId(mInflatedId);

}

//記錄當(dāng)前ViiewStub在父容器中的位置

final?intindex=parent.indexOfChild(this);

//把當(dāng)前ViewStub對象從父容器中移除

parent.removeViewInLayout(this);

//獲取當(dāng)前ViewStub的layoutParams參數(shù)

final?ViewGroup.LayoutParamslayoutParams=getLayoutParams();

if?(layoutParams?!=?null)?{

//連同ViewStub的layoutParams參數(shù)一起,把加載獲得到的View設(shè)置到父容器相應(yīng)的位置级乐,代替了ViewStub的存在

//注意layoutParams參數(shù)包含哪些值

parent.addView(view,?index,?layoutParams);

}?else?{

parent.addView(view,?index);

}

//創(chuàng)建加載布局的弱引用疙咸,在上面setVisibility()函數(shù)中會用到

mInflatedViewRef=newWeakReference(view);

if?(mInflateListener?!=?null)?{

//布局加載成功,并且成功替換了ViewStub的位置风科,和擁有了ViewStub的資源撒轮。于是執(zhí)行回調(diào)通知調(diào)用者

mInflateListener.onInflate(this,?view);

}

//把加載到的布局對象返回給外部調(diào)用者

return?view;

}?else?{

//沒有指定待加載的布局,則報(bào)異常

throw?new?IllegalArgumentException("ViewStub?must?have?a?valid?layoutResource");

}

}?else?{

//沒有父容器丐重,則報(bào)異常

throw?new?IllegalStateException("ViewStub?must?have?a?non-null?ViewGroup?viewParent");

}

}

/**

*?設(shè)置回調(diào),當(dāng)ViewStub成功的加載了布局資源后杆查,會回調(diào)此接口進(jìn)行通知

*

*?@param?inflateListener?The?OnInflateListener?to?notify?of?successful?inflation.

*

*?@see?android.view.ViewStub.OnInflateListener

*/

public?void?setOnInflateListener(OnInflateListener?inflateListener)?{

mInflateListener=inflateListener;

}

/**

*?資源文件成功被ViewStub加載后的監(jiān)聽器

*

*?@see?android.view.ViewStub#setOnInflateListener(android.view.ViewStub.OnInflateListener)

*/

public?static?interface?OnInflateListener?{

/**

*?Invoked?after?a?ViewStub?successfully?inflated?its?layout?resource.

*?This?method?is?invoked?after?the?inflated?view?was?added?to?the

*?hierarchy?but?before?the?layout?pass.

*

*?@param?stub?The?ViewStub?that?initiated?the?inflation.

*?@param?inflated?The?inflated?View.

*/

void?onInflate(ViewStub?stub,?View?inflated);

}

}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末扮惦,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子亲桦,更是在濱河造成了極大的恐慌崖蜜,老刑警劉巖浊仆,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異豫领,居然都是意外死亡抡柿,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進(jìn)店門等恐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來洲劣,“玉大人,你說我怎么就攤上這事课蔬〈鸦” “怎么了?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵二跋,是天一觀的道長战惊。 經(jīng)常有香客問我,道長扎即,這世上最難降的妖魔是什么吞获? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮谚鄙,結(jié)果婚禮上各拷,老公的妹妹穿的比我還像新娘。我一直安慰自己襟锐,他們只是感情好撤逢,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著粮坞,像睡著了一般蚊荣。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上莫杈,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天互例,我揣著相機(jī)與錄音,去河邊找鬼筝闹。 笑死媳叨,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的关顷。 我是一名探鬼主播糊秆,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼议双!你這毒婦竟也來了痘番?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎汞舱,沒想到半個(gè)月后伍纫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡昂芜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年莹规,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片泌神。...
    茶點(diǎn)故事閱讀 39,965評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡良漱,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出腻扇,到底是詐尸還是另有隱情债热,我是刑警寧澤,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布幼苛,位于F島的核電站窒篱,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏舶沿。R本人自食惡果不足惜墙杯,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望括荡。 院中可真熱鬧高镐,春花似錦、人聲如沸畸冲。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽邑闲。三九已至算行,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間苫耸,已是汗流浹背州邢。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留褪子,地道東北人量淌。 一個(gè)月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像嫌褪,于是被迫代替她去往敵國和親呀枢。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評論 2 355

推薦閱讀更多精彩內(nèi)容