首先先看看仿制的效果先,如下图:
是不是很像支付宝的效果呢,我们今天就要通过讲解android5.0新出的控件CoordinatorLayout,AppBarLayout,CollapsingToolbarLayout来实现这个效果。
在讲解之前先看看界面布局文件,在一个一个讲讲怎么实现吧:
.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="com.example.jack.coordinatorlayouttest.ScrollingActivity">
.support.design.widget.AppBarLayout
android:id="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:theme="@style/AppTheme.AppBarOverlay">
.support.design.widget.CollapsingToolbarLayout
android:id="@+id/toolbar_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="@color/color1984D1"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
app:title=" ">
"@layout/shenghuo_head1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="100dp"
android:layout_marginBottom="25dp"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.8"/>
.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:contentInsetLeft="0dp"
app:contentInsetStart="0dp"
app:layout_collapseMode="pin">
"@+id/toolbar1"
layout="@layout/toolbar_head1"
android:layout_width="match_parent"
android:layout_height="match_parent" />
"@+id/toolbar2"
layout="@layout/toolbar_head2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"/>
.support.v7.widget.Toolbar>
.support.design.widget.CollapsingToolbarLayout>
.support.design.widget.AppBarLayout>
"@layout/content_scrolling" />
.support.design.widget.CoordinatorLayout>
这就是整个高仿支付宝界面的核心布局界面的,看看代码量也不多吧,只要就是用了CoordinatorLayout,AppBarLayout,CollapsingToolbarLayou,Toolbar这四个控件吧。
在各个布局文件里,最外围的是CoordinatorLayout这个控件,这个有什么作用呢,就我的大白话来说就是协调子View之间动作的一个父View,通过Behavior来给子view实现交互的。这样好像还是有点说不通,没关系
同学们通过看上面的布局文件,可以发现
这一个内容界面是的布局是
这一句的内容是:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:showIn="@layout/activity_scrolling"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<android.support.v7.widget.RecyclerView
android:id="@+id/myRecyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent">
android.support.v7.widget.RecyclerView>
LinearLayout>
没错就是一个linearLayout包裹着RecyclerView组成他的内容界面,在这代码里有这一句app:layout_behavior="@string/appbar_scrolling_view_behavior"
就是这句和CoordinatorLayout控件互动实现滑动,总结就是CoordinatorLayout控件和app:layout_behavior来进行互动,进而CoordinatorLayout的子控件和app:layout_behavior互动。当然@string/appbar_scrolling_view_behavior
是系统自带的,本质是一个类,我们也可以自定义这个类实现其他效果,不过这不是我们这一章所讲的了,我们点到即止。
其次就是AppBarLayout,去除官方解释,简单来说就是它可以让你定制当某个可滚动View的滚动手势发生变化时,其内部的子View实现何种动作。内部的子View通过在布局中加app:layout_scrollFlags
设置执行的动作。而layout_srcollFlags的动作主要如下:
1. scroll:值设为scroll的View会跟随滚动事件一起发生移动。
2. enterAlways:值设为enterAlways的View,当ScrollView往下滚动时,该View会直接往下滚动。而不用考虑ScrollView是否在滚动。
3. exitUntilCollapsed:值设为exitUntilCollapsed的View,当这个View要往上逐渐“消逝”时,会一直往上滑动,直到剩下的的高度达到它的最小高度后,再响应ScrollView的内部滑动事件。
4. enterAlwaysCollapsed:是enterAlways的附加选项,一般跟enterAlways一起使用,它是指,View在往下“出现”的时候,首先是enterAlways效果,当View的高度达到最小高度时,View就暂时不去往下滚动,直到ScrollView滑动到顶部不再滑动时,View再继续往下滑动,直到滑到View的顶部结束。
这是layout_srcollFlags里可以设置的各个属性的解释,考虑文章的重点是模仿支付宝所以没有篇幅和每个属性都给个效果图,所以各属性你们有空还要自己试一试,这样子才能掌握更好。
我们这里AppBarLayout关联的是CollapsingToolbarLayout,设置的属性是app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
里面的scroll让
这可以滑动,而exitUntilCollapsed实现的效果是这一块当滑动到最顶的时候不会跟这个继续滑到最顶,而保留这一块。最后snap这是属性是子View不会存在局部显示的情况,滚动Child View的部分高度,当我们松开手指时,Child View要么向上全部滚出屏幕,要么向下全部滚进屏幕。
是用来对Toolbar进行再次包装的ViewGroup,主要是用于实现折叠的App Bar效果。CollapsingToolbarLayout只要有这方面:
1.title展开时是最大的,然后随着收缩会越来越少,直到屏幕的顶部,通过app:title设置title,不然就默认。
2.通过setContentScrim(Drawable)来设置达到某一个状态之后的出现的效果
3.通过setStatusBarScrim(Drawable)来设置达到某一个状态之后的状态栏出现的效果
4.当app:layout_collapseMode设为parallax
子View可以选择在当前的布局当时是否以“视差”的方式来跟随滚动
5.当app:layout_collapseMode设为pin
Toolbar固定位置而不受移动的影响
在我们实现这里,我们把layout="@layout/shenghuo_head1"
即设为app:layout_collapseMode="parallax"
让它以“视差”的方式来跟随滚动,而toolbar设为app:layout_collapseMode="pin"
以让他固定不动。
在此整体布局就已经完成,不过还有一个效果就是向上移动是toolbar的的View是动态变化的,一开始我以为这些控件会有这个功能吧,没想到找了很久都没找到,没办法只能自己实现了。二话不说上代码:
private AppBarLayout mAppBarLayout=null;
private View mToolbar1=null;
private View mToolbar2=null;
private ImageView mZhangdan=null;
private TextView mZhangdan_txt=null;
private ImageView mTongxunlu=null;
private ImageView mJiahao=null;
private ImageView mZhangdan2=null;
private ImageView mShaoyishao=null;
private ImageView mSearch=null;
private ImageView mZhaoxiang=null;
private RecyclerView myRecyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scrolling);
myRecyclerView=(RecyclerView)findViewById(R.id.myRecyclerView);
myRecyclerView.setLayoutManager(new LinearLayoutManager(this));
myRecyclerView.setAdapter(new ToolbarAdapter(this));
mAppBarLayout=(AppBarLayout)findViewById(R.id.app_bar);
mToolbar1=(View)findViewById(R.id.toolbar1);
mToolbar2=(View)findViewById(R.id.toolbar2);
mZhangdan=(ImageView)findViewById(R.id.img_zhangdan);
mZhangdan_txt=(TextView)findViewById(R.id.img_zhangdan_txt);
mTongxunlu=(ImageView)findViewById(R.id.tongxunlu);
mJiahao=(ImageView)findViewById(R.id.jiahao);
mZhangdan2=(ImageView)findViewById(R.id.img_shaomiao);
mShaoyishao=(ImageView)findViewById(R.id.img_fukuang);
mSearch=(ImageView)findViewById(R.id.img_search);
mZhaoxiang=(ImageView)findViewById(R.id.img_zhaoxiang);
mAppBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
if (verticalOffset == 0){
//张开
mToolbar1.setVisibility(View.VISIBLE);
mToolbar2.setVisibility(View.GONE);
setToolbar1Alpha(255);
state=true;
} else if (Math.abs(verticalOffset) >= appBarLayout.getTotalScrollRange()) {
//收缩
mToolbar1.setVisibility(View.GONE);
mToolbar2.setVisibility(View.VISIBLE);
setToolbar2Alpha(255);
state=false;
} else {
int alpha=255-Math.abs(verticalOffset)-150;
if(alpha<=0){
//收缩toolbar
mToolbar1.setVisibility(View.GONE);
mToolbar2.setVisibility(View.VISIBLE);
setToolbar2Alpha(Math.abs(verticalOffset));
}else{
//张开toolbar
mToolbar1.setVisibility(View.VISIBLE);
mToolbar2.setVisibility(View.GONE);
setToolbar1Alpha(alpha);
}
}
}
});
}
//设置展开时各控件的透明度
public void setToolbar1Alpha(int alpha){
mZhangdan.getDrawable().setAlpha(alpha);
mZhangdan_txt.setTextColor(Color.argb(alpha,255,255,255));
mTongxunlu.getDrawable().setAlpha(alpha);
mJiahao.getDrawable().setAlpha(alpha);
}
//设置闭合时各控件的透明度
public void setToolbar2Alpha(int alpha){
mZhangdan2.getDrawable().setAlpha(alpha);
mShaoyishao.getDrawable().setAlpha(alpha);
mSearch.getDrawable().setAlpha(alpha);
mZhaoxiang.getDrawable().setAlpha(alpha);
}
代码还是有点多了不过最核心就设置AppBarLayout 的监听器addOnOffsetChangedListener来进行效果的处理。当verticalOffset=0的时候即使整个展开的是时候要做的就是显示要显示的,隐藏要隐藏的设置,在设置透明度,同理当verticalOffset等于appBarLayout.getTotalScrollRange()即等于最大值的时候,就是关闭的时候,处理的展开相反。当他在中间值的时候,通过int alpha=255-Math.abs(verticalOffset)-150;得到要设置的透明度,减去150是为了让效果更明显。当alpha小于0的时候是执行展开的toolbar的透明度效果,反之大于0的时候是闭合时toolbar的透明图效果。
剩下的看源码吧