前言
新開一篇占個位置,記錄一些零碎的知識點靶擦,有些細小的點沒法單獨寫一篇文章腮考,就記在這里面擎淤。不定期更新。
1. 兩個TextView秸仙,一左一右排成一排嘴拢,右邊的保持完整顯示,并緊貼著左邊寂纪,左邊的如果過長席吴,則顯示省略號。
這個需求描述起來可能有點說不清楚捞蛋,我們看一下圖就明白了:一開始以為很簡單孝冒,實現(xiàn)起來還是費了一番功夫去調(diào)試,不多說拟杉,直接上代碼:
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_nick_name"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="1"
android:ellipsize="end"
android:maxLines="1"
android:textSize="14dp" />
<TextView
android:id="@+id/tv_next_trip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
android:text="@string/where_is_your_next_trip"
android:textSize="14dp" />
</LinearLayout>
在使用一段時間后庄涡,發(fā)現(xiàn)這種方法存在bug,在重復(fù)設(shè)置name值時搬设,可能會出現(xiàn)name明明很短卻展示了省略號穴店,或者name后面多了好幾個空格這樣的問題,猜想可能在布局時出了問題拿穴,于是在設(shè)置name后泣洞,請求重新布局,問題得到解決默色,代碼如下:
tvNickName.setText(nickName);
tvNickName.requestLayout(); // 請求重新布局
2. RecyclerView移動指定位置item到頂部
需求的場景是:在聊天頁面球凰,用戶可以下拉加載更多消息,這個時候把請求到的新消息插入到頭部腿宰,調(diào)用adapter.notifyDataSetChanged()就會把最頂部的新消息展示出來呕诉,而我想要的,是保持我刷新之前的item位于頂部吃度,并露出一點點新的消息甩挫,所以我需要將指定位置的item移動到頂部。還是先看一下實際效果吧:
于是我在網(wǎng)上查了一下央碟,大部分的答案都指向一種方法,先用scrollToPosition()方法讓指定元素出現(xiàn)在屏幕內(nèi),然后再通過計算并且用scrollBy()方法進行二次調(diào)整亿虽,使用起來麻煩不說菱涤,或多或少還有些問題。于是我就在想有沒有更加簡便的實現(xiàn)方式洛勉,點進scrollToPosition()的源碼里粘秆,我發(fā)現(xiàn)了一些情況:
/**
* Convenience method to scroll to a certain position.
*
* RecyclerView does not implement scrolling logic, rather forwards the call to
* {@link android.support.v7.widget.RecyclerView.LayoutManager#scrollToPosition(int)}
* @param position Scroll to this adapter position
* @see android.support.v7.widget.RecyclerView.LayoutManager#scrollToPosition(int)
*/
public void scrollToPosition(int position) {
if (mLayoutFrozen) {
return;
}
stopScroll();
if (mLayout == null) {
Log.e(TAG, "Cannot scroll to position a LayoutManager set. " +
"Call setLayoutManager with a non-null argument.");
return;
}
mLayout.scrollToPosition(position);
awakenScrollBars();
}
感情RecyclerView并沒有實現(xiàn)這個方法啊,而是使用了LayoutManager里的scrollToPosition()方法收毫,看到這里攻走,我心里仿佛又有了點兒b數(shù),點開LinearLayoutManager的源碼此再,果然發(fā)現(xiàn)了我想要的東西:
/**
* Scroll to the specified adapter position with the given offset from resolved layout
* start. Resolved layout start depends on {@link #getReverseLayout()},
* {@link ViewCompat#getLayoutDirection(android.view.View)} and {@link #getStackFromEnd()}.
* <p>
* For example, if layout is {@link #VERTICAL} and {@link #getStackFromEnd()} is true, calling
* <code>scrollToPositionWithOffset(10, 20)</code> will layout such that
* <code>item[10]</code>'s bottom is 20 pixels above the RecyclerView's bottom.
* <p>
* Note that scroll position change will not be reflected until the next layout call.
* <p>
* If you are just trying to make a position visible, use {@link #scrollToPosition(int)}.
*
* @param position Index (starting at 0) of the reference item.
* @param offset The distance (in pixels) between the start edge of the item view and
* start edge of the RecyclerView.
* @see #setReverseLayout(boolean)
* @see #scrollToPosition(int)
*/
public void scrollToPositionWithOffset(int position, int offset) {
mPendingScrollPosition = position;
mPendingScrollPositionOffset = offset;
if (mPendingSavedState != null) {
mPendingSavedState.invalidateAnchor();
}
requestLayout();
}
scrollToPositionWithOffset(int position, int offset)昔搂,使用這個方法就可以實現(xiàn)想要的效果。先拿到LinearLayoutManager输拇,再調(diào)用該方法即可:
LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerview.getLayoutManager();
layoutManager.scrollToPositionWithOffset(position, offset);
后來我又想到其實還可以利用RecyclerView倒序列表來實現(xiàn)同樣的效果摘符,不過這個知識點記錄下來以后還是能派上用場的。
3. dp轉(zhuǎn)pixel的三個方法間的區(qū)別
以前需要dp轉(zhuǎn)pixel的時候都是直接使用現(xiàn)成的工具類策吠,今天偶然看到有三個系統(tǒng)方法逛裤,專門用來轉(zhuǎn)換成pixel的,它們是分別是:getDimension() 奴曙、 getDimensionPixelSize() 和 getDimensionPixelOffset别凹。它們的區(qū)別在哪呢?我們來看一下輸出:
getDimension: 44.625
getDimensionPixelSize: 45
getDimensionPixelOffset: 44
同樣的dp值洽糟,轉(zhuǎn)換出來的pixel值卻有所不同。根據(jù)得到的三個值堕战,我們可以猜想它們分別是:原始的float值坤溃、四舍五入的int值、強制轉(zhuǎn)換的int值嘱丢。查看官方文檔后薪介,也驗證了我的猜想。另附上使用方法:
getResources().getDimension(R.dimen.activity_vertical_margin);
getResources().getDimensionPixelSize(R.dimen.activity_vertical_margin);
getResources().getDimensionPixelOffset(R.dimen.activity_vertical_margin);
4. inflate方法參數(shù)的含義
inflate方法有兩參數(shù)和三參數(shù)的重載越驻,我們先來看看兩參數(shù)的方法:
public View inflate(XmlPullParser parser, @Nullable ViewGroup root) {
return inflate(parser, root, root != null);
}
兩參數(shù)的方法其實就是 根據(jù)root是否為空汁政,來決定第三個參數(shù),并且調(diào)用三參數(shù)的方法缀旁,所以我們只需要弄明白三參數(shù)的方法即可:
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot)
三參數(shù)的方法根據(jù)第2记劈、3個參數(shù)傳值的不同,可以分為以下三種情況:
-
root不為null并巍,attachToRoot為true
這種情況下會將resource指定的布局添加到root中目木,添加的過程中resource所指定的的布局的根節(jié)點的各個屬性都是有效的,示例:
LayoutInflater.from(this).inflate(R.layout.view_room_amenity_icon, amenitiesContainer, true);
只需要這樣就可以把view_room_amenity_icon布局添加到amenitiesContainer中懊渡,而不再需要調(diào)用amenitiesContainer.addView(view)了刽射。
-
root不為null军拟,而attachToRoot為false
這種情況下不會將resource所指定的布局添加到root中,但是既然我們不添加到root中誓禁,我們還傳一個root參數(shù)干嘛懈息,直接傳null不就行了嗎?其實這里是有說道的摹恰,我們在開發(fā)的過程中給控件指定了layout_width和layout_height屬性漓拾,這些屬性表示一個控件在容器中的大小,就是說這個控件必須在容器中戒祠,這個屬性才有意義骇两。這就意味著如果我們直接將resource指定的布局加載進來而不給它指定一個父布局,那么它的根節(jié)點的layout_width和layout_height屬性將會失效(因為這個時候它不處于任何容器中姜盈,那么它的根節(jié)點的寬高自然會失效)低千。如果我們想讓resource指定的布局的根節(jié)點有效,又不想讓其處于某一個容器中馏颂,那我們就可以設(shè)置root不為null示血,而attachToRoot為false。示例:
LinearLayout item = (LinearLayout) LayoutInflater.from(this).inflate(R.layout.view_room_amenity_icon, amenitiesContainer, false);
......
amenitiesContainer.addView(item);
我們可以在對item進行一些處理(如設(shè)置內(nèi)部的圖片救拉、文字等)后难审,再將它通過addView方法添加到amenitiesContainer中。
-
root為null
當(dāng)root為null時亿絮,attachToRoot將失去作用告喊,設(shè)置任何值都沒有意義。當(dāng)root為null表示我們不需要將resource所指定的布局添加到任何容器中派昧,同時也表示沒有任何容器來來協(xié)助resource所指定布局的根節(jié)點生成布局參數(shù)黔姜。示例:
LinearLayout item = (LinearLayout) LayoutInflater.from(this).inflate(R.layout.view_room_amenity_icon, amenitiesContainer, false);
amenitiesContainer.addView(item);
item添加到amenitiesContainer中,item的根節(jié)點的布局參數(shù)將會失效蒂萎。
我們最后再看看inflate方法的返回值秆吵,查閱官方文檔后得知:當(dāng)提供了root(root不為空)且attachToRoot為true時,返回root五慈,否則返回resource所指定的布局纳寂。
5. 控件 focusable 和 focusableInTouchMode 屬性的區(qū)別
大多數(shù)控件都可以獲得焦點,如果focusable屬性值為true泻拦,表示可以通過鍵盤(虛擬鍵盤或者物理鍵盤)或者軌跡球?qū)⒔裹c移動到當(dāng)前控件上毙芜,如果該屬性值為false,則無法將焦點移動到當(dāng)前控件聪轿。
只要我們用手觸摸手機屏幕爷肝,便進入了觸摸模式,即TouchMode。在默認(rèn)情況下灯抛,觸摸一個控件雖然可以觸發(fā)該控件的單擊事件金赦,但無法使控件處在焦點狀態(tài)。而設(shè)置focusableInTouchMode可以使控件通過觸摸獲取焦點对嚼。將focusableInTouchMode屬性值設(shè)為true夹抗,當(dāng)觸摸某個控件時,會先將焦點移動到被觸摸的控件上纵竖,然后需要再次觸摸該控件才會響應(yīng)單擊事件漠烧。但是注意,我們需要將focusable屬性值設(shè)為true靡砌,當(dāng)前控件才可能獲得焦點已脓,否則當(dāng)前控件無論使用何種方式都無法獲得焦點。默認(rèn)情況下通殃,Button度液、TextView的focusableInTouchMode屬性都為false,而EditText的focusableInTouchMode屬性為true画舌,因為EditText需要通過觸摸獲取焦點堕担,而另外兩個控件則不需要。
- focusable為true曲聂,不會影響 focusableInTouchMode霹购,如果focusableInTouchMode為false,在TouchMode狀態(tài)下朋腋,依舊無法獲取焦點
- 如果focusable為false齐疙,一定會使focusableInTouchMode為false
相對的
- focusableInTouchMode為false,不會影響focusable
- 如果focusableInTouchMode為true乍丈,一定會使focusable為true
(已親自驗證)
6. git fetch 和 git pull 的區(qū)別
git pull 這條指令的內(nèi)部實現(xiàn)就是把遠程倉庫使用 git fetch 取下來以后再進行 merge 操作剂碴。
7.EditText 隱藏、顯示密碼
在UI驗收的時候轻专,設(shè)計給我提了個bug,說密碼輸入框顯示和隱藏狀態(tài)下提示語的字體不一樣察蹲,我試了一下確實有這個問題请垛,但是只在英文狀態(tài)下會出現(xiàn):
//顯示密碼
etPassword.setInputType(InputType.TYPE_CLASS_TEXT);
//隱藏密碼
etPassword.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
后來在網(wǎng)上查了一下,原來這種方式會將字體設(shè)置為等寬字體(猜測是出于安全考慮亚兄,無法通過密碼的寬度來縮小破解范圍)混稽,而我們的漢字又恰恰是等寬字體,所以只有英文出現(xiàn)了這個問題。努力了一番匈勋,沒有太好的辦法解決這個問題礼旅,索性換了一種實現(xiàn)方式,終于解決了這個問題洽洁。
正確而完美的實現(xiàn)方式
先在xml中設(shè)置EditText的屬性:
android:inputType="textPassword"
再通過代碼改變顯示隱藏狀態(tài):
//顯示密碼
etPassword.setTransformationMethod(HideReturnsTransformationMethod.getInstance());
//隱藏密碼
etPassword.setTransformationMethod(PasswordTransformationMethod.getInstance());
每次改變后痘系,光標(biāo)會跑到最前面,我們需要手動將光標(biāo)置于內(nèi)容的末端:
//將光標(biāo)置于末端
etPassword.setSelection(etPassword.getText().length());
8. clipToPadding和clipChildren的使用
clipToPadding:
Defines whether the ViewGroup will clip its children and resize (but not clip) any EdgeEffect to its padding, if padding is not zero. This property is set to true by default.
大概翻譯一下:當(dāng)padding不為0時饿自,這個屬性決定了ViewGroup是否裁剪自己padding內(nèi)的子View汰翠。默認(rèn)值為true,也就是默認(rèn)會裁剪自己padding內(nèi)的子View昭雌。
也可以理解為:ViewGroup的繪制區(qū)域是否在padding內(nèi)复唤。
比較巧妙的一個用法是,在RecyclerView中:
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="8dp"
android:clipToPadding="false" />
這樣設(shè)置烛卧,可以讓RecyclerView在第一次展示時頂部留出8dp的空白佛纫,如果往上滑動,Item可以填充到頂部的padding內(nèi)唱星。
clipChildren:
Defines whether a child is limited to draw inside of its bounds or not. This is useful with animations that scale the size of the children to more than 100% for instance. In such a case, this property should be set to false to allow the children to draw outside of their bounds. The default value of this property is true.
大概翻譯一下:是否將子View的繪制限制在父View的邊界內(nèi)雳旅。這個屬性可以用于縮放動畫的例子,將這個屬性設(shè)置為false间聊,以允許子View的繪制超出父View的邊界攒盈。這個屬性默認(rèn)值為true。
官方文檔已經(jīng)說的十分清楚了哎榴,唯一需要注意的是:使用該屬性時型豁,需要將android:clipChildren="false"放在布局的根節(jié)點才會生效。
9.maxLength和maxEms的區(qū)別
maxLength:
Set an input filter to constrain the text length to the specified number.
翻譯:通過設(shè)置一個InputFilter來限制文本長度為一個指定的值尚蝌。
補充說明:
- 漢字迎变、英文字母、標(biāo)點以及空格都只占用一個長度
- 由于對文本長度進行了截取飘言,所以不會顯示省略號
maxEms:
Makes the TextView be at most this many ems wide.
翻譯:設(shè)置TextView的最大寬度為N個em的寬度衣形。
ems其實是em單位的復(fù)數(shù)形式,em單位可以參見維基百科(科學(xué)上網(wǎng))
維基百科中的解釋并不明確姿鸿,Android官方文檔中也沒有相關(guān)說明
但是筆者通過試驗谆吴,排除掉了一種解釋:
em是一個印刷排版的單位,em字面意思為:equal M(和M字符一致的寬度為一個單位)簡稱em
// 后面已經(jīng)證明這個解釋在Android中并不適用
我們來做一下測試:
設(shè)置android:maxEms="5" 然后填入一些內(nèi)容:
內(nèi)容 | 最大個數(shù) |
---|---|
數(shù)字 | 10 |
字母a | 10 |
字母i | 23 |
字母M | 6 |
英文逗號 | 31 |
漢字 | 5 |
設(shè)置android:maxEms="10" 然后填入一些內(nèi)容:
內(nèi)容 | 最大 個數(shù) |
---|---|
數(shù)字 | 21 |
字母a | 21 |
字母i | 47 |
字母M | 13 |
英文逗號 | 63 |
漢字 | 11 |
我只能說苛预,這是一個并不十分精確的單位...
個人覺得最靠譜的一種解釋是(僅供參考):
em 等于當(dāng)前的字體尺寸句狼,如果字體大小是16px,那么1em=16px热某。
這其實是css中關(guān)于em單位的解釋腻菇,猜測安卓應(yīng)該也差不多胳螟。
補充說明:
- maxEms只對TextView生效,如果要限制EditText的文本長度筹吐,應(yīng)該使用maxLength
- maxEms是對TextView的最大寬度做了限制糖耸,而不是對文本內(nèi)容進行截取,所以maxEms是支持省略號的
- maxEms只在 android:layout_width="wrap_content" 時生效
10.關(guān)于18 : 9屏幕開屏圖的適配
如今全面屏盛行骏令,屏幕比例大都是18 : 9(好像只有三星是18.5 : 9)蔬捷,適配起來也不是太困難,只需要在AndroidManifest文件中加入如下代碼即可解決大部分問題:
<meta-data
android:name="android.max_aspect"
android:value="2.1"/>
平常使用的第三方圖片加載庫也都支持各種縮放模式榔袋,但是唯獨遺漏了一個地方周拐,那就是開屏圖,可以看到在18 : 9的手機上凰兑,開屏圖會拉伸變形:
究其原因,是在開屏圖的實現(xiàn)方式上吏够。我們實現(xiàn)應(yīng)用的開屏圖勾给,一個比較簡單常見的方法就是,給LaunchActivity設(shè)置一個主題锅知,然后在主題中設(shè)置背景圖:
<activity
android:name=".view.activity.LaunchActivity"
android:screenOrientation="portrait"
android:theme="@style/LaunchTheme">
<style name="LaunchTheme" parent="AppTheme">
<item name="android:windowBackground">@mipmap/c_boot_bg</item>
<item name="android:windowFullscreen">true</item>
</style>
這種方式實現(xiàn)起來很方便播急,但是弊端是這種方式設(shè)置的圖片,不支持各種縮放模式售睹,我們只能在不同的資源目錄下放上相應(yīng)大小的圖片桩警,讓系統(tǒng)去自動選取最合適的圖片。
于是昌妹,當(dāng)開屏圖被拉伸后捶枢,我就在資源文件目錄下新建了一個mipmap-xxhdpi-2160x1080目錄,然后放入相應(yīng)的圖片飞崖,打開模擬器新建了一個2160x1080 5.99寸屏幕的設(shè)備(公司不給配測試機烂叔,我基本都在模擬器上搞)試了一下沒問題,但是在CTO的手機上(也是18 : 9的屏幕)卻還是被拉伸了固歪,說明我新加的圖片資源沒有匹配上蒜鸡,這就奇怪了,CTO手機的分辨率和尺寸跟我的模擬器一模一樣牢裳,為什么一個能適配术瓮,一個不能呢?
后來我找到了問題的原因:屏幕下方的虛擬按鍵
由于全面屏手機追求窄邊框贰健,正面大都是沒有按鈕的,所以必須啟用虛擬按鍵恬汁,而這個虛擬按鍵是要占用屏幕空間的伶椿。我們先來看一看系統(tǒng)是如何匹配資源目錄的辜伟,這里我就不做實驗了,直接上結(jié)論:
dpi范圍 | 密度 | 手機分辨率 |
---|---|---|
0dpi ~ 120dpi | ldpi | 320 x 240 |
120dpi ~ 160dpi | mdpi | 480 x 320 |
160dpi ~ 240dpi | hdpi | 800 x 480 |
240dpi ~ 320dpi | xhdpi | 1280 x 720 |
320dpi ~ 480dpi | xxhdpi | 1920 x 1080 |
480dpi ~ 640dpi | xxxhdpi | 2560 x 1440 |
以下內(nèi)容引用自:http://blog.csdn.net/cloud_castle/article/details/52313858
如果當(dāng)前為xhdpi設(shè)備脊另,并且只有以下幾個目錄导狡,則drawable的尋找順序為:
xhdpi -> xxhdpi -> xxxhdpi(如果沒有更高的了) -> nodpi(如果有的話) -> hdpi -> mdpi,如果在xxhdpi中找到目標(biāo)圖片偎痛,則壓縮2/3來使用旱捧,如果在mdpi中找到圖片,則放大2倍來使用踩麦。
如果當(dāng)前設(shè)備為xhdpi-1280x800枚赡,當(dāng)前目錄有values-xhdpi-1280x800,values-xhdpi-1280x960谓谦,values-xhdpi-1280x720贫橙,則尋找順序為:
values-xhdpi-1280x800 -> values-xhdpi-1280x720 -> values-xhdpi。
只向等于或低于自己分辨率的目錄下尋找反粥,直到values-xhdpi卢肃,如果依然沒有找到,按照之前的順序繼續(xù)進行才顿。(hdpi-1280x800 -> hdpi-1280x720 -> hdpi -> …)
結(jié)合上面的結(jié)論莫湘,當(dāng)全面屏手機開啟虛擬按鍵后,扣除掉虛擬按鍵占用的尺寸(在原生系統(tǒng)郑气、5.99寸屏幕幅垮、2160x1080的手機上,虛擬按鍵高度為144px)屏幕尺寸約為2016x1080 竣贪,注意現(xiàn)在是2016x1080军洼,之前我建的資源目錄是2160x1080,根據(jù)上面的匹配規(guī)則演怎,是不會去匹配比自己分辨率高的資源目錄的匕争,所以才出現(xiàn)了之前的適配問題。
所以爷耀,我們只需要再建一個mipmap-xxhdpi-2016x1080的目錄甘桑,問題就得到解決了。通過這個問題讓我對資源目錄的匹配規(guī)則也有了更深入的了解歹叮。
11.使用getIdentifier()方法獲取資源
/**
* Return a resource identifier for the given resource name. A fully
* qualified resource name is of the form "package:type/entry". The first
* two components (package and type) are optional if defType and
* defPackage, respectively, are specified here.
*
* <p>Note: use of this function is discouraged. It is much more
* efficient to retrieve resources by identifier than by name.
*
* @param name The name of the desired resource.
* @param defType Optional default resource type to find, if "type/" is
* not included in the name. Can be null to require an
* explicit type.
* @param defPackage Optional default package to find, if "package:" is
* not included in the name. Can be null to require an
* explicit package.
*
* @return int The associated resource identifier. Returns 0 if no such
* resource was found. (0 is not a valid resource ID.)
*/
public int getIdentifier(String name, String defType, String defPackage) {
return mResourcesImpl.getIdentifier(name, defType, defPackage);
}
這個方法雖然在性能上差一些跑杭,但有時候用起來真的很省事,舉個例子:
當(dāng)服務(wù)端返回一個枚舉值咆耿,并且這個枚舉值不能直接用來展示德谅,你得在strings.xml文件里找到相應(yīng)的值用來做展示。使用如下的方式萨螺,可以讓代碼邏輯變得簡單窄做,而不用去寫一堆 switch 代碼了:
//data為服務(wù)端返回的數(shù)據(jù)
int resourceID = context.getResources().getIdentifier(data.getLanguage(), "string", context.getPackageName());
tvLangeage.setText(context.getString(resourceID));
12.SharedPreferences 中 commit() 和 apply() 方法的區(qū)別
commit() 和apply() 雖然都是原子操作愧驱,但是原子的操作不同。
- commit() 方法是原子操作提交到數(shù)據(jù)庫椭盏,所以從提交數(shù)據(jù)到存入disk都是同步過程组砚,中間不可打斷,有返回值掏颊。
- apply() 方法的原子操作是原子提交到內(nèi)存中糟红,而非數(shù)據(jù)庫,所以在提交到內(nèi)存中時不可打斷乌叶,之后再異步提交到數(shù)據(jù)庫中盆偿,因此沒有相應(yīng)的返回值。
所有commit() 提交都是同步過程枉昏,效率會比apply() 異步提交的速度慢陈肛,但是apply() 沒有返回值,永遠無法知道存儲是否成功兄裂。
結(jié)論:在不關(guān)心提交結(jié)果是否成功并且沒有后續(xù)操作的情況下句旱,優(yōu)先考慮apply() 方法。
13.onAttachedToWindow() 和 onDetachedFromWindow()
View里的:
onAttachedToWindow() 是在第一次 onDraw() 前調(diào)用晰奖,可以進行一些初始化操作
onDetachedFromWindow() 可以在這個方法做一些收尾工作
14.onDraw() 和 dispatchDraw()
- 自定義一個view時谈撒,重寫onDraw。
調(diào)用view.invalidate(),會觸發(fā)onDraw和computeScroll()匾南。前提是該view被附加在當(dāng)前窗口上
view.postInvalidate(); //是在非UI線程上調(diào)用的
- 自定義一個ViewGroup啃匿,重寫onDraw。
onDraw可能不會被調(diào)用蛆楞,原因是需要先設(shè)置一個背景(顏色或圖)溯乒。
表示這個group有東西需要繪制了,才會觸發(fā)draw豹爹,之后是onDraw裆悄。
因此,一般直接重寫dispatchDraw來繪制viewGroup