Android下的沉浸式状态栏+折叠TitleBar(CoordinatorLayout+CollapsingToolbarLayout)+ViewPager切换实现

Android下的沉浸式状态栏+折叠TitleBar(CoordinatorLayout+CollapsingToolbarLayout)+ViewPager切换实现


最终效果以及过程当中出现的问题以下:(简单解决在ViewPager+Fragment的组合中实现该效果时出现有页面视图偏移一个状态栏高度问题)

                                                                                                                 
           
 
一:实现沉浸式的状态栏
    沉浸式状态栏的实现是从android版本KITKAT开始,从KITKAT开始谷歌开始支持状态栏的背景色设置为透明,但在Lollipop版本(5.0)以后概念有所不一样。
 设置状态栏透明的步骤:

1.实现当前activity的theme样式为无Tilte的,不然会有系统的titlebar显示在屏幕上方影响效果。
    即在Style.xml文件里面自定义一个主题样式:AppNoTitleTheme
    主要添加条目属性字段:windowNoTitletrue。并把要实现沉浸样式的Activity或整个应用的theme设置为该style 
     
     
     
     
android:theme="@style/AppNoTitleTheme"
AppNoTitleTheme 对应以下:
     
     
     
     
<style name="AppNoTitleTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <!-- Customize your theme here. --> <item name="colorPrimary">@color/colorPrimary</item> <item name="windowNoTitle">true</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> </style>
 
固然也能够直接引用系统预约义的 样式:
     
     
     
     
android:theme="@style/Theme.AppCompat.Light.NoActionBar"
2.是实现状态栏的背景为透明背景,实现能够看到状态栏下方的视图内容,该实现通常在Activity中代码添加FLAG实现
   
   
   
   
  1. //此FLAG可以使状态栏透明,且当前视图在绘制时,从屏幕顶端开始即top = 0开始绘制,这也是实现沉浸效果的基础
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { this.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); this.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);//可不加 } setContentView(R.layout.activity_main);//在此以前添加以上FLAG initView(); initEvent(); }
tip:该FLAG须要在Activity 的setContentView(R.layout.activity_main)方法以前添加
加上此段代码以后在KITKAT及之上的版本便可实现状态栏透明,而且当前要展现的视图view从top为0的地方开始绘制。

至此状态栏已经实现透明,且当前的Activity视图已经能够延伸到状态栏下方
效果以下:


该效果实现以后有以下问题:此时标题会随整个试图的延伸一块儿延伸到状态栏的下方,导致状态栏遮挡了部分自定义的标题
解决该问题,也很简单android原生已经提供了相关实现:
要想实现标题栏不被遮挡,能够在在根节点的布局文件中添加fitsSystemWindows clipToPadding的标志位便可。代码以下:
   
   
   
   
<RelativeLayout android:fitsSystemWindows="true" android:clipToPadding="false" android:layout_width="match_parent" android:layout_height="match_parent"></RelativeLayout>

fitsSystemWindows:该属性值表示系统布局过程当中是否会为该view自动适应系统窗口(状态栏/导航栏),为true时系统会在设置了该属性的view的布局中,自动为其添加状态栏的高度的paddingtop值,使其实际布内容不被状态栏遮挡;为false时,则不会为其添加该padding值。默认不设的值为false。

clipToPadding:该属性值为在绘制的时候是否能够在其padding区域内绘制。当为true时能够在其padding区域内绘制,不然不可绘制。
》》但此时效果以下:虽然视图沉了一个状态栏的高度,可是同时状态栏的颜色是透明的,显示出了原有的底色。

此时,须要解决的是让状态栏下的颜色为自定义的,在版本为Lollipop及以后s状态栏能够设置背景色,可是KITKAT版本并无此方法,这也是KITKAT只是设置状态栏背景为透明是相关的。因此KITKAT版本相比Lollipop及更高版本的沉浸实现是有必定差异。对此经常使用的解决方法就是
再也不添加fitSystemwindows属性,而是手动添加一个占位布局,设置其高度为statusbar的高度,背景为设置为本身想要的颜色便可。

进一步,若是要实现底层背景是整张图片,并以该图片为背景色,须要其整个延伸至状态栏下方,则可作以下布局,一样在自定义的titlebar的布局上添加占位控件。设置其高度,同时设置其颜色为透明便可。
   
   
   
   
  1.                        
<RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/textdemo_image" android:src="@drawable/bg3" android:layout_width="match_parent" android:layout_height="match_parent" /> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical">                         <!-- textdemo_titleholderview 此控件为占位控件设置其高度为状态栏的高度-->     <View     android:id="@+id/textdemo_titleholderview"     android:layout_width="match_parent"     android:layout_height="0dp" />                         <!-- titlebar_view此控件为自定义的标题栏titlebar-->     <include layout="@layout/titlebar_view"></include> <View android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <include layout="@layout/line_mode_view"></include> <include layout="@layout/line_mode_view"></include> </LinearLayout> </LinearLayout> </RelativeLayout>
占位控件代码实现以下:
   
   
   
   
  1. titlebarHolder为添加的顶部的(标题栏上方)占位控件
ViewGroup.LayoutParams layoutParams = titlebarHolder.getLayoutParams();// layoutParams.height = getStatueBarHeight(); titlebarHolder.setLayoutParams(layoutParams); titlebarHolder.setBackgroundColor(Color.TRANSPARENT);//此处也可设置自定义的颜色,设置为透明则会直接看到底层的图片
》》》背景为整张图片的最终效果:

 
也可参考此篇博客:android状态栏总结

========至此已经完整作到了沉浸式页面的简单实现=========

二.下面将要实现沉浸效果+折叠TitleBar样式单页面的实现

效果以下:

布局文件以下:须要添加

 xmlns:app="http://schemas.android.com/apk/res-auto"//以便引用其余包下定义的属性值, e.g. app:layout_scrollFlags="
   
   
   
   
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent"> <!--CoordinatorLayout:协调布局 该实例中能够协调子View的滑动事件效果,该实例中有两个子View 1.AppBarLayout:用来包括CollapsingToolbarLayout(折叠布局),主要使用该AppBarLayout,已有的android.support.design.widget.AppBarLayout$ScrollingViewBehavior 2.RecyclerView:该View经过设置app:layout_behavior="@string/appbar_scrolling_view_behavior"属性,直接与AppBarLayout,相关联。 ps:由于CoordinatorLayout处理的是联动效果,通常须要一个可滑动操做的空间,通常可用的有(RecyclerView4包中的NestedScrollView),可是(ListView)不可用 pps:总体联动实现是,先经过layout_behavior实现该RecyclerViewAppBarLayout的联动。而后是CollapsingToolbarLayout内部的效果,经过设置其app:layout_scrollFlags android:minHeight以及子viewapp:layout_collapseMode="pin"实现。 --> <android.support.design.widget.CoordinatorLayout android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="match_parent"> <!-- CollapsingToolbarLayout:折叠布局视图继承自Framlayout,全部子view默认从左上角开始 该实例中定义了两个子View,其中的 1.RelativeLayout:充当整个CollapsingToolbarLayout的可滑动布局,跟随滑动事件一块儿滑动 2.LinearLayout:充当titlebar使用,设置属性app:layout_collapseMode="pin"使其位置固定不动 ps:可使用ToolBar代替上面的的LinearLayout,可是此时CollapsingToolbarLayoutminHeight,无效会自动匹配该Toolbar的高度, 且该Toolbar不太好定义样式。 --> <android.support.design.widget.CollapsingToolbarLayout android:id="@+id/collapsingToolbarLayout" android:layout_width="match_parent" android:layout_height="match_parent" android:minHeight="200dp" app:layout_scrollFlags="scroll|snap|exitUntilCollapsed"> <!--该RelativeLayout定义了总体的可折叠CollapsingToolbarLayout的底层布局 有总体的背景图片以ImageView引入,设置其android:scaleType="centerCrop"防止背景变形 其余为所须要的自定义的布局 --> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"> <!--总体的折叠视图背景图片--> <ImageView android:id="@+id/textdemo_image" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" android:src="@drawable/bg3" /> <!-- 本身所需的要跟随滚动折叠的布局试图--> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <View android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <!--简单的文字布局--> <include layout="@layout/line_mode_view"></include> <include layout="@layout/line_mode_view"></include> </LinearLayout> </LinearLayout> </RelativeLayout> <!--充当titleBar的布局--> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" app:layout_collapseMode="pin"> <!--占位控件,用来使下面的布局偏移到状态栏之下,具体高度代码设置--> <View android:id="@+id/textdemo_titleholderview" android:layout_width="match_parent" android:layout_height="0dp" /> <!--实际的TitleBar布局文件--> <include layout="@layout/titlebar_view"></include> </LinearLayout> </android.support.design.widget.CollapsingToolbarLayout> </android.support.design.widget.AppBarLayout> <android.support.v7.widget.RecyclerView android:id="@+id/textdemo_recyclerview" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior"> </android.support.v7.widget.RecyclerView> </android.support.design.widget.CoordinatorLayout></LinearLayout>
布局层级关系以下:


对应该Acticity的代码以下:
   
   
   
   
  1. bug相关解决代码
public class MainActivity extends AppCompatActivity { private RecyclerView recyclerview; private LinearLayout titlebar; private View titlebarHolder; private ImageView textdemo_image; private CollapsingToolbarLayout collapsingToolbarLayout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { this.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);//沉浸式状态栏实现的前提 this.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);//可不加 } else { } setContentView(R.layout.activity_main); initView(); initEvent(); } private void initView() { recyclerview = (RecyclerView) findViewById(R.id.textdemo_recyclerview); titlebar = (LinearLayout) findViewById(R.id.textdemo_titlebar); titlebarHolder = findViewById(R.id.textdemo_titleholderview); textdemo_image = (ImageView) findViewById(R.id.textdemo_image); collapsingToolbarLayout = (CollapsingToolbarLayout) findViewById(R.id.collapsingToolbarLayout); } private void initEvent() { LinearLayoutManager manager = new LinearLayoutManager(getApplicationContext()); textdemo_image.setScaleType(ImageView.ScaleType.CENTER_CROP); ViewGroup.LayoutParams layoutParams = titlebarHolder.getLayoutParams(); layoutParams.height = getStatueBarHeight(); titlebarHolder.setLayoutParams(layoutParams); RecyclerView.Adapter adapter = new MyAdapter(); recyclerview.setLayoutManager(manager); recyclerview.setAdapter(adapter);        //fitSystemWindow(); } //private void fitSystemWindow() { // // ViewCompat.setOnApplyWindowInsetsListener(collapsingToolbarLayout, new OnApplyWindowInsetsListener() { // @Override // public WindowInsetsCompat onApplyWindowInsets(View v, WindowInsetsCompat insets) { // insets.replaceSystemWindowInsets(0, 0, 0, 0);    // return insets.consumeSystemWindowInsets(); // return insets; // } // }); //} private int getStatueBarHeight() {//拿取状态栏的高度 int identifier = getResources().getIdentifier("status_bar_height", "dimen", "android"); if (identifier > 0) { return (int) getResources().getDimension(identifier); } return 0; } class MyAdapter extends RecyclerView.Adapter { @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { return new MyViewholder(new TextView(getApplicationContext())); } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { ((MyViewholder) holder).updateData("我是模拟条目文本:::::" + position); } @Override public int getItemCount() { return 50; } } class MyViewholder extends RecyclerView.ViewHolder { public MyViewholder(View itemView) { super(itemView); } public void updateData(String str) { ((TextView) itemView).setText(str); } }}

首先要用到的控件有:1.CoordinatorLayout 2.AppBarLayout  3.CollapsingToolbarLayout 4.可滑动的控件RecyclerView
如下是这几个控件的简单介绍,可对比上方布局中的代码查看:

1.CoordinatorLayout:Design包下的协调布局,简单说就是一个能够协调其子view之间动做 (通常是滑动操做) 的一个总的Layout,继承自GroupLayout,能够经过定义可滑动子view的行为 layout_behavior 来实现与其余相关子view的行为互动。

2.AppBarLayout,Design包下的继承自LinearLayout,使用该布局是由于CoordinatorLayout子view的layout_behavior中有已经预约义的与AppBarLayout协调互动的behavior: android.support.design.widget.AppBarLayout$ScrollingViewBehavior,该联动效果已能知足基本需求(该layout_behavior能够自定义)。

3.CollapsingToolbarLayout ,可折叠的toolbar。就是能够拉伸和折叠的toolbar布局。该布局中须要声明的属性有:
  • == 》滑动时候的行为:app:layout_collapseMode="pin",设置相关view的行为模式(也可设置CollapsingToolbarLayout 的子view
  •     pin-当滑动时,在CollapsingToolbarLayout 控件可见时,其一直会位于布局位置,不随其余view一块滑动(通常给子View中充当toolbar的布局添加该属性)
  •     parallax -设置为这个模式时,在滑动中CollapsingToolbarLayout中的该View(好比ImageView)也能够同时滚动,实现视差滚动效果,一般和layout_collapseParallaxMultiplier(设置视差因子)搭配使用。

  • ==》视差因子:layout_collapseParallaxMultiplier:会在滚动中与相关联动的view一块儿滚动,但有视差效果,取值从0-1表示,滑动结束时,联动控件之间相互重叠的比例

  • ==》对什么动做响应,何时响应:该属性有标志位决定:app:layout_scrollFlags="scroll|exitUntilCollapsed" 
  • scroll - 想滚动就必须设置这个(也能够说是设置其对滚动事件)
  • enterAlways - 实现quick return效果, 当向下移动时,当即显示该View(即初始时该View为所有折叠位于屏幕以外,当下拉动做时该控件会首先作出反应,直接显示出该view)
  • enterAlwaysCollapsed - 当你的View已经设置minHeight属性又使用此标志时,你的View只能以最小高度进入,只有当滚动视图到达顶部时才扩大到完整高度。(此属性值与上面属性配合使用)
    exitUntilCollapsed - 向上滚动时收缩View,但能够固定Toolbar一直在上面。

  • ==》折叠前的控件高度大小:就是控件的layout_height属性值。

  • ==》折叠后的最小高度:android:minHeight e.g. android:minHeight="200dp";****注意:该属性值只有在其子view中没有使用Toolbar控件时才有用。当子view中使用了android.support.v7.widget.Toolbar则会以该Toolbar的高度为准。

  • ==》在折叠的时候 状态栏的背景颜色android.support.design:statusBarScrim  e.g. app:statusBarScrim="#123456" The drawable to use as a scrim for the status bar content when the CollapsingToolbarLayout has been scrolled sufficiently off screen. )

  • ==》折叠后该layout的背景色:android.support.design:contentScrim  e.g.  app:contentScrim="#ff5252",The drawable to use as a scrim on top of the CollapsingToolbarLayouts content when it has been scrolled sufficiently off screen. 


4.该该可滑动控件能够是RecyclerView或者v4包中的NestedScrollView,可是对于Listview无效。java

具体更为详细的这几个控件的介绍可参考:http://blog.csdn.net/lxk_1993/article/details/51443045android


下面是踩坑时间可跳过(design包版本为:com.android.suport:design:23.4.0时会出现如下情况):git

此时加上上面介绍的沉浸式页面的实现按说已经能够实现所需效果,可是发现github

1.在KITKAT版本手机上运行时效果已经正常,windows

2.但在Lollipop版本的系统上运行时会出现以下效果:review代码可知此时关于沉浸式状态栏的设置,只有在Activity中添加的Flag(this.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);app


鉴于此参考大部分的作法,在CollapsingToolbarLayout直接子View添加属性fitsSystemWindows = true;(回顾此属性的意义为系统自动适配状态栏高度到控件,给设置此属性的View添加paddingTop值,以适应系统窗口 好比:状态栏/导航栏),因此按说不该该添加此属性值才对。ide


但实际效果为:函数

1.Lollipop版本的系统运行已经达到预期的效果。布局

2.可是,KITKAT版本的系统运行效果却又出现了和上面相似效果以下(有部分差异,此时KITKAT版本只有CollapsingToolbarLayout下的第一个设置了fitsSystemWindows = true的View会下移一个状栏的高度,其余的不会下移,在此表现即为CollapsingToolbarLayout子View中的第一个RelativeLayout会下移,可是做为TitleBar使用的第二个子View却不会下移ui


 解决方法可有:
1.代码中判断版本并设置CollapsingToolbarLayout直接子View的fitsSystemWindows属性值代码以下:
   
   
   
   
for (int i = 0; i < collapsingToolbarLayout.getChildCount(); i++) {//拿取CollapsingToolbarLayout的子View并根据版本设置其fitsSystemWindows的属性 if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) { collapsingToolbarLayout.getChildAt(i).setFitsSystemWindows(true); } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) { collapsingToolbarLayout.getChildAt(i).setFitsSystemWindows(false); } else {//不支持沉浸式状态栏的版本,要把使View向下偏移的占位控件的高度设置为0 //设置充当TitleBar使用的控件里面的占位空间的高度为0, } }
2.直接在布局文件中把CollapsingToolbarLayout 的全部子View的fitsSystemWindows属性设置为true,此时Lollipop版本效果已经OK,但因为在KITKAT版本系统中CollapsingToolbarLayout的第一个设置为fitsSystemWindows为true的View会被下移一个状态栏的高度,所以能够简单的再在该 CollapsingToolbarLayout下添加一个高度为0的View,把其   fitsSystemWindows属性也设置为true便可。此操做能够用代码,也可直接写入布局文件中。

如今问题解决让咱们稍微深究下:在同时使用沉浸式页面和CollapsingToolbarLayout时为何会出现View下移一个状态栏的高度
现象为:当页面设置为沉浸式的时候,CollapsingToolbarLayout的子View正常的不设置fitsSystemWIndows的属性时,即其默认为false,正常不会下移以适应状态栏的高度时,在Lollipop版本为何依旧会往下偏移,而KITKAT版本就是正常的:注意,此处使用的design包版本为:com.android.suport:design:23.4.0
直接上CollapsingToolbarLayout 的源码,先直接找其onLayout方法,其中一段代码以下:

   
   
   
   
  1. .getFitsSystemWindows(child)) {
// Update our child view offset helpers for (int i = 0, z = getChildCount(); i < z; i++) { final View child = getChildAt(i); if (mLastInsets != null && !ViewCompat final int insetTop = mLastInsets.getSystemWindowInsetTop(); if (child.getTop() < insetTop) { // If the child isn't set to fit system windows but is drawing within the inset // offset it down ViewCompat.offsetTopAndBottom(child, insetTop); } } getViewOffsetHelper(child).onViewLayout(); }
今后段代码可知CollapsingToolbarLayout 在的layout过程当中,会遍历子View,并当在mLastInset不为null,且其fitsSystemWIndows属性为false时会拿到mLastInset中的SysTemWindowsInsetTop值(即复制的状态栏的高度),当该top值比子View设置的paddingtop值大(即状态栏会遮挡到子view的布局内容时)会自动为其添加一个状态栏高度的padding值,而这也正是上面当不设置fitsSystemWIndows属性时会向下偏移一个状态栏的高度。而在设置了以后反而不会下移。
但如今的问题是为何KITKAT的就不会出现此问题:咱们接下来看,这个mLastInsets是什么?代码中能够看到为WindowInsetsCompat类型的对象,再看其是在何处初始化的:
   
   
   
   
private WindowInsetsCompat setWindowInsets(WindowInsetsCompat insets) { if (mLastInsets != insets) { mLastInsets = insets; requestLayout(); } return insets.consumeSystemWindowInsets(); }
而该setWindowInsets()方法的调用是在CollapsingToolbarLayout 的构造函数中源码以下:
   
   
   
   
ViewCompat.setOnApplyWindowInsetsListener(this, new android.support.v4.view.OnApplyWindowInsetsListener() { @Override public WindowInsetsCompat onApplyWindowInsets(View v, WindowInsetsCompat insets) { return setWindowInsets(insets); } });
至此可知其初始化是在一个OnApplyWindowInsetsListener()的回调中进行的,而设置此监听的在ViewCompat中的相关代码以下,
    
    
    
    
/**    *方法的相关声明 * Set an {@link OnApplyWindowInsetsListener} to take over the policy for applying * window insets to this view. This will only take effect on devices with API 21 or above. */ public static void setOnApplyWindowInsetsListener(View v, OnApplyWindowInsetsListener listener) { IMPL.setOnApplyWindowInsetsListener(v, listener); }
继续看IMPL的初始化:其是在ViewCompat的静态代码块中初始化的:
   
   
   
   
static final ViewCompatImpl IMPL; static { final int version = android.os.Build.VERSION.SDK_INT; if (BuildCompat.isAtLeastN()) { IMPL = new Api24ViewCompatImpl(); } else if (version >= 23) { IMPL = new MarshmallowViewCompatImpl(); } else if (version >= 21) { IMPL = new LollipopViewCompatImpl(); } else if (version >= 19) { IMPL = new KitKatViewCompatImpl(); } else if (version >= 18) { IMPL = new JbMr2ViewCompatImpl(); } else if (version >= 17) { IMPL = new JbMr1ViewCompatImpl(); } else if (version >= 16) { IMPL = new JBViewCompatImpl(); } else if (version >= 15) { IMPL = new ICSMr1ViewCompatImpl(); } else if (version >= 14) { IMPL = new ICSViewCompatImpl(); } else if (version >= 11) { IMPL = new HCViewCompatImpl(); } else { IMPL = new BaseViewCompatImpl(); } }
至此此已能够看到官方的声明该方法只有在API为21及其以上才能使用(即只有在Lollipop版本及其之上才会设置该listener),一样CollapsingToolbarLayout 中的在onLayout()方法中用到的WindowInsetsCompat对象mLastInset只有在Lollipop版本及其之上才会被初始化,所以回到CollapsingToolbarLayout 的onLayout的那段代码:
   
   
   
   
// Update our child view offset helpers for (int i = 0, z = getChildCount(); i < z; i++) { final View child = getChildAt(i); if (mLastInsets != null && !ViewCompat.getFitsSystemWindows(child)) { final int insetTop = mLastInsets.getSystemWindowInsetTop(); if (child.getTop() < insetTop) { // If the child isn't set to fit system windows but is drawing within the inset // offset it down ViewCompat.offsetTopAndBottom(child, insetTop); } } getViewOffsetHelper(child).onViewLayout(); }
以上总结及另外一种解决方法为:
1.在CollapsingToolbarLayout+沉浸式状态栏的实现中,当不设置fitsSystemWindows为true时,在版本为KITKAT,mLastInsets为null,根本不会进入到下面的逻辑,其子View也就不会向下偏移。而对于LOLLIPOP及其以上则其子View会向下偏移。
而上面的解决方法中的设置CollapsingToolbarLayout的子View的fitsSystemWindows为true的方案只是在该处的if判断中加了拦截,从而达到预期效果。
基于此,也可使mLastInsets为null来解决问题,可在collapsingToolbarLayout初始化以后调用如下代码:
   
   
   
   
ViewCompat.setOnApplyWindowInsetsListener(collapsingToolbarLayout, new OnApplyWindowInsetsListener() { @Override public WindowInsetsCompat onApplyWindowInsets(View v, WindowInsetsCompat insets) { //insets.replaceSystemWindowInsets(0, 0, 0, 0); 该行代码无效                // return insets.consumeSystemWindowInsets(); return insets; } });
对比CollapsingToolbarLayout的构造函数里面的该方法可知此时在回调过程当中不会触发mLastInsets的初始化操做,因此mLastInsets也不会被初始化。一样能够实现所需效果

2.CollapsingToolbarLayout+沉浸式状态栏的实现中,当设置fitsSystemWindows为true时,为何KITKAT版本的只会使第一个子View下移一个状态栏的高度,倒没有找到源码在那个地方。
至此则已经能够实现支持沉浸式的版本KITKAT和LOLLIPOP及以上版本的在 CollapsingToolbarLayout实现上的兼容。

三:将以上单页面的实现放入Fragment中,再放入ViewPager

在解决掉第二歨的兼容问题问题以后,在ViewPager的Fragment中使用该组合时也不会出现个别fragment中会有view向下偏移状态栏高度的问题,即一开始想要获得的效果。


PS:
1.以上的解决方法中都只是使onLayout()中view向下偏移的代码不执行来实现的。可是最终缘由应该是在沉浸式的页面中WindowInsetsCompat对象中的mLastInsets.getSystemWindowInsetTop()拿到的值是状态栏的高度。可是若是能改变该对象内的值应该也是可行的,至少在镶套进ViewPager的Fragment以后会出现第二个页面此处拿到的值为0。可是并无找到缘由。若是那位同窗知道还望留言告知。
2.以上当使用的在design包版本为:com.android.suport:design:23.4.0会出现,可是在使用design包的版本为25.0.0时,不须要设置CollapsingToolbarLayout的fitsSystemWindows属性,在KITKAT和LOLLIPOP的系统中均可以获得想要的效果。代码中能够看到在25.0.0版本中的CollapsingToolbarLayout代码中,
onLayout()方法中用到的WindowInsetsCompat对象mLastInset并非在构造函数中设置的listener中初始化的,而是在另一个函数中进行的初始化,具体能够查看源码

最终的实例代码在如下地址:https://github.com/M075097/ImmersionStyleDemo