Android 自定義view 基礎(chǔ)篇(二)

目錄

從0到1Android自定義View(二) 分類和核心函數(shù).png

一、自定義 View 分類

常見的 Android 自定義 View 主要有兩種類型:

1坝橡、組合控件

通過 Android 的基礎(chǔ)控件(TextView、ImageView湃番、Button褪猛、ProgressBar 等)組合而成,比如下拉刷新吃环、瀑布流控件也颤、帶左/右滑功能的控件、視頻控件等郁轻,這種自定義View的難點(diǎn)在于程序的邏輯處理

2翅娶、完全自定義控件

繼承自 View文留、TextureView 或 SurfaceView ,然后重寫核心的回調(diào)方法竭沫,以View 為例燥翅,按需復(fù)寫其構(gòu)造、onMeasure蜕提、onLayout森书、onTouchEvent、onDraw贯溅、onAttachedToWindow拄氯、onDetachedFromWindow 等方法,這種自定義 View 的難點(diǎn)在于程序的設(shè)計(jì)它浅、效率優(yōu)化和排版译柏,比如輸入法中的手寫控件、圖文混排控件(現(xiàn)在很多都是通過webview加載網(wǎng)頁(yè)實(shí)現(xiàn)了)姐霍、個(gè)性化進(jìn)度條鄙麦、彈幕顯示控件、Markdown控件镊折、IDE代碼編輯控件等

注意:

我們需要合理的使用自定義 View 胯府,千萬不能濫用,不要?jiǎng)硬粍?dòng)就自定義 View 恨胚,基礎(chǔ)控件能完成的功能骂因,千萬別自定義 View,因?yàn)榛A(chǔ)空間 Android赃泡,本身就有性能優(yōu)化的寒波,自定義 View 的價(jià)值在于做到基礎(chǔ)控件無法做到的效果,為應(yīng)用的表現(xiàn)增色升熊;俄烁,將公用的交互效果提取成自定義控件,方便復(fù)用级野,減少不必要的重復(fù)勞動(dòng)页屠。

二、自定義 View 核心知識(shí)點(diǎn)

這部分主要是介紹自定義 View 的核心知識(shí)點(diǎn)蓖柔,上面提到過辰企,完全自定義 View 通常是繼承 View ,TextureView况鸣,SurfaceView蟆豫,所以先來了解下這三者之間的區(qū)別所在。

1懒闷、 View、SurfaceView、TextureView 的區(qū)別

View

普通的 View愤估,與宿主窗口共享同一個(gè)繪圖表面帮辟,UI 在主線程中繪制,在有無硬件加速的情況下都能工作(沒有硬件加速的情況下玩焰,canvas 的有些方法會(huì)失效)

SurfaceView

繼承自 View由驹,繪制和顯示效率高,因?yàn)閾碛歇?dú)立的繪圖表面昔园,UI 在一個(gè)獨(dú)立的線程中進(jìn)行繪制蔓榄,不會(huì)占用主線程的資源。SurfaceView 的使用和普通的 View 不一樣默刚,需要結(jié)合 SurfaceHodler 一起使用甥郑。因?yàn)楹退拗鞔翱诓皇枪蚕硗粋€(gè)繪圖表面的原因,對(duì)其做動(dòng)畫操作可能會(huì)得不到想要的效果

TextureView

繼承自 View荤西,與 SurfaceView 相比澜搅,TextureView 不會(huì)創(chuàng)建一個(gè)單獨(dú)的繪圖表面,這使得它可以像一般的 View 一樣執(zhí)行一些變換操作邪锌,比如移動(dòng)勉躺、動(dòng)畫等等,但 TextureView 必須在硬件加速開啟的窗口中才能正常工作觅丰;

2饵溅、 幾個(gè)重要的函數(shù)

最后通過自定義 View 的流程圖來了解一下自定義 View 幾個(gè)重要的函數(shù)。

自定義view的流程圖.jpg

(1)構(gòu)造函數(shù)

構(gòu)造函數(shù)是View的入口妇萄,可以用于初始化一些的內(nèi)容蜕企,和獲取自定義屬性

View的構(gòu)造函數(shù)有四種重載

自定義View的構(gòu)造函數(shù).png

從上面的圖也可以看出,自定 View 的構(gòu)造函數(shù)的參數(shù)最多有四個(gè)嚣伐,而且有四個(gè)參數(shù)的構(gòu)造函數(shù)只能在 API 21 以上使用糖赔,因此四個(gè)參數(shù)的構(gòu)造函數(shù)先不考慮,不過我們也需要了解這四個(gè)參數(shù)具體代表什么轩端?

Context:View 中隨處都會(huì)用到

AttributeSet:XML 屬性(從 XML inflate 的時(shí)候使用)

int defStyleAttr:應(yīng)用到 View 的默認(rèn)風(fēng)格(定義在主題中)

int defStyleRes:如果沒有使用 defStyleAttr放典,應(yīng)用到 View 的默認(rèn)風(fēng)格

那么這里就有個(gè)問題了,有四種構(gòu)造函數(shù)基茵,我們?cè)撛趺催x擇呢奋构?

比如上面圖片顯示的自定義的 MyView ,繼承 View 對(duì)象拱层,如果我們想在普通的代碼中新建一個(gè) MyView弥臼,可以直接使用一個(gè)參數(shù)的構(gòu)造函數(shù),這也是大多數(shù)選擇使用的根灯。

一個(gè)參數(shù)的構(gòu)造函數(shù).png

那么兩個(gè)參數(shù)的構(gòu)造函數(shù)什么時(shí)候使用呢径缅?比如有時(shí)候在 xml 中添加一個(gè)自定義 View 掺栅,并且加了一些布局屬性,寬高屬性以及 margin 屬性纳猪,這些屬性會(huì)存放在第二個(gè)構(gòu)造函數(shù)的 AttributeSet 參數(shù)里氧卧。

兩個(gè)參數(shù)的構(gòu)造函數(shù).png

有三個(gè)參數(shù)的構(gòu)造函數(shù)比第二個(gè)構(gòu)造函數(shù)多了一個(gè) int 型的值,名字叫 defStyleAttr 氏堤,從名稱上判斷沙绝,這是一個(gè)關(guān)于自定義屬性的參數(shù)。第三個(gè)構(gòu)造函數(shù)不會(huì)被系統(tǒng)默認(rèn)調(diào)用鼠锈,而是需要我們自己去顯式調(diào)用闪檬,比如在第二個(gè)構(gòu)造函數(shù)里調(diào)用調(diào)用第三個(gè)函數(shù),并將第三個(gè)參數(shù)設(shè)為0 购笆。defStyleAttr 指定的是在Theme style 定義的一個(gè) attr粗悯,它的類型是 reference 主要生效在 obtainStyledAttributes 方法里,obtainStyledAttributes 方法有四個(gè)參數(shù)由桌,第三個(gè)參數(shù)是 defStyleAttr 为黎,第四個(gè)參數(shù)是自己指定的一個(gè) style ,當(dāng)且僅當(dāng) defStyleAttr 為 0 或者在 Theme 中找不到 defStyleAttr 指定的屬性時(shí)行您,第四個(gè)參數(shù)才會(huì)生效铭乾,這些指的都是默認(rèn)屬性,當(dāng)在 xml 里面定義的娃循,就以在 xml 文件里指定的為準(zhǔn)炕檩,所以優(yōu)先級(jí)大概是:xml>style>defStyleAttr>defStyleRes>Theme 指定,當(dāng)defStyleAttr 為 0 時(shí)捌斧,就跳過 defStyleAttr 指定的 reference 笛质,所以一般用 0 就能滿足一些基本開發(fā)。

(2)onMeasure(測(cè)量 View 大欣搪臁)

這個(gè)函數(shù)有什么用呢妇押?將這個(gè)問題轉(zhuǎn)化一下,就是問為什么要測(cè)量 View 的大小呢姓迅?

因?yàn)?View 的大小不僅由自身所決定敲霍,同時(shí)也會(huì)受到父控件的影響,為了我們的控件能更好的適應(yīng)各種情況丁存,一般會(huì)自己進(jìn)行測(cè)量

onMeasure.png

MeasureSpce 的 mode 有三種:EXACTLY, AT_MOST肩杈,UNSPECIFIED,除去 UNSPECIFIED 不談解寝,其他兩種 mode:

當(dāng)父布局是 EXACTLY 時(shí)扩然,子控件確定大小或者 match_parent,mode 都是 EXACTLY聋伦,子控件是 wrap_content 時(shí)夫偶,mode 為 AT_MOST界睁;

當(dāng)父布局是 AT_MOST 時(shí),子控件確定大小索守,mode 為 EXACTLY晕窑,子控件 wrap_content 或者 match_parent 時(shí),mode 為 AT_MOST卵佛。

所以在確定控件大小時(shí),需要判斷 MeasureSpec 的 mode敞斋,不能直接用 MeasureSpec 的 size截汪。在進(jìn)行一些邏輯處理以后,調(diào)用 setMeasureDimension() 方法植捎,將測(cè)量得到的寬高傳進(jìn)去供 layout 使用衙解。

onMeasure流程.png

在實(shí)際運(yùn)用之中只需要記住有測(cè)量模式有三種,用 MeasureSpec 的 getSize是獲取數(shù)值焰枢, getMode是獲取模式即可蚓峦。如果對(duì) View 的寬高進(jìn)行修改了,不要調(diào)用 super.onMeasure( widthMeasureSpec, heightMeasureSpec); 要調(diào)用 setMeasuredDimension( widthsize, heightsize); 這個(gè)函數(shù)济锄。

(3)onSizeChanged(確定 View 大惺钜)

那么這個(gè)函數(shù)又是什么時(shí)候調(diào)用呢?

這個(gè)函數(shù)在視圖大小發(fā)生改變時(shí)調(diào)用荐绝。

那么問題又來了一汽,上面的 onMeasure 函數(shù)中不是說對(duì) View 的寬高進(jìn)行了修改后,要調(diào)用 setMeasuredDimension 嗎低滩?調(diào)用這個(gè)方法后召夹,View 的大小基本已經(jīng)確定了啊,View 的視圖大小還會(huì)發(fā)生變化嗎恕沫?這是因?yàn)?View 的大小不僅僅只是由其本身來決定的监憎,也受它的父控件影響,所以在確定 View 大小的時(shí)候最好使用系統(tǒng)提供的 onSizeChanged 回調(diào)函數(shù)婶溯。

onSizeChanged.png

(4)onLayout(確定子 View 布局位置)

確定布局的函數(shù)是 onLayout 鲸阔,它用于確定子 View 的位置,在自定義 ViewGroup 中會(huì)用到爬虱,他調(diào)用的是子 View 的 layout 函數(shù)隶债。比如,有時(shí)候我們自定義 View 的時(shí)候跑筝,需要獲取 View 的一些信息就需要用到這個(gè)函數(shù)死讹。當(dāng)然,如果是單純的 View 就沒與必要重寫這個(gè)方法曲梗,為什么這么說呢赞警?

因?yàn)閱渭兊?View 妓忍,不是一個(gè) View 容器,沒有子 View 愧旦,而 onLayout 方法里主要是具體擺放子View 的位置世剖,水平擺放或者垂直擺放,所以在單純的自定義 View 是不需要重寫 onLayout 方法笤虫。不過需要注意的一點(diǎn)是旁瘫,子 View 的 margin 屬性是否生效就要看 parent 是否在自身的 onLayout 方法進(jìn)行處理,而 View 的 padding 屬性是在 onDraw 方法中生效的

(5)onDraw(繪制內(nèi)容)

重頭戲琼蚯,onDraw酬凳,也就是是實(shí)際繪制的部分。

onDraw.png

一般自定義控件耗費(fèi)心思最多的就是這個(gè)方法了遭庶,需要在這個(gè)方法里宁仔,用 Paint 在 Canvas 上畫出你想要的圖案。如果是直接繼承的 View峦睡,那么在重寫 onDraw 的方法是時(shí)候完全可以把 super.ondraw(canvas) 刪掉翎苫,因?yàn)樗哪J(rèn)實(shí)現(xiàn)是空。

注:非原創(chuàng)榨了,不裝逼煎谍,不虛假。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末阻逮,一起剝皮案震驚了整個(gè)濱河市粱快,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌叔扼,老刑警劉巖事哭,帶你破解...
    沈念sama閱讀 211,884評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異瓜富,居然都是意外死亡鳍咱,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,347評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門与柑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來谤辜,“玉大人,你說我怎么就攤上這事价捧〕竽睿” “怎么了?”我有些...
    開封第一講書人閱讀 157,435評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵结蟋,是天一觀的道長(zhǎng)脯倚。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么推正? 我笑而不...
    開封第一講書人閱讀 56,509評(píng)論 1 284
  • 正文 為了忘掉前任恍涂,我火速辦了婚禮,結(jié)果婚禮上植榕,老公的妹妹穿的比我還像新娘再沧。我一直安慰自己,他們只是感情好尊残,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,611評(píng)論 6 386
  • 文/花漫 我一把揭開白布炒瘸。 她就那樣靜靜地躺著,像睡著了一般夜郁。 火紅的嫁衣襯著肌膚如雪什燕。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,837評(píng)論 1 290
  • 那天竞端,我揣著相機(jī)與錄音,去河邊找鬼庙睡。 笑死事富,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的乘陪。 我是一名探鬼主播统台,決...
    沈念sama閱讀 38,987評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼啡邑!你這毒婦竟也來了贱勃?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,730評(píng)論 0 267
  • 序言:老撾萬榮一對(duì)情侶失蹤谤逼,失蹤者是張志新(化名)和其女友劉穎贵扰,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體流部,經(jīng)...
    沈念sama閱讀 44,194評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡戚绕,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,525評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,664評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡工腋,死狀恐怖奏路,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情制妄,我是刑警寧澤,帶...
    沈念sama閱讀 34,334評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站吨凑,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏端盆。R本人自食惡果不足惜怀骤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,944評(píng)論 3 313
  • 文/蒙蒙 一费封、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蒋伦,春花似錦弓摘、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,764評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至研叫,卻和暖如春锤窑,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背嚷炉。 一陣腳步聲響...
    開封第一講書人閱讀 31,997評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工渊啰, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人申屹。 一個(gè)月前我還...
    沈念sama閱讀 46,389評(píng)論 2 360
  • 正文 我出身青樓绘证,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親哗讥。 傳聞我的和親對(duì)象是個(gè)殘疾皇子嚷那,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,554評(píng)論 2 349

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