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。

好啦,本章结束啦

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容