本篇主要講解View及Drawable相關(guān)
View相關(guān)
Q:MotionEvent是什么护糖?包含幾種事件卜壕?什么條件下會產(chǎn)生?
- 技術(shù)點:View觸控
- 參考回答::MotionEvent是手指觸摸屏幕鎖產(chǎn)生的一系列事件。包含的事件有:
- ACTION_DOWN:手指剛接觸屏幕
- ACTION_MOVE:手指在屏幕上滑動
- ACTION_UP:手指在屏幕上松開的一瞬間
- ACTION_CANCEL:手指保持按下操作京闰,并從當前控件轉(zhuǎn)移到外層控件時會觸發(fā)
Q:scrollTo()和scrollBy()的區(qū)別?
- 技術(shù)點:View滑動
- 參考回答:scrollBy內(nèi)部調(diào)用了scrollTo乳附,它是基于當前位置的相對滑動辛蚊;而scrollTo是絕對滑動,因此如果利用相同輸入?yún)?shù)多次調(diào)用scrollTo()方法窟扑,由于View初始位置是不變只會出現(xiàn)一次View滾動的效果而不是多次喇颁。
- 引申:兩者都只能對view內(nèi)容進行滑動寄月,而不能使view本身滑動,且非平滑无牵,可使用Scroller有過渡滑動的效果
Q:Scroller中最重要的兩個方法是什么漾肮?主要目的是?
- 技術(shù)點:View滑動
- 思路:從Scroller實現(xiàn)滑動的具體過程出發(fā)
- 參考回答:Scroller實現(xiàn)滑動的具體過程:
- 在MotionEvent.ACTION_UP事件觸發(fā)時調(diào)用startScroll()方法茎毁,該方法并沒有進行實際的滑動操作克懊,而是記錄滑動相關(guān)量
- 馬上調(diào)用invalidate/postInvalidate()方法,請求View重繪七蜘,導(dǎo)致View.draw方法被執(zhí)行
緊接著會調(diào)用View.computeScroll()方法谭溉,此方法是空實現(xiàn),需要自己處理邏輯橡卤。具體邏輯是:先判斷computeScrollOffset()扮念,若為true(表示滾動未結(jié)束),則執(zhí)行scrollTo()方法碧库,它會再次調(diào)用postInvalidate()柜与,如此反復(fù)執(zhí)行,直到返回值為false嵌灰。流程圖如下:
View滑動流程圖
其中弄匕,最重要的兩個方法是startScroll()和computeScroll()
Q:談一談View的事件分發(fā)機制?
- 技術(shù)點:View事件分發(fā)
- 思路:從分發(fā)本質(zhì)沽瞭、傳遞順序迁匠、核心方法展開
- 參考回答:
- 事件分發(fā)本質(zhì):就是對MotionEvent事件分發(fā)的過程。即當一個MotionEvent產(chǎn)生了以后驹溃,系統(tǒng)需要將這個點擊事件傳遞到一個具體的View上城丧。
- 點擊事件的傳遞順序:Activity(Window) -> ViewGroup -> View
- 三個主要方法:
- dispatchTouchEvent:進行事件的分發(fā)(傳遞)。返回值是 boolean 類型豌鹤,受當前onTouchEvent和下級view的dispatchTouchEvent影響
- onInterceptTouchEvent:對事件進行攔截亡哄。該方法只在ViewGroup中有,View(不包含 ViewGroup)是沒有的傍药。一旦攔截磺平,則執(zhí)行ViewGroup的onTouchEvent,在ViewGroup中處理事件拐辽,而不接著分發(fā)給View拣挪。且只調(diào)用一次,所以后面的事件都會交給ViewGroup處理俱诸。
- onTouchEvent:進行事件處理菠劝。
Q:如何解決View的滑動沖突?
- 技術(shù)點:View滑動沖突
- 思路:從處理規(guī)則和具體實現(xiàn)方法展開討論
- 參考回答:
- (1)處理規(guī)則:
- 對于由于外部滑動和內(nèi)部滑動方向不一致導(dǎo)致的滑動沖突睁搭,可以根據(jù)滑動的方向判斷誰來攔截事件赶诊。
- 對于由于外部滑動方向和內(nèi)部滑動方向一致導(dǎo)致的滑動沖突笼平,可以根據(jù)業(yè)務(wù)需求,規(guī)定何時讓外部View攔截事件何時由內(nèi)部View攔截事件舔痪。
- 對于上面兩種情況的嵌套寓调,相對復(fù)雜,可同樣根據(jù)需求在業(yè)務(wù)上找到突破點锄码。
- (2)實現(xiàn)方法:
- 外部攔截法:指點擊事件都先經(jīng)過父容器的攔截處理夺英,如果父容器需要此事件就攔截,否則就不攔截滋捶。具體方法:需要重寫父容器的onInterceptTouchEvent方法痛悯,在內(nèi)部做出相應(yīng)的攔截。
- 內(nèi)部攔截法:指父容器不攔截任何事件重窟,而將所有的事件都傳遞給子容器载萌,如果子容器需要此事件就直接消耗,否則就交由父容器進行處理巡扇。具體方法:需要配合requestDisallowInterceptTouchEvent方法扭仁。
Q:談一談View的工作原理?
- 技術(shù)點:View工作流程
- 思路:圍繞三大流程展開
參考回答:View工作流程簡單來說就是霎迫,先measure測量斋枢,用于確定View的測量寬高,再 layout布局知给,用于確定View的最終寬高和四個頂點的位置,最后 draw繪制描姚,用于將View 繪制到屏幕上涩赢。具體過程圖見:
View的繪制流程
- ViewRoot對應(yīng)于ViewRootImpl類,它是連接WindowManager和DecorView的紐帶轩勘。
- View的繪制流程是從ViewRoot和performTraversals開始筒扒。
- performTraversals()依次調(diào)用performMeasure()、performLayout()和performDraw()三個方法绊寻,分別完成頂級 View的繪制花墩。
- 其中,performMeasure()會調(diào)用measure()澄步,measure()中又調(diào)用onMeasure()冰蘑,實現(xiàn)對其所有子元素的measure過程,這樣就完成了一次measure過程村缸;接著子元素會重復(fù)父容器的measure過程祠肥,如此反復(fù)至完成整個View樹的遍歷。layout和draw同理梯皿。
Q:MeasureSpec是什么仇箱?有什么作用县恕?
- 技術(shù)點:View工作流程(measure)
- 思路:從MeasureSpec作用、組成剂桥、模式和決定因素展開
- 參考回答:
- 作用:通過寬測量值widthMeasureSpec和高測量值heightMeasureSpec決定View的大小
- 組成:一個32位int值忠烛,高2位代表SpecMode(測量模式),低30位代表SpecSize( 某種測量模式下的規(guī)格大小)权逗。
- 三種模式:
- UNSPECIFIED:父容器不對View有任何限制况木,要多大有多大。常用于系統(tǒng)內(nèi)部旬迹。
- EXACTLY(精確模式):父視圖為子視圖指定一個確切的尺寸SpecSize火惊。對應(yīng)LayoutParams中的match_parent或具體數(shù)值。
- AT_MOST(最大模式):父容器為子視圖指定一個最大尺寸SpecSize奔垦,View的大小不能大于這個值屹耐。對應(yīng)LayoutParams中的wrap_content。
決定因素:值由子View的布局參數(shù)LayoutParams和父容器的MeasureSpec值共同決定椿猎。具體規(guī)則見下圖:
- 引申:直接繼承View的自定義View需要重寫onMeasure()并設(shè)置wrap_content時的自身大小惶岭,否則效果相當于macth_parent
Q:自定義View/ViewGroup需要注意什么?
- 技術(shù)點:自定義View
參考回答:
Q:onTouch()犯眠、onTouchEvent()和onClick()關(guān)系按灶?
- 技術(shù)點:View事件分發(fā)
- 參考回答:優(yōu)先度onTouch()>onTouchEvent()>onClick()。因此onTouchListener的onTouch()方法會先觸發(fā)筐咧;如果onTouch()返回false才會接著觸發(fā)onTouchEvent()鸯旁,同樣的,內(nèi)置諸如onClick()事件的實現(xiàn)等等都基于onTouchEvent()量蕊;如果onTouch()返回true铺罢,這些事件將不會被觸發(fā)。
- 引申:OnTouchListener残炮、OnClickListener的沖突
Q:SurfaceView和View的區(qū)別韭赘?
- 技術(shù)點:View、SurfaceView
- 參考回答:SurfaceView是從View基類中派生出來的顯示類势就,他和View的區(qū)別有:
- View需要在UI線程對畫面進行刷新泉瞻,而SurfaceView可在子線程進行頁面的刷新
- View適用于主動更新的情況,而SurfaceView適用于被動更新苞冯,如頻繁刷新袖牙,這是因為如果使用View頻繁刷新會阻塞主線程,導(dǎo)致界面卡頓
- SurfaceView在底層已實現(xiàn)雙緩沖機制抱完,而View沒有贼陶,因此SurfaceView更適用于需要頻繁刷新、刷新時數(shù)據(jù)處理量很大的頁面
Q:invalidate()和postInvalidate()的區(qū)別?
- 技術(shù)點:View刷新
- 參考回答:invalidate()與postInvalidate()都用于刷新View碉怔,主要區(qū)別是invalidate()在主線程中調(diào)用烘贴,若在子線程中使用需要配合handler;而postInvalidate()可在子線程中直接調(diào)用撮胧。
Drawable相關(guān)
Q:了解哪些Drawable桨踪?適用場景?
- 技術(shù)點:res資源
- 參考回答:BitmapDrawable表示一張圖片芹啥、NinePatchDrawable可自動地根據(jù)所需的寬/高對圖片進行相應(yīng)的縮放并保證不失真锻离、ShapeDrawable表示純色、有漸變效果的基礎(chǔ)幾何圖形墓怀、StateListDrawable表示一個Drawable的集合且每個Drawable對應(yīng)著View的一種狀態(tài)汽纠、LayerDrawable可通過將不同的Drawable放置在不同的層上面從而達到一種疊加后的效果
Q:mipmap系列中xxxhdpi、xxhdpi傀履、xhdpi虱朵、hdpi、mdpi和ldpi存在怎樣的關(guān)系钓账?
- 技術(shù)點:res資源
- 參考回答:表示不同密度的圖片資源碴犬,像素從高到低依次排序為xxxhdpi>xxhdpi>xhdpi>hdpi>mdpi>ldpi,根據(jù)手機的dpi不同加載不同密度的圖片
Q:dp梆暮、dpi服协、px的區(qū)別?
- 技術(shù)點:Android適配
- 參考回答:
- px:像素啦粹,如分辨率1920x1080表示高為1920個像素偿荷、寬為1080個像素
- dpi:每英寸的像素點,如分辨率為1920x1080的手機尺寸為4.95英寸卖陵,則該手機DPI為(1920x1920+ 1080x1080)?/4.95≈445dpi
- dp:密度無關(guān)像素遭顶,是個相對值
Q:res目錄和assets目錄的區(qū)別?
- 技術(shù)點:res泪蔫、assets
- 參考回答:
- res/raw中的文件會被映射到R.java文件中,訪問時可直接使用資源ID喘批,不可以有目錄結(jié)構(gòu)
- assets文件夾下的文件不會被映射到R.java中撩荣,訪問時需要AssetManager類,可以創(chuàng)建子文件夾