Android5.0推出的MaterialDesign库包含了处理头部工具栏的多个控件,不但允许自定义顶部导航栏,而且导航栏高度是可以伸缩的。如此一来,一方面导航栏能够放得下更多控件,另一方面在用户想看具体内容时也能腾出更多的屏幕空间。
这么说可能比较抽象,那就先来看看两张导航栏的效果图,第一张是导航栏完全展开时的界面,此时页面头部的导航栏占据了较大部分的高度;
第二张是导航栏完全收缩时的界面,此时头部导航栏只剩矮矮的一个长条。
看起来很眼熟是不是,上面的截图正是仿支付宝首页的头部效果。如果你熟悉AppBarLayout和CollapsingToolbarLayout的话,也许可以很快做出类似以上的简单界面,具体地说,就是定义一个CoordinatorLayout嵌套AppBarLayout再嵌套CollapsingToolbarLayout再嵌套Toolbar的布局。之所以要嵌套这么多层,是因为要完成以下功能:
1、CoordinatorLayout嵌套AppBarLayout,这是为了让头部导航栏能够跟随内容视图下拉而展开,跟随内容视图上拉而收缩。这个内容视图可以是RecyclerView,也可以是NestedScrollView;
2、AppBarLayout嵌套CollapsingToolbarLayout,这是为了定义导航栏下面需要展开和收缩的部分视图;
3、CollapsingToolbarLayout嵌套Toolbar,这是为了定义导航栏上方无论何时都要显示的长条区域,其中Toolbar还要定义两个不同的样式布局,用于分别显示展开与收缩状态时的工具栏界面。
下面是基于以上思路实现的布局文件代码:
然而仅仅实现上述布局并非万事大吉,支付宝首页的头部在伸缩时可是有动画效果的,就像下面这个动图那样有淡入淡出的渐变动画:
这个渐变动画其实可分为两段:
1、导航栏从展开状态向上收缩时,头部的各控件要慢慢向背景色过渡,也就是淡入效果;
2、导航栏向上收缩到一半,顶部的工具栏要换成收缩状态下的工具栏布局,并且随着导航栏继续向上收缩,新工具栏上的各控件也要慢慢变得清晰起来,也就是淡出效果。
如果导航栏是从收缩状态向下展开,则此时相应的做上述渐变动画的取反效果,即:
1、导航栏从收缩状态向下展开时,头部的各控件要慢慢向背景色过渡,也就是淡入效果;同时展开导航栏的下部分布局,并且该布局上的各控件渐渐变得清晰;
2、导航栏向下展开到一半,顶部的工具栏要换成展开状态下的工具栏布局,并且随着导航栏继续向下展开,新工具栏上的各控件也要慢慢变得清晰起来,也就是淡出效果。
看起来还比较复杂,如果只对某个控件做渐变动画还好,可是导航栏上的控件有好几个,而且并不固定常常会增加和修改。倘若要对导航栏上的各控件逐一动画过去,不但费力气,而且后期也不好维护。为了解决这个问题,我们可以采取类似遮罩的做法,即一开始先给导航栏罩上一层透明的视图,此时导航栏的画面就完全显示;然后随着导航栏的移动距离,计算当前位置下的遮罩透明度,比如该遮罩变得越来越不透明,看起来导航栏就像蒙上了一层面纱,蒙到最后就看不见了。反过来,也可以一开始给导航栏罩上一层不透明的视图,此时导航栏的控件是看不见的,然后随着距离的变化,遮罩变得越来越不透明,导航栏也会跟着变得越来越清晰了。
渐变动画的思路有了,可谓万事俱备,只欠东风,再来一个导航栏的移动偏移监听器便行,正好有个现成的AppBarLayout.OnOffsetChangedListener,只需给AppBarLayout对象调用addOnOffsetChangedListener方法,即可实现给导航栏注册偏移监听器的功能。接下来的事还是直接看看具体的实现代码吧:
点此查看Android开发笔记的完整目录
__________________________________________________________________________
本文现已同步发布到微信公众号“老欧说安卓”,打开微信扫一扫下面的二维码,或者直接搜索公众号“老欧说安卓”添加关注,更快更方便地阅读技术干货。
这么说可能比较抽象,那就先来看看两张导航栏的效果图,第一张是导航栏完全展开时的界面,此时页面头部的导航栏占据了较大部分的高度;
第二张是导航栏完全收缩时的界面,此时头部导航栏只剩矮矮的一个长条。
看起来很眼熟是不是,上面的截图正是仿支付宝首页的头部效果。如果你熟悉AppBarLayout和CollapsingToolbarLayout的话,也许可以很快做出类似以上的简单界面,具体地说,就是定义一个CoordinatorLayout嵌套AppBarLayout再嵌套CollapsingToolbarLayout再嵌套Toolbar的布局。之所以要嵌套这么多层,是因为要完成以下功能:
1、CoordinatorLayout嵌套AppBarLayout,这是为了让头部导航栏能够跟随内容视图下拉而展开,跟随内容视图上拉而收缩。这个内容视图可以是RecyclerView,也可以是NestedScrollView;
2、AppBarLayout嵌套CollapsingToolbarLayout,这是为了定义导航栏下面需要展开和收缩的部分视图;
3、CollapsingToolbarLayout嵌套Toolbar,这是为了定义导航栏上方无论何时都要显示的长条区域,其中Toolbar还要定义两个不同的样式布局,用于分别显示展开与收缩状态时的工具栏界面。
下面是基于以上思路实现的布局文件代码:
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" > <android.support.design.widget.AppBarLayout android:id="@+id/abl_bar" android:layout_width="match_parent" android:layout_height="wrap_content" android:fitsSystemWindows="true" > <android.support.design.widget.CollapsingToolbarLayout android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" app:layout_scrollFlags="scroll|exitUntilCollapsed|snap" app:contentScrim="@color/blue_dark" > <include android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="@dimen/toolbar_height" app:layout_collapseMode="parallax" app:layout_collapseParallaxMultiplier="0.7" layout="@layout/life_pay" /> <android.support.v7.widget.Toolbar android:layout_width="match_parent" android:layout_height="@dimen/toolbar_height" app:layout_collapseMode="pin" app:contentInsetLeft="0dp" app:contentInsetStart="0dp" > <include android:id="@+id/tl_expand" android:layout_width="match_parent" android:layout_height="match_parent" layout="@layout/toolbar_expand" /> <include android:id="@+id/tl_collapse" android:layout_width="match_parent" android:layout_height="match_parent" layout="@layout/toolbar_collapse" android:visibility="gone" /> </android.support.v7.widget.Toolbar> </android.support.design.widget.CollapsingToolbarLayout> </android.support.design.widget.AppBarLayout> <android.support.v7.widget.RecyclerView android:id="@+id/rv_content" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginTop="10dp" app:layout_behavior="@string/appbar_scrolling_view_behavior" /> </android.support.design.widget.CoordinatorLayout>
然而仅仅实现上述布局并非万事大吉,支付宝首页的头部在伸缩时可是有动画效果的,就像下面这个动图那样有淡入淡出的渐变动画:
这个渐变动画其实可分为两段:
1、导航栏从展开状态向上收缩时,头部的各控件要慢慢向背景色过渡,也就是淡入效果;
2、导航栏向上收缩到一半,顶部的工具栏要换成收缩状态下的工具栏布局,并且随着导航栏继续向上收缩,新工具栏上的各控件也要慢慢变得清晰起来,也就是淡出效果。
如果导航栏是从收缩状态向下展开,则此时相应的做上述渐变动画的取反效果,即:
1、导航栏从收缩状态向下展开时,头部的各控件要慢慢向背景色过渡,也就是淡入效果;同时展开导航栏的下部分布局,并且该布局上的各控件渐渐变得清晰;
2、导航栏向下展开到一半,顶部的工具栏要换成展开状态下的工具栏布局,并且随着导航栏继续向下展开,新工具栏上的各控件也要慢慢变得清晰起来,也就是淡出效果。
看起来还比较复杂,如果只对某个控件做渐变动画还好,可是导航栏上的控件有好几个,而且并不固定常常会增加和修改。倘若要对导航栏上的各控件逐一动画过去,不但费力气,而且后期也不好维护。为了解决这个问题,我们可以采取类似遮罩的做法,即一开始先给导航栏罩上一层透明的视图,此时导航栏的画面就完全显示;然后随着导航栏的移动距离,计算当前位置下的遮罩透明度,比如该遮罩变得越来越不透明,看起来导航栏就像蒙上了一层面纱,蒙到最后就看不见了。反过来,也可以一开始给导航栏罩上一层不透明的视图,此时导航栏的控件是看不见的,然后随着距离的变化,遮罩变得越来越不透明,导航栏也会跟着变得越来越清晰了。
渐变动画的思路有了,可谓万事俱备,只欠东风,再来一个导航栏的移动偏移监听器便行,正好有个现成的AppBarLayout.OnOffsetChangedListener,只需给AppBarLayout对象调用addOnOffsetChangedListener方法,即可实现给导航栏注册偏移监听器的功能。接下来的事还是直接看看具体的实现代码吧:
public class AlipayActivity extends AppCompatActivity implements OnOffsetChangedListener { private final static String TAG = "AlipayActivity"; private AppBarLayout abl_bar; private View tl_expand, tl_collapse; private View v_expand_mask, v_collapse_mask, v_pay_mask; private int mMaskColor; private RecyclerView rv_content; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_alipay); mMaskColor = getResources().getColor(R.color.blue_dark); rv_content = (RecyclerView) findViewById(R.id.rv_content); rv_content.setLayoutManager(new GridLayoutManager(this, 4)); rv_content.setAdapter(new LifeAdapter(this, LifeItem.getDefault())); abl_bar = (AppBarLayout) findViewById(R.id.abl_bar); tl_expand = (View) findViewById(R.id.tl_expand); tl_collapse = (View) findViewById(R.id.tl_collapse); v_expand_mask = (View) findViewById(R.id.v_expand_mask); v_collapse_mask = (View) findViewById(R.id.v_collapse_mask); v_pay_mask = (View) findViewById(R.id.v_pay_mask); abl_bar.addOnOffsetChangedListener(this); } @Override public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { Log.d(TAG, "verticalOffset="+verticalOffset); int offset = Math.abs(verticalOffset); int total = appBarLayout.getTotalScrollRange(); int alphaIn = offset; int alphaOut = (200-offset)<0?0:200-offset; int maskColorIn = Color.argb(alphaIn, Color.red(mMaskColor), Color.green(mMaskColor), Color.blue(mMaskColor)); int maskColorInDouble = Color.argb(alphaIn*2, Color.red(mMaskColor), Color.green(mMaskColor), Color.blue(mMaskColor)); int maskColorOut = Color.argb(alphaOut*2, Color.red(mMaskColor), Color.green(mMaskColor), Color.blue(mMaskColor)); if (offset <= total / 2) { tl_expand.setVisibility(View.VISIBLE); tl_collapse.setVisibility(View.GONE); v_expand_mask.setBackgroundColor(maskColorInDouble); } else { tl_expand.setVisibility(View.GONE); tl_collapse.setVisibility(View.VISIBLE); v_collapse_mask.setBackgroundColor(maskColorOut); } v_pay_mask.setBackgroundColor(maskColorIn); } }
点此查看Android开发笔记的完整目录
__________________________________________________________________________
本文现已同步发布到微信公众号“老欧说安卓”,打开微信扫一扫下面的二维码,或者直接搜索公众号“老欧说安卓”添加关注,更快更方便地阅读技术干货。
作者:aqi00 发表于2017/5/22 9:41:50 原文链接
阅读:8 评论:0 查看评论