就是NavigationView的內部實現發生了改變,它在23.1.0版本以前內部實現是ListView實現的,而在23.1.0(包括這個版本)以後改成由RecyclerView實現,在通常咱們使用時候並不會發生什麼異常,而咱們若是須要添加一個headerView的時候,這時候就須要注意了,若是咱們須要獲取headerView裏面的控件的話,按以前的作法咱們只須要直接findViewById()或者經過navigationView.findViewById()就能獲取到並使用,而在23.1.0版本以後,因爲內部實現發生了改變,此時若是經過findViewById()或者經過navigationView.findViewById()獲取headerView裏面的控件的話,則會報NullPointerException
空指針異常,說明在23.1.0版本以後按這樣的方法並不能獲取到headerView內控件的實例。java
那麼咱們就來看看NavigationView源碼,來看看它的內部實現究竟是不是改變了呢?
我找來了兩個版本的Design包:分別爲23.0.1版本和23.1.0版本。
咱們先來看看舊版本的(23.0.1)NavigationView的源碼實現:
貼幾個主要的,經過一層一層查看,咱們發現了導航欄菜單的實現類NavigationMenuView ,它繼承於ListViewandroid
1
|
public
class
NavigationMenuView
extends
ListView
implements
MenuView {...}
|
而23.1.0版本改變了這個實現,採用RecyclerView實現:api
1
|
public
class
NavigationMenuView
extends
RecyclerView
implements
MenuView {...}
|
在23.1.0之後正確作法是不在xml佈局中addHeaderLayout,而是在代碼中經過inflateHeaderView()添加,這個方法會返回當前inflate的View實例,經過它咱們能夠找到headerView內的控件:app
1
2
3
4
5
6
7
8
|
View headerView = mNavigationView.inflateHeaderView(R.layout.header);
mHeaderButton = (Button) headerView.findViewById(R.id.btn_header);
mHeaderButton.setOnClickListener(
new
View.OnClickListener() {
@Override
public
void
onClick(View v) {
Toast.makeText(MainActivity.
this
,
"click button!"
, Toast.LENGTH_SHORT).show();
}
});
|
平時咱們使用EditText用來寫入長文本時,一般會在右下角顯示一個文本,用來顯示當前EditText目前有多少字符了,之前咱們實現這個功能經過都是用TextWatcher來監聽文本的變化來計算,而新版本的Design包爲TextInputLayout添加了這個功能,咱們只須要在xml中設置ide
1
|
app:counterEnabled=
"true"
|
來開啓計數功能,它默認是不開啓的,或在代碼中設置:佈局
1
2
|
TextInputLayout textInputLayout = (TextInputLayout) findViewById(R.id.til);
textInputLayout.setCounterEnabled(
true
);
|
這樣咱們的EditText就有計數功能了,效果爲:
固然咱們還能夠設置最大字數限制:
在xml中設置:字體
1
|
app:counterMaxLength=
"100"
|
在代碼中設置:動畫
1
2
3
|
TextInputLayout textInputLayout = (TextInputLayout) findViewById(R.id.til);
textInputLayout.setCounterEnabled(
true
);
textInputLayout.setCounterMaxLength(
100
);
|
顯然若是須要設置最大的字數,確定是須要先開啓計數功能,設置counterEnabled爲true
效果爲:this
固然這個最大字數的限制僅僅只是個提示做用,意思就是咱們輸入的字符數量達到這個限額的時候,還能夠繼續輸入,如:
因此,禁止輸入的邏輯須要咱們本身來實現,咱們能夠經過結合TextWatcher來實現限制最大字數的邏輯,經過判斷當達到最大限額數量時候禁止繼續輸入spa
假如你若是想同時使用錯誤提示和計數這兩個功能,那麼固然也能夠,只不過計數就放到了右下角了,效果如圖:
固然還有其它的一些api,雖然並非新增的,順便也一塊兒說明一下:
app:hintAnimationEnabled=」true」 —設置hint過分到左上角顯示是否使用動畫過分,默認爲true,若是設爲false則過分很是生硬
app:hintTextAppearance=」」 —設置hint的字體樣式,值爲一個style
app:errorTextAppearance=」」 —設置錯誤提示的字體樣式
app:counterTextAppearance=」」 —設置計數字體的樣式
app:counterOverflowTextAppearance=」」 —這個api比較有趣,這個觸發的時機是達到最大輸入字數時候,這時計數的字體樣式會變爲這裏設置的樣式
下面就演示app:counterOverflowTextAppearance這個api的效果,好比咱們能夠爲它設置當字數達到上限的時候,計數字體就變大和顯示另一種顏色:
這樣就很是明顯的能夠看到區別了。
按照Google給的解釋來講,這個Flag主要是爲了確保滾動結束時,View將不會以滾動的中間狀態顯示,即不會讓滾動時未完成的部分顯示出來,相反,它會滾動到最近的邊緣位置,使其以徹底可見或滾動徹底的狀態顯示在屏幕上,這段話可能難以聯想到這種效果,那麼就以實際效果來看看設置這個snap標誌和不設置的區別:
爲了代碼簡短,我只截取了AppBarLayout的代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
<
android.support.design.widget.AppBarLayout
android:layout_width
=
"match_parent"
android:layout_height
=
"256dp"
android:theme
=
"@style/AppTheme.AppBarOverlay"
>
<
android.support.design.widget.CollapsingToolbarLayout
android:layout_width
=
"match_parent"
android:layout_height
=
"wrap_content"
app:contentScrim
=
"@color/colorPrimary"
app:layout_scrollFlags
=
"scroll|exitUntilCollapsed|snap"
>
<
ImageView
android:layout_width
=
"match_parent"
android:layout_height
=
"match_parent"
android:scaleType
=
"centerCrop"
android:src
=
"@mipmap/bg"
app:layout_collapseMode
=
"parallax"
app:layout_collapseParallaxMultiplier
=
"0.7"
/>
<
android.support.v7.widget.Toolbar
android:id
=
"@+id/toolbar"
android:layout_width
=
"match_parent"
android:layout_height
=
"?attr/actionBarSize"
app:layout_collapseMode
=
"pin"
app:popupTheme
=
"@style/AppTheme.PopupOverlay"
/>
</
android.support.design.widget.CollapsingToolbarLayout
>
</
android.support.design.widget.AppBarLayout
>
|
效果爲:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
<
android.support.design.widget.AppBarLayout
android:layout_width
=
"match_parent"
android:layout_height
=
"256dp"
android:theme
=
"@style/AppTheme.AppBarOverlay"
>
<
android.support.design.widget.CollapsingToolbarLayout
android:layout_width
=
"match_parent"
android:layout_height
=
"wrap_content"
app:contentScrim
=
"@color/colorPrimary"
app:layout_scrollFlags
=
"scroll|exitUntilCollapsed"
>
<
ImageView
android:layout_width
=
"match_parent"
android:layout_height
=
"match_parent"
android:scaleType
=
"centerCrop"
android:src
=
"@mipmap/bg"
app:layout_collapseMode
=
"parallax"
app:layout_collapseParallaxMultiplier
=
"0.7"
/>
<
android.support.v7.widget.Toolbar
android:id
=
"@+id/toolbar"
android:layout_width
=
"match_parent"
android:layout_height
=
"?attr/actionBarSize"
app:layout_collapseMode
=
"pin"
app:popupTheme
=
"@style/AppTheme.PopupOverlay"
/>
</
android.support.design.widget.CollapsingToolbarLayout
>
</
android.support.design.widget.AppBarLayout
>
|
效果爲:
根據上面兩個效果的對比,很明顯的就能夠發現,snap標誌主要的做用就是不會讓滾動時未完成的部分顯示出來,效果圖中加了snap標誌的很明顯,當往上滾動一點距離的時候,它會彈回來,而滾動到快要到結束狀態的時候,則是滾動到最近的邊緣位置,使其隱藏起來,此時往下滑動一下,Toolbar就顯示出來了,而不加snap標誌的效果,則是能夠顯示滾動時未完成的部分。
AppBarLayout如今容許用戶滾動從AppBarLayout內,而不是隻能從滾動視圖內滾動 ,另外能夠經過添加DragCallback這種行爲能夠控制是否能夠從AppBarLayout內滾動
爲了更好的理解,來兩張效果圖吧:
23.1.0版本:
23.0.1之前版本:
爲了有23.0.1之前版本的效果,我特地找來了我一個在23.0.1之前版本上寫的demo來演示
從這兩個效果中就能夠看出,在舊版本上,咱們在AppBarLayout中進行滾動時,發現不能滾動,而在新版本23.1.0上滾動時,卻能夠在AppBarLayout內進行滾動,這就是新版本的改進
經過使用app:actionLayout或MenuItemCompat.setActionView()可以爲抽屜的菜單項添加自定義視圖,這使得NavigationView獲得了更好的擴展性
來看一張效果圖:
在menu.xml中設置:
1
2
3
4
5
6
7
8
9
10
11
|
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<
group
android:checkableBehavior
=
"single"
>
<
item
android:icon
=
"@mipmap/ic_launcher"
android:title
=
"one"
app:actionLayout
=
"@layout/action"
/>
...
</
group
>
</
menu
>
|
或者在代碼中設置:
1
2
|
MenuItem menuItem = mNavigationView.getMenu().getItem(
1
);
MenuItemCompat.setActionView(menuItem,R.layout.action);
|
能夠看到菜單項在後面添加了自定義的視圖,這更能方便咱們擴展功能,就好比博主本人前段時間寫的簡郵App,菜單項都是一些收件箱、發件箱、草稿箱等,而這些正好須要有提醒郵件數量的功能,以前因爲NavigationView擴展性太差,致使這個功能沒有加入,而在23.1.0的版本上,對NavigationView的擴展性作了改進,看到圖中第二個item項的藍色區域了吧,這個區域就是隨便咱們怎麼定製視圖,從而使得NavigationView和一些第三方的抽屜能夠媲美了
百分比佈局庫按個人理解就是:
百分比佈局庫是以父ViewGroup的寬高爲基礎,根據子View(ViewGroup)所設置的百分比來動態設置子View(ViewGroup)的寬高
以往百分比佈局只支持分別設置寬和高的百分比來設置的,而此次新增的功能,是能夠經過設置寬高比來設置了,經過設置只有一個單一的寬度或高度和使用app:aspectRatio設置寬高比,那麼PercentFrameLayout或PercentRelativeLayout會自動調整其它尺寸
Palette能夠從圖像中獲取顏色,如今新增了一個方法setRegion(),支持從一個位圖的一個特定區域提取
經過使用ItemAnimator新增的canReuseUpdatedViewHolder()方法,你能夠選擇重用現有ViewHolder,使得其支持Item的內容動畫
以前咱們定義RecyclerView的Item動畫每每是經過繼承RecyclerView.ItemAnimator來實現的,而新版本則推薦咱們繼承於RecyclerView.SimpleItemAnimator類來實現咱們的動畫,由於這個類封裝新的api同時也提供了舊的api的支持,並且有些方法已經從這個版本中移除了,好比之前咱們是經過recyclerView.getItemAnimator().setSupportsChangeAnimations(false)這個方法來設置Item的內容改變時的動畫支持,而新版本中這個方法將再也不有效,而是須要經過下面的代碼設置:
1
2
3
4
|
ItemAnimator animator = recyclerView.getItemAnimator();
if
(animator
instanceof
SimpleItemAnimator) {
((SimpleItemAnimator) animator).setSupportsChangeAnimations(
false
);
}
|