Android-协调人员CoordinatorLayout(一)
最近查资料比较多,因为要实现一个比较难的交互式布局,用到最多的就是CoordinatorLayout,翻阅网上的资料七拼八凑的也算是弄明白了,其实之前读书时就用过,后面就忘了,当年记录的笔记也早忘记在哪了,这次就写在网上,相当于笔记了。
先看看我们要实现的界面
1533180062683.gif
这是CoordinatorLayout最简单的实现了,都有这么好看,那要是学得非常精通了,那就牛逼了。哈哈,废话不多说上笔记。
我们先创一个activity,在他的xml文件中写入一个Toolbar加recyclerview
<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:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/colorPrimaryDark">
</android.support.v7.widget.Toolbar>
<android.support.v7.widget.RecyclerView
android:id="@+id/recycle_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none" />
</android.support.design.widget.CoordinatorLayout>
当然,细心的人会发现列表与toolbar重叠了,额,这个不急后面就能改变,至于为什么会这样我们点击CoordinatorLayout进入源代码就能看到他是进入了ViewGroup,所以就这样了。
在activity的java文件中,我们找到Toolbar并设置setSupportActionBar,不然Toolbar是不会鸟你的,如下:
public class Main22Activity extends AppCompatActivity {
private RecyclerView recyclerView;
private List<String> list=new ArrayList<>();
private TestAdapter testAdapter;
private Toolbar toolbar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main22);
recyclerView = (RecyclerView) findViewById(R.id.recycle_view);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
testAdapter = new TestAdapter(list,this);
recyclerView.setAdapter(testAdapter);
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
}
@Override
protected void onStart() {
super.onStart();
for(int x=0;x<20;x++){
list.add("x"+x);
}
}
@Override
protected void onResume() {
super.onResume();
testAdapter.updateList(list);
}
}
好,写到这里就真的开始写关键代码了,在CoordinatorLayout中要对Toolbar下死手,就要在他外面包一层AppBarLayout布局,已于重叠我们要在RecyclerView中加入app:layout_behavior="@string/appbar_scrolling_view_behavior"这是一个系统自定义的behavior,它里面做了设置marginTop="?attr/actionBarSize"的工作。代码如下:
<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:orientation="vertical">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/colorPrimaryDark">
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/recycle_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
</android.support.design.widget.CoordinatorLayout>
运行后发现说好了协调呢?不急,刚刚我们在RecyclerView设置的app:layout_behavior其实就监听了他的滑动,这时候我们就缺Toolbar的协调,就相当于观察者与被观察者,我们这个时候有了被观察者,观察者还没设置,那么我们就需要在Toolbar中设置app:layout_scrollFlags="scroll",相当于告诉系统,我要监听滑动,谁的滑动?谁设置了app:layout_behavior="@string/appbar_scrolling_view_behavior"我监听谁。至于layout_scrollFlags还有其他选项我们要使用多个就用"|"分开就行。他的参数详解如下:
scroll:
官方:The view will be scroll in direct relation to scroll events. This flag needs to be set for any of the other flags to take effect. If any sibling views before this one do not have this flag, then this value has no effect.
Child View 伴随着滚动事件而滚出或滚进屏幕。注意两点:第一点,如果使用了其他值,必定要使用这个值才能起作用;第二点:如果在这个child View前面的任何其他Child View没有设置这个值,那么这个Child View的设置将失去作用。
enterAlways
官方:When entering (scrolling on screen) the view will scroll on any downwards scroll event, regardless of whether the scrolling view is also scrolling. This is commonly referred to as the 'quick return' pattern.
快速返回模式。其实就是向下滚动时Scrolling View和Child View之间的滚动优先级问题。对比scroll和scroll | enterAlways设置,发生向下滚动事件时,前者优先滚动Scrolling View,后者优先滚动Child View,当优先滚动的一方已经全部滚进屏幕之后,另一方才开始滚动。
enterAlwaysCollapsed
官方:An additional flag for 'enterAlways' which modifies the returning view to only initially scroll back to it's collapsed height. Once the scrolling view has reached the end of it's scroll range, the remainder of this view will be scrolled into view. The collapsed height is defined by the view's minimum height.
enterAlways的附加值。这里涉及到Child View的高度和最小高度,向下滚动时,Child View先向下滚动最小高度值,然后Scrolling View开始滚动,到达边界时,Child View再向下滚动,直至显示完全。
exitUntilCollapsed
官方:When exiting (scrolling off screen) the view will be scrolled until it is 'collapsed'. The collapsed height is defined by the view's minimum height.
这里也涉及到最小高度。发生向上滚动事件时,Child View向上滚动退出直至最小高度,然后Scrolling View开始滚动。也就是,Child View不会完全退出屏幕。
snap
官方:Upon a scroll ending, if the view is only partially visible then it will be snapped and scrolled to it's closest edge. For example, if the view only has it's bottom 25% displayed, it will be scrolled off screen completely. Conversely, if it's bottom 75% is visible then it will be scrolled fully into view.
简单理解,就是Child View滚动比例的一个吸附效果。也就是说,Child View不会存在局部显示的情况,滚动Child View的部分高度,当我们松开手指时,Child View要么向上全部滚出屏幕,要么向下全部滚进屏幕,有点类似ViewPager的左右滑动
这里我选择设置app:layout_scrollFlags="scroll|snap|enterAlways",完整代码如下:
<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:orientation="vertical">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/colorPrimaryDark"
android:title="@string/app_name"
app:titleTextColor="@android:color/white"
app:layout_scrollFlags="scroll|snap|enterAlways">
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/recycle_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
</android.support.design.widget.CoordinatorLayout>
运行即可。
当然在常见的app布局当中,我们见到最多的就如下图:
1533192826845.gif
toolbar可以推上去,tablayout保留在顶部。那么怎么实现呢?话不多说直接上代码。main.xml中我注释了recyclerview增加了TabLayout与viewpager
<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:orientation="vertical">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/colorPrimaryDark"
android:title="@string/app_name"
app:titleTextColor="@android:color/white"
app:layout_scrollFlags="scroll|snap|enterAlways">
</android.support.v7.widget.Toolbar>
<android.support.design.widget.TabLayout
android:id="@+id/tablayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimaryDark">
</android.support.design.widget.TabLayout>
</android.support.design.widget.AppBarLayout>
<!--<android.support.v7.widget.RecyclerView-->
<!--android:id="@+id/recycle_view"-->
<!--android:layout_width="match_parent"-->
<!--android:layout_height="match_parent"-->
<!--android:scrollbars="none"-->
<!--android:visibility="gone"-->
<!--app:layout_behavior="@string/appbar_scrolling_view_behavior"/>-->
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
</android.support.v4.view.ViewPager>
</android.support.design.widget.CoordinatorLayout>
记住viewpager下要有app:layout_behavior="@string/appbar_scrolling_view_behavior"
在activity中将TabLayout填充数据
public class Main22Activity extends AppCompatActivity {
// private RecyclerView recyclerView;
// private List<String> list=new ArrayList<>();
// private TestAdapter testAdapter;
private Toolbar toolbar;
private TabLayout mTabLayout;
private ViewPager mViewPager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main22);
// recyclerView = (RecyclerView) findViewById(R.id.recycle_view);
// recyclerView.setLayoutManager(new LinearLayoutManager(this));
// testAdapter = new TestAdapter(list,this);
// recyclerView.setAdapter(testAdapter);
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mTabLayout = (TabLayout)findViewById(R.id.tablayout);
mViewPager = (ViewPager)findViewById(R.id.viewpager);
}
@Override
protected void onStart() {
super.onStart();
// for(int x=0;x<20;x++){
// list.add("x"+x);
// }
}
@Override
protected void onResume() {
super.onResume();
// testAdapter.updateList(list);
initViewPager();
}
private void initViewPager() {
// 创建一个集合,装填Fragment
ArrayList<Fragment> fragments = new ArrayList<>();
// 装填
fragments.add(new OneFragment());
fragments.add(new TwoFragment());
fragments.add(new ThreeFragment());
// 创建ViewPager适配器
MyPagerAdapter myPagerAdapter = new MyPagerAdapter(getSupportFragmentManager());
myPagerAdapter.setFragments(fragments);
// 给ViewPager设置适配器
mViewPager.setAdapter(myPagerAdapter);
// TabLayout 指示器 (记得自己手动创建4个Fragment,注意是 app包下的Fragment 还是 V4包下的 Fragment)
mTabLayout.addTab(mTabLayout.newTab());
mTabLayout.addTab(mTabLayout.newTab());
mTabLayout.addTab(mTabLayout.newTab());
// 使用 TabLayout 和 ViewPager 相关联
mTabLayout.setupWithViewPager(mViewPager);
// TabLayout指示器添加文本
mTabLayout.getTabAt(0).setText("头条");
mTabLayout.getTabAt(1).setText("热点");
mTabLayout.getTabAt(2).setText("娱乐");
}
}
运行后发现啥都没有也不能上下滑动,就只能viewpager的左右滑动。如下图:
微信图片_20180802144158.jpg
原因是我们fragment中数据并没有填充屏幕,所以没有滑动效果,我们可以在fragment中加入recyclerview然后填充数据,这里我们用过recyclerview了就不在使用他了,我们用个新的,CoordinatorLayout支持Viewpage、recyclerview、还有NestedScrollView。我们先以onefragment做样例,在他的布局中加入NestedScrollView然后放很多数据让他可以滑动。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context="com.easy.customeasytablayout.customviews.coordinatorlayout.OneFragment">
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/dp_20"
android:text="测试"/>
........ 很多button
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
</LinearLayout>
运行后控件就能动了。viewpager在CoordinatorLayout中的使用要注意viewpage根布局要加入app:layout_behavior="@string/appbar_scrolling_view_behavior",然后fragment中要使用NestedScrollView或recyclerview,不能使用ListView与ScrollView。
好啦,本章结束啦