就是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
);
}
|