android中view視圖繪制不同狀態(tài)背景圖片原理深入分析以及使用詳解_第1頁
android中view視圖繪制不同狀態(tài)背景圖片原理深入分析以及使用詳解_第2頁
android中view視圖繪制不同狀態(tài)背景圖片原理深入分析以及使用詳解_第3頁
android中view視圖繪制不同狀態(tài)背景圖片原理深入分析以及使用詳解_第4頁
android中view視圖繪制不同狀態(tài)背景圖片原理深入分析以及使用詳解_第5頁
已閱讀5頁,還剩12頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、今天繼續(xù)給大家分享下View的相關(guān)知識(shí),重點(diǎn)有一下兩點(diǎn): 1、View的幾種不同狀態(tài)屬性 2、如何根據(jù)不同狀態(tài)去切換我們的背景圖片。開篇介紹:android背景選擇器selector用法匯總 對Android開發(fā)有經(jīng)驗(yàn)的同學(xué),對節(jié)點(diǎn)的使用一定很熟悉,該節(jié)點(diǎn)的作用就是定義一組狀態(tài)資源圖片,使其能夠 在不同的狀態(tài)下更換某個(gè)View的背景圖片。例如,如下的hello_selection.xml文件定義:java HYPERLINK /qinjuning/article/details/7474827 o view plain view plain HYPERLINK /qinjuning/artic

2、le/details/7474827 o copy copy HYPERLINK /qinjuning/article/details/7474827 o print print HYPERLINK /qinjuning/article/details/7474827 o ? ? 更多關(guān)于節(jié)點(diǎn)的使用請參考該博客 其實(shí),前面說的xml文件,最終會(huì)被Android框架解析成StateListDrawable類對象。知識(shí)點(diǎn)一:StateListDrawable類介紹 類功能說明:該類定義了不同狀態(tài)值下與之對應(yīng)的圖片資源,即我們可以利用該類保存多種狀態(tài)值,多種圖片資源。 常用方法為: public v

3、oidaddState(int stateSet,Drawabledrawable) 功能: 給特定的狀態(tài)集合設(shè)置drawable圖片資源 使用方式:參考前面的hello_selection.xml文件,我們利用代碼去構(gòu)建一個(gè)相同的StateListDrawable類對象,如下:java HYPERLINK /qinjuning/article/details/7474827 o view plain view plain HYPERLINK /qinjuning/article/details/7474827 o copy copy HYPERLINK /qinjuning/article/

4、details/7474827 o print print HYPERLINK /qinjuning/article/details/7474827 o ? ?/初始化一個(gè)空對象StateListDrawablestalistDrawable=newStateListDrawable();/獲取對應(yīng)的屬性值A(chǔ)ndroid框架自帶的屬性attrintpressed=android.R.attr.state_pressed;intwindow_focused=android.R.attr.state_window_focused;intfocused=android.R.attr.state_fo

5、cused;intselected=android.R.attr.state_selected;stalistDrawable.addState(newintpressed,window_focused,getResources().getDrawable(R.drawable.pic1);stalistDrawable.addState(newintpressed,-focused,getResources().getDrawable(R.drawable.pic2);stalistDrawable.addState(newintselected,getResources().getDraw

6、able(R.drawable.pic3);stalistDrawable.addState(newintfocused,getResources().getDrawable(R.drawable.pic4);/沒有任何狀態(tài)時(shí)顯示的圖片,我們給它設(shè)置我空集合stalistDrawable.addState(newint,getResources().getDrawable(R.drawable.pic5); 上面的“-”負(fù)號(hào)表示對應(yīng)的屬性值為false 當(dāng)我們?yōu)槟硞€(gè)View使用其作為背景色時(shí),會(huì)根據(jù)狀態(tài)進(jìn)行背景圖的轉(zhuǎn)換。 public booleanisStateful() 功能: 表明該狀態(tài)

7、改變了,對應(yīng)的drawable圖片是否會(huì)改變。 注:在StateListDrawable類中,該方法返回為true,顯然狀態(tài)改變后,我們的圖片會(huì)跟著改變。知識(shí)點(diǎn)二:View的五種狀態(tài)值 一般來說,Android框架為View定義了四種不同的狀態(tài),這些狀態(tài)值的改變會(huì)引發(fā)View相關(guān)操作,例如:更換背景圖片、是否 觸發(fā)點(diǎn)擊事件等;視 視圖幾種不同狀態(tài)含義見下圖: 其中selected和focused的區(qū)別有如下幾點(diǎn): 1,我們通過查看setSelected()方法,來獲取相關(guān)信息。 SDK中對setSelected()方法-對于與selected狀態(tài)有如下說明: public voidsetSel

8、ected(boolean selected) Since: HYPERLINK F:android-sdk-windowsdocsguideappendixapi-levels.html l level1 APILevel 1 Changes the selection state of this view. Aview can be selected or not.Note that selection is not the same as focus. Views are typically selected in the context of an AdapterView like L

9、istView or GridView ;the selected view is the view that is highlighted. Parametersselected true if the view must be selected, false otherwise 由以上可知:selected不同于focus狀態(tài),通常在AdapterView類群下例如ListView或者GridView會(huì)使某個(gè)View處于 selected狀態(tài),并且獲得該狀態(tài)的View處于高亮狀態(tài)。 2、一個(gè)窗口只能有一個(gè)視圖獲得焦點(diǎn)(focus),而一個(gè)窗口可以有多個(gè)視圖處于”selected”狀態(tài)中。

10、總結(jié):focused狀態(tài)一般是由按鍵操作引起的; pressed狀態(tài)是由觸摸消息引起的; selected則完全是由應(yīng)用程序主動(dòng)調(diào)用setSelected()進(jìn)行控制。 例如:當(dāng)我們觸摸某個(gè)控件時(shí),會(huì)導(dǎo)致pressed狀態(tài)改變;獲得焦點(diǎn)時(shí),會(huì)導(dǎo)致focus狀態(tài)變化。于是,我們可以通過這種 更新后狀態(tài)值去更新我們對應(yīng)的Drawable對象了。問題:如何根據(jù)狀態(tài)值的改變?nèi)ダL制/顯示對應(yīng)的背景圖? 當(dāng)View任何狀態(tài)值發(fā)生改變時(shí),都會(huì)調(diào)用refreshDrawableList()方法去更新對應(yīng)的背景Drawable對象。 其整體調(diào)用流程如下: View.java類中java HYPERLINK /q

11、injuning/article/details/7474827 o view plain view plain HYPERLINK /qinjuning/article/details/7474827 o copy copy HYPERLINK /qinjuning/article/details/7474827 o print print HYPERLINK /qinjuning/article/details/7474827 o ? ?/路徑:frameworksbasecorejavaandroidviewView.java/*Callthistoforceaviewtoupdatei

12、tsdrawablestate.Thiswillcause*drawableStateChangedtobecalledonthisview.Viewsthatareinterested*inthenewstateshouldcallgetDrawableState.*/主要功能是根據(jù)當(dāng)前的狀態(tài)值去更換對應(yīng)的背景Drawable對象publicvoidrefreshDrawableState()mPrivateFlags|=DRAWABLE_STATE_DIRTY;/所有功能在這個(gè)函數(shù)里去完成drawableStateChanged();./*Thisfunctioniscalledwhene

13、verthestateoftheviewchangesinsuch*awaythatitimpactsthestateofdrawablesbeingshown.*/獲得當(dāng)前的狀態(tài)屬性-整型集合;調(diào)用Drawable類的setState方法去獲取資源。protectedvoiddrawableStateChanged()/該視圖對應(yīng)的Drawable對象,通常對應(yīng)于StateListDrawable類對象Drawabled=mBGDrawable;if(d!=null&d.isStateful()/通常都是成立的/getDrawableState()方法主要功能:會(huì)根據(jù)當(dāng)前View的狀態(tài)屬性值

14、,將其轉(zhuǎn)換為一個(gè)整型集合/setState()方法主要功能:根據(jù)當(dāng)前的獲取到的狀態(tài),更新對應(yīng)狀態(tài)下的Drawable對象。d.setState(getDrawableState();/*ReturnanarrayofresourceIDsofthedrawablestatesrepresentingthe*currentstateoftheview.*/publicfinalintgetDrawableState()if(mDrawableState!=null)&(mPrivateFlags&DRAWABLE_STATE_DIRTY)=0)returnmDrawableState;else/

15、根據(jù)當(dāng)前View的狀態(tài)屬性值,將其轉(zhuǎn)換為一個(gè)整型集合,并返回mDrawableState=onCreateDrawableState(0);mPrivateFlags&=DRAWABLE_STATE_DIRTY;returnmDrawableState; 通過這段代碼我們可以明白View內(nèi)部是如何獲取更細(xì)后的狀態(tài)值以及動(dòng)態(tài)獲取對應(yīng)的背景Drawable對象-setState()方法去完成的。這兒我簡單的分析下Drawable類里的setState()方法的功能,把流程給走一下: Step 1、setState()函數(shù)原型 , 函數(shù)位于:frameworksbasegraphicsjavaand

16、roidgraphicsdrawableStateListDrawable.java 類中java HYPERLINK /qinjuning/article/details/7474827 o view plain view plain HYPERLINK /qinjuning/article/details/7474827 o copy copy HYPERLINK /qinjuning/article/details/7474827 o print print HYPERLINK /qinjuning/article/details/7474827 o ? ?/如果狀態(tài)態(tài)值發(fā)生了改變,就回

17、調(diào)onStateChange()方法。publicbooleansetState(finalintstateSet)if(!Arrays.equals(mStateSet,stateSet)mStateSet=stateSet;returnonStateChange(stateSet);returnfalse; 該函數(shù)的主要功能: 判斷狀態(tài)值是否發(fā)生了變化,如果發(fā)生了變化,就調(diào)用onStateChange()方法進(jìn)一步處理。 Step 2、onStateChange()函數(shù)原型: 該函數(shù)位于 frameworksbasegraphicsjavaandroidgraphicsdrawableSt

18、ateListDrawable.java 類中java HYPERLINK /qinjuning/article/details/7474827 o view plain view plain HYPERLINK /qinjuning/article/details/7474827 o copy copy HYPERLINK /qinjuning/article/details/7474827 o print print HYPERLINK /qinjuning/article/details/7474827 o ? ?/狀態(tài)值發(fā)生了改變,我們需要找出第一個(gè)吻合的當(dāng)前狀態(tài)的Drawable對象

19、protectedbooleanonStateChange(intstateSet)/要找出第一個(gè)吻合的當(dāng)前狀態(tài)的Drawable對象所在的索引位置,具體匹配算法請自己深入源碼看看intidx=mStateListState.indexOfStateSet(stateSet);./獲取對應(yīng)索引位置的Drawable對象if(selectDrawable(idx)returntrue;. 該函數(shù)的主要功能: 根據(jù)新的狀態(tài)值,從StateListDrawable實(shí)例對象中,找到第一個(gè)完全吻合該新狀態(tài)值的索引下標(biāo)處 ; 繼而,調(diào)用selectDrawable()方法去獲取索引下標(biāo)的當(dāng)前Drawabl

20、e對象。 具體查找算法在mStateListState.indexOfStateSet(stateSet) 里實(shí)現(xiàn)了?;舅悸肥牵翰檎业谝粋€(gè)能完全吻合該新狀態(tài)值 的索引下標(biāo),如果找到了,則立即返回。 具體實(shí)現(xiàn)過程,只好看看源碼咯。 Step 3、selectDrawable()函數(shù)原型: 該函數(shù)位于 frameworksbasegraphicsjavaandroidgraphicsdrawableStateListDrawable.java 類中java HYPERLINK /qinjuning/article/details/7474827 o view plain view plain H

21、YPERLINK /qinjuning/article/details/7474827 o copy copy HYPERLINK /qinjuning/article/details/7474827 o print print HYPERLINK /qinjuning/article/details/7474827 o ? ?publicbooleanselectDrawable(intidx)if(idx=0&idxmDrawableContainerState.mNumChildren)/獲取對應(yīng)索引位置的Drawable對象Drawabled=mDrawableContainerSta

22、te.mDrawablesidx;.mCurrDrawable=d;/mCurrDrawable即使當(dāng)前Drawable對象mCurIndex=idx;.else./請求該View刷新自己,這個(gè)方法我們稍后講解。invalidateSelf();returntrue; 該函數(shù)的主要功能是選擇當(dāng)前索引下標(biāo)處的Drawable對象,并保存在mCurrDrawable中。知識(shí)點(diǎn)三: 關(guān)于Drawable.Callback接口 該接口定義了如下三個(gè)函數(shù): java HYPERLINK /qinjuning/article/details/7474827 o view plain view plain

23、HYPERLINK /qinjuning/article/details/7474827 o copy copy HYPERLINK /qinjuning/article/details/7474827 o print print HYPERLINK /qinjuning/article/details/7474827 o ? ?/該函數(shù)位于frameworksbasegraphicsjavaandroidgraphicsdrawableDrawable.java類中publicstaticinterfaceCallback/如果Drawable對象的狀態(tài)發(fā)生了變化,會(huì)請求View重新繪制,/

24、因此我們對應(yīng)于該View的背景Drawable對象能夠”繪制出來”.publicvoidinvalidateDrawable(Drawablewho);/該函數(shù)目前還不懂publicvoidscheduleDrawable(Drawablewho,Runnablewhat,longwhen);/該函數(shù)目前還不懂publicvoidunscheduleDrawable(Drawablewho,Runnablewhat);其中比較重要的函數(shù)為: public voidinvalidateDrawable(Drawable who) 函數(shù)功能:如果Drawable對象的狀態(tài)發(fā)生了變化,會(huì)請求View

25、重新繪制,因此我們對應(yīng)于該View的背景Drawable對象 能夠重新”繪制“出來。 Android框架View類繼承了該接口,同時(shí)實(shí)現(xiàn)了這三個(gè)函數(shù)的默認(rèn)處理方式,其中invalidateDrawable()方法如下:java HYPERLINK /qinjuning/article/details/7474827 o view plain view plain HYPERLINK /qinjuning/article/details/7474827 o copy copy HYPERLINK /qinjuning/article/details/7474827 o print print H

26、YPERLINK /qinjuning/article/details/7474827 o ? ?publicclassViewimplementsDrawable.Callback,KeyEvent.Callback,AccessibilityEventSource./InvalidatesthespecifiedDrawable./默認(rèn)實(shí)現(xiàn),重新繪制該視圖本身publicvoidinvalidateDrawable(Drawabledrawable)if(verifyDrawable(drawable)/是否是同一個(gè)Drawable對象,通常為真finalRectdirty=drawabl

27、e.getBounds();finalintscrollX=mScrollX;finalintscrollY=mScrollY;/重新請求繪制該View,即重新調(diào)用該View的draw()方法.invalidate(dirty.left+scrollX,dirty.top+scrollY,dirty.right+scrollX,dirty.bottom+scrollY);. 因此,我們的Drawable類對象必須將View設(shè)置為回調(diào)對象,否則,即使改變了狀態(tài),也不會(huì)顯示對應(yīng)的背景圖。 如下:Drawable d ; / 圖片資源 d.setCallback(View v) ; / 視圖v的背景

28、資源為 d 對象知識(shí)點(diǎn)四:View繪制背景圖片過程 在前面的博客中 HYPERLINK /qinjuning/article/details/7110211 t _blank Android中View繪制流程以及invalidate()等相關(guān)方法分析,我們知道了一個(gè)視圖的背景繪制過程時(shí)在 View類里的draw()方法里完成的,我們這兒在回顧下draw()的流程,同時(shí)重點(diǎn)講解下繪制背景的操作。java HYPERLINK /qinjuning/article/details/7474827 o view plain view plain HYPERLINK /qinjuning/article

29、/details/7474827 o copy copy HYPERLINK /qinjuning/article/details/7474827 o print print HYPERLINK /qinjuning/article/details/7474827 o ? ?/方法所在路徑:frameworksbasecorejavaandroidviewView.java/draw()繪制過程privatevoiddraw(Canvascanvas)/該方法會(huì)做如下事情/1、繪制該View的背景/其中背景圖片繪制過程如下:/是否透明,視圖通常是透明的,為trueif(!dirtyOpaque

30、)/開始繪制視圖的背景finalDrawablebackground=mBGDrawable;if(background!=null)finalintscrollX=mScrollX;/獲取偏移值finalintscrollY=mScrollY;/視圖的布局坐標(biāo)是否發(fā)生了改變,即是否重新layout了。if(mBackgroundSizeChanged)/如果是,我們的Drawable對象需要重新設(shè)置大小了,即填充該View。background.setBounds(0,0,mRight-mLeft,mBottom-mTop);mBackgroundSizeChanged=false;/Vie

31、w沒有發(fā)生偏移if(scrollX|scrollY)=0)background.draw(canvas);/OK,該方法會(huì)繪制當(dāng)前StateListDrawable的當(dāng)前背景Drawableelse/View發(fā)生偏移,由于背景圖片值顯示在布局坐標(biāo)中,即背景圖片不會(huì)發(fā)生偏移,只有視圖內(nèi)容onDraw()會(huì)發(fā)生偏移/我們調(diào)整canvas對象的繪制區(qū)域,繪制完成后對canvas對象屬性調(diào)整回來canvas.translate(scrollX,scrollY);background.draw(canvas);/OK,該方法會(huì)繪制當(dāng)前StateListDrawable的當(dāng)前背景Drawablecanva

32、s.translate(-scrollX,-scrollY);./2、為繪制漸變框做一些準(zhǔn)備操作/3、調(diào)用onDraw()方法繪制視圖本身/4、調(diào)用dispatchDraw()方法繪制每個(gè)子視圖,dispatchDraw()已經(jīng)在Android框架中實(shí)現(xiàn)了,在ViewGroup方法中。/5、繪制漸變框 Thats all ! 我們用到的知識(shí)點(diǎn)也就這么多吧。如果大家有絲絲不明白的話,可以去看下源代碼,具體去分析下這些流程到底 是怎么走下來的。 我們從宏觀的角度分析了View繪制不同狀態(tài)背景的原理,View框架就是這么做的。為了易于理解性, 下面我們通過一個(gè)小Demo來演示前面種種流程。 Demo

33、 說明: 我們參照View框架中繪制不同背景圖的實(shí)現(xiàn)原理,自定義一個(gè)View類,通過給它設(shè)定StateListDrawable對象,使其能夠在 不同狀態(tài)時(shí)能動(dòng)態(tài)繪制背景圖片。 基本流程方法和View.java類實(shí)現(xiàn)過程一模一樣。 截圖如下: 初始背景圖 觸摸后顯示的背景圖(pressed) 一、主文件MainActivity.java如下:java HYPERLINK /qinjuning/article/details/7474827 o view plain view plain HYPERLINK /qinjuning/article/details/7474827 o copy cop

34、y HYPERLINK /qinjuning/article/details/7474827 o print print HYPERLINK /qinjuning/article/details/7474827 o ? ?/*authorhttp:/qinjuning*/publicclassMainActivityextendsActivityOverridepublicvoidonCreate(BundlesavedInstanceState)super.onCreate(savedInstanceState);LinearLayoutll=newLinearLayout(MainActi

35、vity.this);CustomViewcustomView=newCustomView(MainActivity.this);/簡單設(shè)置為width200px-height100px吧ViewGroup.LayoutParamslp=newViewGroup.LayoutParams(200,100);customView.setLayoutParams(lp);/需要將該View設(shè)置為可點(diǎn)擊/觸摸狀態(tài),否則觸摸該View沒有效果。customView.setClickable(true);ll.addView(customView);setContentView(ll); 功能很簡單,為

36、Activity設(shè)置了視圖 。二、自定義View如下 , CustomView.java :java HYPERLINK /qinjuning/article/details/7474827 o view plain view plain HYPERLINK /qinjuning/article/details/7474827 o copy copy HYPERLINK /qinjuning/article/details/7474827 o print print HYPERLINK /qinjuning/article/details/7474827 o ? ?/*authorhttp:/

37、qinjuning*/自定義ViewpublicclassCustomViewextendsView/*extendsButton*/privatestaticStringTAG=TackTextView;privateContextmContext=null;privateDrawablemBackground=null;privatebooleanmBGSizeChanged=true;/視圖View布局(layout)大小是否發(fā)生變化publicCustomView(Contextcontext)super(context);mContext=context;initStateListD

38、rawable();/初始化圖片資源/初始化圖片資源privatevoidinitStateListDrawable()/有兩種方式獲取我們的StateListDrawable對象:/獲取方式一、手動(dòng)構(gòu)建一個(gè)StateListDrawable對象StateListDrawablestatelistDrawable=newStateListDrawable();intpressed=android.R.attr.state_pressed;intwindowfocused=android.R.attr.state_window_focused;intenabled=android.R.attr.

39、state_enabled;intstateFoucesd=android.R.attr.state_focused;/匹配狀態(tài)時(shí),是一種優(yōu)先包含的關(guān)系。/-號(hào)表示該狀態(tài)值為false.即不匹配statelistDrawable.addState(newintpressed,windowfocused,mContext.getResources().getDrawable(R.drawable.btn_power_on_pressed);statelistDrawable.addState(newint-pressed,windowfocused,mContext.getResources().getDrawable(R.drawable.btn_power_on_nor);mBackground=statelistDrawable;/必須設(shè)置回調(diào),當(dāng)改變狀態(tài)時(shí),會(huì)回掉該View進(jìn)行invalidate()刷新操作.mBackground.setCallback(this);/取消默認(rèn)的背景圖片,因?yàn)槲覀冊O(shè)置了自己的背景圖片了,否則可能造成背景圖片重疊。this.setBackgroundDrawable(null);/獲取方式二、使用XML獲取StateListDrawable對象/mBackground=mContext.getResources().getDrawabl

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論