美文网首页AndroidAndroid开发UI
一站式CoordinatorLayout+ToolBar联动使用

一站式CoordinatorLayout+ToolBar联动使用

作者: Leogh | 来源:发表于2017-08-30 11:59 被阅读336次

    什么叫一站式

    那还用问,就是一学就会呗。啦啦啦啦啦啦啦啦啦啦啦啦啦!
    主要是我看别人的介绍的东西看得头大,一大堆重要细节都没有,漏了一点细节的话很多效果都没有。总得来说一站式就是吹牛皮
    文章比较长耐心看完就会用

    ToolBar+DrawerLayout使用
    Android 自定义侧滑菜单效果(ViewDragHelper)


    一、撸代码前要了解的东西

    Google在2015的IO大会,给我们带来了更加详细的Material Design设计规范,同时,也给我们带来了全新的Android Design Support Library,在这个support库里面,Google给我们提供了更加规范的MD设计风格的控件。最重要的是,Android Design Support Library的兼容性更广,直接可以向下兼容到Android 2.2。(敲黑板,这是重点拿笔记下来)

    上面提到了Design Support Library,要使用这个库当然是要引入到项目中咯,在Gradle中引入:

    compile 'com.android.support:design:24.1.0'
    

    CoordinatorLayout等一些控件就是Material Design设计风格的控件,具体有哪些控件可以搜一下。望文生义这个控件就是协调控件:

    1. 扩展或者缩小Toolbar或者头部,让主内容区域有更多的空间。
    2. 控制哪个view应该扩展还是收缩,以及其显示大小比例,包括视差滚动效果动画。

    看一下效果图呗(颜色不协调是为了更好的区分不同区域):
    控制哪个view应该扩展还是收缩,以及其显示大小比例,包括视差滚动效果动画。

    CoorCollapsingToolbar.gif

    扩展或者缩小Toolbar或者头部,让主内容区域有更多的空间。

    CoorToolBar.gif CoorFloatingActionButton.gif

    这三种效果主要都是根据xml来决定,当然还可以通过自定义Behavior来完成这个或者完成更复杂的效果,这些都不管,现在只用xml来完成。
    如果效果还尽人意请往下看看呗。


    二、CoordinatorLayout与CollapsingToolbar控制View的伸展与收缩

    大致的效果在上图1所示。一下分解各个实现的步骤。

    1. 首先咱们要使用ToolBar一般都是要先隐藏原来的ActionBar,隐藏ActionBar有几种方法,这里我们就只在Manifest.xml里面进行配置。创建一个activity命名CoorCollapsingToolbarAct然后在xml中进行注册并设置Theme
    <activity android:name=".CoorToolViewPagerAct"
                      android:theme="@style/coordinatorTheme"/>
    

    coordinatorTheme是在res\values\styles.xml中的自定义样式,父样式parent就是去掉ActionBar的样式如下:

    <!--colorPrimaryDark设置透明色的原因是为了通过后面对状态栏的颜色改变起效果(可以试着改变一下看效果)-->
        <style name="coordinatorTheme" parent="Theme.AppCompat.Light.NoActionBar">
            <item name="android:colorPrimary">@color/colorPrimary</item>
            <item name="android:colorPrimaryDark">@android:color/transparent</item>
        </style>
    
    1. 要实现这些效果需结合AppBarLayout来共同完成
    • AppBarLayout必须作为CoordinatorLayout的直接子View,否则它的大部分功能将不会生效,如layout_scrollFlags等。
    • AppBarLayout它可以让你定制当某个可滚动View的滚动手势发生变化时,其内部的子View实现何种动作。
    • 内部的子View通过在布局中加app:layout_scrollFlags设置执行的动作,具体往下看。
    1. 知道什么是CollapsingToolBarLayout
    • CollapsingToolbarLayout你可以像魔术一样让 Toolbar折叠起来
    • 用 CollapsingToolbarLayout 包裹 Toolbar,但仍然在 AppBarLayout 中
    • 从 Toolbar 不设置layout_scrollFlags
    • 为 CollapsingToolbarLayout 声明layout_scrollFlags,并且将layout_scrollFlags 设置成scroll|exitUntilCollapsed|snap
    • 改变 AppBarLayout 扩张状态时的布局高度大小。在这个例子中,我用 250dp

    app:layout_scrollFlags属性值
    scroll: 所有想滚动出屏幕的view都需要设置这个flag, 没有设置这个flag的view将被固定在屏幕顶部。
    snap: 在滚动结束后,如果view只是部分可见,它将滑动到最近的边界。
    exitUntilCollapsed: 滚动退出屏幕,最后折叠在顶端。
    还有enterAlways,enterAlwaysCollapsed等属性可以逐一试试看。

    1. xml编写
      使用CoordinatorLayout往往是将他直接作为根布局来操作。创建activity_coor_collapsing.xml.
    <?xml version="1.0" encoding="utf-8"?>
    <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"
        >
    
        <!--app:elevation="0dp"  TabLayout与AppBarLayout结合使用TabLayout下面会出现阴影 设置此属性可去除-->
        <android.support.design.widget.AppBarLayout
            android:id="@+id/appbar"
            theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
            android:layout_width="match_parent"
            android:layout_height="300dp"
            android:fitsSystemWindows="true"
            android:elevation="0dp">
    
            <!--
            1、statusBarScrim 折叠时状态栏的颜色(设置为透明色时,状态栏会展示contentScrim背景色的效果)
             contentScrim:折叠之后的背景色(不包括状态栏)
            2、注意:暂时发现 5.x与4.x的系统不设置折叠样式时,折叠时会将title默认隐藏,具体效果可以试试,不知道是不是机型问题,有待考察
            collapsedTitleTextAppearance 折叠字体样式 expandedTitleMarginStart 展开字体样式-->
            <android.support.design.widget.CollapsingToolbarLayout
                android:id="@+id/main_collapsing"
                android:layout_width="match_parent"
                android:layout_height="250dp"
                android:fitsSystemWindows="true"
                app:collapsedTitleTextAppearance="@style/collapsedTitleTextAppearance_white"
                app:contentScrim="@color/colorPrimary"
                app:expandedTitleMarginEnd="64dp"
                app:expandedTitleMarginStart="48dp"
                app:expandedTitleTextAppearance="@style/collapsedTitleTextAppearance_green"
                app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
                app:statusBarScrim="#fff000">
    
                <!--layout_collapseMode (折叠模式) - 有两个值:
                    pin -  设置为这个模式时,当CollapsingToolbarLayout完全收缩后,Toolbar还可以保留在屏幕上。
                     parallax - 设置为这个模式时,在内容滚动时,CollapsingToolbarLayout中的View(比如ImageView)也可以同时滚动,实现视差滚动效果,通常和layout_collapseParallaxMultiplier(设置视差因子)搭配使用。
                    layout_collapseParallaxMultiplier(视差因子) - 设置视差滚动因子,值为:0-1。-->
                <ImageView
                    android:id="@+id/backdrop"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:fitsSystemWindows="true"
                    android:scaleType="centerCrop"
                    android:src="@drawable/jjy_bg"
                    app:layout_collapseMode="parallax"
                    app:layout_collapseParallaxMultiplier="1"
                    />
    
                <!--app:popupTheme,这个属性就是用来自定义我们弹出的菜单的样式,在之前的Actionbar的溢出菜单,
                我们是不能自定义他的样式的,只能根据你的theme来选择黑白两种,不能自己定义,现在我们可以定义弹出菜单的样式。
                暂时使用系统定义好的样式-->
                <android.support.v7.widget.Toolbar
                    android:id="@+id/toolbar"
                    android:layout_width="match_parent"
                    android:layout_height="?attr/actionBarSize"
                    app:layout_collapseMode="pin"
                    app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
            </android.support.design.widget.CollapsingToolbarLayout>
    
            <android.support.design.widget.TabLayout
                android:id="@+id/tabs"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_alignParentBottom="true"
                android:background="@color/colorPrimary"
                app:tabIndicatorColor="@color/colorAccent"
                app:tabSelectedTextColor="#000"
                app:tabTextColor="#fff"/>
        </android.support.design.widget.AppBarLayout>
    
        <!--layout_behavior=”@string/appbar_scrolling_view_behavior”标志位(该Behavior系统以及帮我们实现),
        那么当带有这个标志位的控件滑动的时候会触发带有scroll_flags标志位的另一个控件进行滑动,
        此时imageview的layout_collapseMode是parallax,所以它会以有视差的方式来相对滑动,而toolbar设置了pin的标记位,
        所以在收缩后会固定在屏幕顶部。
        可在VIewPager中放置Recyclerview,ScrollView等滑动的布局(ListView与GridView不行)可进行联动-->
        <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>
    
        <!--没有渐变效果一直显示不隐藏  原因时上面使用了TabLayout  感觉是不能在AppBarLayout添加TabLayout来一起使用-->
        <android.support.design.widget.FloatingActionButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="@dimen/activity_horizontal_margin"
            android:clickable="true"
            android:src="@android:drawable/ic_menu_add"
            app:layout_anchor="@id/appbar"
            app:layout_anchorGravity="bottom|right|end"/>
    </android.support.design.widget.CoordinatorLayout>
    

    分析+解密[吹牛皮](敲黑板,文件中的注释是重点记下来要考)

    • CollapsingToolbarLayout中的statusBarScrim:折叠时状态栏的颜色。前面在Activity的Theme中将状态栏设置为透明色,所以当折叠ToolBar时会显示我们在这里设置的色值。如果在Theme中不设置为透明这里将不起作用。
    • 根布局CoordinatorLayout与AppBarLayout都要设置android:fitsSystemWindows="true",如对此属性不懂可参考fitsystemwindows简单使用
    • layout_behavior=”@string/appbar_scrolling_view_behavior”标志位(该Behavior系统以及帮我们实现),那么当带有这个标志位的控件滑动的时候会触发带有scroll_flags标志位的另一个控件进行滑动,此时imageview的layout_collapseMode是parallax,所以它会以有视差的方式来相对滑动,而toolbar设置了pin的标记位,所以在收缩后会固定在屏幕顶部。可在VIewPager中放置Recyclerview,ScrollView等滑动的布局(ListView与GridView不行)可进行联动.

    比较奇葩的发现

    暂时发现,如果你想实现title(图一的LOGO)的的效果,需设置CollapsingToolbarLayout的title值,然而5.x与4.x的系统不设置折叠样式collapsedTitleTextAppearance时,折叠时会将title默认隐藏,具体效果可以试试,不知道是不是机型问题,有待考察,6.x的系统不设置折叠时也会展示出来。

    三、撸代码(图一效果)

    因为用上了ViewPager,所以顺带也用上了TabLayout,不了解可以看看TabLayout高端用法,所以也结合了Fragment实现。

    1. 大致创建一个简单的Fragment的基类BaseFragment:
    /**
     * Created by Leogh on 2017/8/28.
     */
    
    public abstract class BaseFragment extends Fragment {
    
       //这个title不用管 弄着玩的
        public TextView tv_title;
    
        @Nullable
        @Override
        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
            View view = getLayoutView(inflater, container);
            tv_title = (TextView) view.findViewById(R.id.tv_title);
            init();
            return view;
        }
    
        public abstract View getLayoutView(LayoutInflater inflater, ViewGroup container);
    
        public abstract void init();
    }
    

    在创建三个Fragment,分别为Fragment1,Fragment2,Fragment3简单粗暴嘛,这里只贴一个Fragment1的代码,其它两个类似改一下就OK。

    /**
     * Created by Leogh on 2017/8/28.
     */
    
    public class Fragment1 extends BaseFragment {
    
        private View view;
        private RecyclerView rv_page1;
        private List<String> mDatas = new ArrayList<String>();
    
        @Override
        public View getLayoutView(LayoutInflater inflater, ViewGroup container) {
            view = inflater.inflate(R.layout.fragment_page1, container, false);
            return view;
        }
    
        @Override
        public void init() {
            initData();
            tv_title.setText("one");
            rv_page1 = (RecyclerView) view.findViewById(R.id.rv_page1);
            rv_page1.setLayoutManager(new LinearLayoutManager(getActivity()));
            rv_page1.setAdapter(new CoorAdapter(getActivity(), mDatas));
        }
    
        private void initData() {
            for (int i = 0; i < 20; i++) {
                mDatas.add("老腊肉" + i);
            }
        }
    }
    

    差点漏了Recyclerview的Adapter了CoorAdapter

    /**
     * Created by Leogh on 2017/8/29.
     */
    
    public class CoorAdapter extends RecyclerView.Adapter<CoorAdapter.MyViewHolder> {
    
        private Context mContext;
        private List<String> mDatas;
    
        public CoorAdapter(Context mContext, List<String> mDatas) {
            this.mContext = mContext;
            this.mDatas = mDatas;
        }
    
        @Override
        public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.main_list_item, parent, false);
            return new MyViewHolder(v);
        }
    
        @Override
        public void onBindViewHolder(MyViewHolder holder, int position) {
            holder.textView.setText(mDatas.get(position));
        }
    
        @Override
        public int getItemCount() {
            return mDatas.size();
        }
    
        class MyViewHolder extends RecyclerView.ViewHolder {
            TextView textView;
    
            public MyViewHolder(View itemView) {
                super(itemView);
                textView = (TextView) itemView.findViewById(R.id.textview);
            }
        }
    
    }
    
    

    Fragment1的布局文件fragment_page1.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  android:orientation="vertical"
                  android:layout_width="match_parent"
                  android:layout_height="match_parent">
    
        <TextView
            android:id="@+id/tv_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="one"
            android:textSize="20sp"
            android:layout_centerInParent="true"/>
    
        <android.support.v7.widget.RecyclerView
            android:id="@+id/rv_page1"
            android:background="#efffff"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:overScrollMode="never"/>
    </RelativeLayout>
    

    最后主Activity上场CoorCollapsingToolbarAct:

    /**
     * Created by Leogh on 2017/8/28.
     * 图片渐变效果与CollapsingToolBarLayout(折叠ToolBar)
     * <p>
     * 要实现此效果 需要使用 CoorinatorLayout (协调布局)  AppBarLayout(导航布局) + 一个可以滑动的布局
     * (注意 不支持 listView和GirdView)
     */
    
    public class CoorCollapsingToolbarAct extends AppCompatActivity {
    
        private Toolbar mToolBar;
        private ViewPager mViewPager;
        private TabLayout mTabLayout;
        private CollapsingToolbarLayout main_collapsing;
        private List<Fragment> mFragments;
        private String[] mTitles = new String[]{"你", "我", "他"};
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_coordinator);
    
            mToolBar = (Toolbar) findViewById(R.id.toolbar);
            mToolBar.setLogo(android.R.drawable.ic_menu_add);
            main_collapsing = (CollapsingToolbarLayout) findViewById(R.id.main_collapsing);
            //手动设置title
            // 注意:目前测试用的是5.1系统 发现不在xml中设置折叠字体样式,折叠时title也会直接隐藏,同时也试了4.4系统也是一样,6.0系统不会
            //我也没有专门去测试,也不能直接得出结论说5.x与4.x的系统一定要设置 具体情况具体分析哈 多试试
            main_collapsing.setTitle("LOGO");
            setSupportActionBar(mToolBar);
            getSupportActionBar().setDisplayHomeAsUpEnabled(false);
            mViewPager = (ViewPager) findViewById(R.id.viewpager);
            mTabLayout = (TabLayout) findViewById(R.id.tabs);
            setupViewPager();
        }
    
        private void setupViewPager() {
            mFragments = new ArrayList<Fragment>();
            mFragments.add(new Fragment1());
            mFragments.add(new Fragment2());
            mFragments.add(new Fragment3());
            FragmentPagerAdapter adapter = new FragmentPagerAdapter(getSupportFragmentManager()) {
                @Override
                public Fragment getItem(int position) {
                    return mFragments.get(position);
                }
    
                @Override
                public int getCount() {
                    return mFragments.size();
                }
    
                @Override
                public CharSequence getPageTitle(int position) {
                    return mTitles[position];
                }
            };
            mViewPager.setAdapter(adapter);
            //ViewPager与TabLayout联动
            mTabLayout.setupWithViewPager(mViewPager);
        }
    
        /**
         * 如果有Menu,创建完后,系统会自动添加到ToolBar上
         * 此方法用于初始化菜单,其中menu参数就是即将要显示的Menu实例。 返回true则显示该menu,false 则不显示;
         * (只会在第一次初始化菜单时调用)
         *
         * @param menu
         * @return
         */
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            getMenuInflater().inflate(R.menu.main_menu, menu);
            return true;
        }
    }
    
    

    到此就可以看到图一的效果了,有很多属性可能没有分析,但是多试试才知道有什么效果。


    四、撸代码(图2效果)

    这里就只上xml文件了,代码都差不多 只是改了一下xml文件,将CollapsingToolBarLayout去掉直接换成了ToolBar来实现效果:

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              xmlns:app="http://schemas.android.com/apk/res-auto">
    
        <android.support.design.widget.AppBarLayout
            android:id="@+id/appbar"
            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/colorPrimary"
                app:layout_scrollFlags="scroll|enterAlways|snap"/>
    
                <android.support.design.widget.TabLayout
                    android:id="@+id/tabs"
                    android:background="@color/colorPrimary"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"/>
        </android.support.design.widget.AppBarLayout>
    
        <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.design.widget.FloatingActionButton
            android:id="@+id/fab"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="end|bottom"
            android:layout_margin="16dp"
            android:src="@android:drawable/ic_input_add" />
    </android.support.design.widget.CoordinatorLayout>
    

    这样,滑动列表的时候就可以直接展示与折叠ToolBar了,不需要拉扯到列表顶部才能对ToolBar进行联动,如果非要以图一的形式来实现就需要自定义Behavior了(暂时没有发现其他方法)。


    五、撸代码(图3效果)

    注意:图三效果就是那个图标(FloatingActionButton)有渐变最后消失的一个过程的效果,图一中我们也对FloatingActionButton做了同样的处理,可是并没有达到预期的效果:

    • 暂时得出来的结论就是, 原因是图一中使用了TabLayout,去掉TabLayout就有渐变效果, 感觉是不能在AppBarLayout添加TabLayout来一起使用。所以这里只要把TabLayout去掉就可以了。
      xml如下:
    <?xml version="1.0" encoding="utf-8"?>
    <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
                                                     xmlns:app="http://schemas.android.com/apk/res-auto"
                                                     android:id="@+id/main_content"
                                                     android:layout_width="match_parent"
                                                     android:layout_height="match_parent"
                                                     android:fitsSystemWindows="true">
    
        <android.support.design.widget.AppBarLayout
            android:id="@+id/appbar"
            theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
            android:layout_width="match_parent"
            android:layout_height="300dp"
            android:fitsSystemWindows="true"
            android:elevation="0dp">
    
            <android.support.design.widget.CollapsingToolbarLayout
                android:id="@+id/main_collapsing"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:fitsSystemWindows="true"
                app:collapsedTitleTextAppearance="@style/collapsedTitleTextAppearance_white"
                app:contentScrim="@color/colorPrimary"
                app:expandedTitleMarginEnd="64dp"
                app:expandedTitleMarginStart="48dp"
                app:expandedTitleTextAppearance="@style/collapsedTitleTextAppearance_green"
                app:layout_scrollFlags="scroll|exitUntilCollapsed"
                app:statusBarScrim="#fff000">
    
                <ImageView
                    android:id="@+id/backdrop"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:fitsSystemWindows="true"
                    android:scaleType="centerCrop"
                    android:src="@drawable/jjy_bg"
                    app:layout_collapseMode="parallax"
                    app:layout_collapseParallaxMultiplier="1"
                    />
    
                <android.support.v7.widget.Toolbar
                    android:id="@+id/toolbar"
                    android:layout_width="match_parent"
                    android:layout_height="?attr/actionBarSize"
                    app:layout_collapseMode="pin"
                    app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
    
            </android.support.design.widget.CollapsingToolbarLayout>
    
        </android.support.design.widget.AppBarLayout>
    
        <android.support.v4.view.ViewPager
            android:id="@+id/viewpager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    
        <!--有渐变效果 layout_anchor指定参照物为AppBarLayout-->
        <android.support.design.widget.FloatingActionButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="16dp"
            android:clickable="true"
            android:src="@mipmap/ic_launcher"
            app:layout_anchor="@id/appbar"
            app:layout_anchorGravity="bottom|right|end"/>
    
    </android.support.design.widget.CoordinatorLayout>
    

    这个Activity的话就直接加载布局就行:

    /**
     * Created by Leogh on 2017/8/29.
     * FloatingActionButton渐变效果
     */
    
    public class CoorFloatingActionButtonAct extends AppCompatActivity {
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.testfloatbutton);
        }
    }
    

    可能有些细节漏了,但注释写的很详细,多留意注释。

    最后提供一下官方Demo:点我点我点我

    相关文章

      网友评论

        本文标题:一站式CoordinatorLayout+ToolBar联动使用

        本文链接:https://www.haomeiwen.com/subject/akvodxtx.html