Md系列3、CoordinatorLayout 里 Toobar和TabLayout等发生的一系列故事(末个人修正)

本文主要涉及android里面md设计的几个控件
CoordinatorLayout
AppBarLayout
CollapsingToolbarLayout
TabLayout

一、看,看出陌生

本文假设是读者还没使用过adnroid support md的控件,先来看一下图片:


海贼王演示.gif

我们看到,标题栏可以伸缩,而且顶部状态栏是沉浸的,颜色沉浸,图片沉浸。

噢,那看看是怎么实现的吧。打开布局文件发现代码如下:

<?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">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="256dp"
        android:fitsSystemWindows="true"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">  

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            app:contentScrim="?attr/colorPrimary"
            app:expandedTitleMarginEnd="64dp"
            app:expandedTitleMarginStart="48dp"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <ImageView
                android:id="@+id/ivImage"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:fitsSystemWindows="true"
                android:transitionName="transition_book_img"
                android:scaleType="centerCrop"
                app:layout_collapseMode="parallax"
                app:layout_collapseParallaxMultiplier="0.7" />

            <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>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <android.support.design.widget.TabLayout
            android:id="@+id/sliding_tabs"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:tabGravity="fill"
            app:tabMode="fixed" />

        <android.support.v4.view.ViewPager
            android:id="@+id/viewpager"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </LinearLayout>

</android.support.design.widget.CoordinatorLayout>

一看,瓦擦,好多没见过

CoordinatorLayout 
AppBarLayout
CollapsingToolbarLayout
TabLayout

android:fitsSystemWindows="true"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
android:transitionName="transition_book_img"
app:layout_collapseParallaxMultiplier="0.7" 
app:layout_collapseMode="pin"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" 
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" 
app:tabGravity="fill" 
app:tabMode="fixed"

好多东西,都是什么鬼。不过还好,抛去属性,控件不认识的也就4个。
他们的包含关系大概如下:


Paste_Image.png

嗯,那就先看看这几个控件吧,熟悉一下。

二、CoordinatorLayout

Android dev CoordinatorLayout官网学习资料

人家Google这么说

CoordinatorLayout is a super-powered FrameLayout.

CoordinatorLayout is intended for two primary use cases:

As a top-level application decor or chrome layout
As a container for a specific interaction with one or more child views
By specifying Behaviors for child views of a CoordinatorLayout you can provide many different interactions within a single parent and those views can also interact with one another. View classes can specify a default behavior when used as a child of a CoordinatorLayout using the DefaultBehavior annotation.

Behaviors may be used to implement a variety of interactions and additional layout modifications ranging from sliding drawers and panels to swipe-dismissable elements and buttons that stick to other elements as they move and animate.

Children of a CoordinatorLayout may have an anchor. This view id must correspond to an arbitrary descendant of the CoordinatorLayout, but it may not be the anchored child itself or a descendant of the anchored child. This can be used to place floating views relative to other arbitrary content panes.

大概也就是这么说:

CoordinatorLayout 是一个加强版的FrameLayout。(继承自ViewGroup)

主要有两个用途:
1、作为顶层应用的装饰或者chrome布局
2、作为一个容器来协调一个或多个子views

CoordinatorLayout,Coordinator有协调的意思。它是一个可以组织众多子view之间互相协作的一个ViewGroup

CoordinatorLayout 有一个Behavior,这个对象可以说让子view直接知道了彼此的存在,通过不同的状态监听控制其他子View的移动或者隐藏与显示等。

简单使用

1、使用之前引入

compile 'com.android.support:appcompat-v7:23.4.0'
compile 'com.android.support:design:23.4.0'

2、布局文件

<?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.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="@mipmap/ic_launcher" />

</android.support.design.widget.CoordinatorLayout>

3、Activity

public class CoordinatorLayoutActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_coordinator);
        findViewById(R.id.fab).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                Snackbar.make(view,"FAB",Snackbar.LENGTH_LONG)
                        .setAction("cancel", new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                //这里的单击事件代表点击消除Action后的响应事件
                            }
                        })
                        .show();
            }
        });
    }
}

4、效果:


应用.gif
  • 亮点在哪里?
    当我们按下Snackbar的时候弹出来提示的时候,按钮的会做一个上移的动画,而我们的代码却不需要做什么。

至于为什么会这么动,那是因为FloatingActionButton默认使用FloatingActionButton.Behavior。
关于Behavior,后面在说。

  • 什么是Snackbar?
    简单来说可以这么说,在Md的世界里 Snackbar 是 作为代替 Toast 而存在的好东西。

当然如果你不信这个动画是因为CoordinatorLayout才形成的,那么好,我们把代码改一下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    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.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="@mipmap/ic_launcher" />

</RelativeLayout>

效果就变成这样子了


按钮无动画.gif

在里面CoordinatorLayout的世界里,Behavior占据了一个特别重要的地位。
然后在上面Snackbar的小示例里面,因为系统默认的关系我们连Behavior的身影都看到。那么下面还是来弄一个小demo,关于Behavior。

CoordinatorLayout里面的直接子View一般是:AppBarLayout+NestedScrollView。
又涉及到了新东西,NestedScrollView还好,简单认为一个是md涉及里面的ScrollView。
至于AppBarLayout,还是可以掰扯的,另起一点,开讲。

深入理解Android开发中的CoordinatorLayout Behavior

二、伸缩 —— CoordinatorLayout + AppBarLayout + NestedScrollView

CoordinatorLayout里面的直接子View一般是:AppBarLayout+NestedScrollView。

NestedScrollView

Google NestedScrollView文档

NestedScrollView is just like ScrollView, 
but it supports acting as both a nested scrolling parent and child on both new and old versions of Android. 
Nested scrolling is enabled by default.

AppBarLayout 是什么?

一起来看看Google给我们的AppBarLayout 说明书吧:

AppBarLayout is a vertical LinearLayout which implements many of the features of material designs app bar concept, namely scrolling gestures.

Children should provide their desired scrolling behavior through setScrollFlags(int) and the associated layout xml attribute: app:layout_scrollFlags.

This view depends heavily on being used as a direct child within a CoordinatorLayout. If you use AppBarLayout within a different ViewGroup, most of it's functionality will not work.

AppBarLayout also requires a separate scrolling sibling in order to know when to scroll. The binding is done through the AppBarLayout.ScrollingViewBehavior behavior class, meaning that you should set your scrolling view's behavior to be an instance of AppBarLayout.ScrollingViewBehavior. A string resource containing the full class name is available.

Google大概就是说:

AppBarLayout是一个实现了很多material designs特性的垂直的LinearLayout,它能响应滑动事件。

  • 1、AppBarLayout最好是CoordinatorLayout的直接子view

  • 2、AppBarLayout的子view
    需要设置app:layout_scrollFlags ,或者是在代码中调用setScrollFlags()设置这个属性。

  • 3、AppBarLayout的兄弟节点(或兄弟节点的子view可以滚动):
    需要指定behavior属性为AppBarLayout.ScrollingViewBehavior(可以使用一个内置的string表示这个默认的实例@string/appbar_scrolling_view_behavior.),才能发挥它的最大的作用

瓦擦,看文字费劲,那么看Google的示例伪代码吧,感觉世界瞬间清爽很多

 <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">
    <!-- 3、指定behavior属性为AppBarLayout.ScrollingViewBehavior -->
     <android.support.v4.widget.NestedScrollView
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             app:layout_behavior="@string/appbar_scrolling_view_behavior">

         <!-- Your scrolling content -->

     </android.support.v4.widget.NestedScrollView>

     <!--1、AppBarLayout最好是CoordinatorLayout的直接子view -->
     <android.support.design.widget.AppBarLayout
             android:layout_height="wrap_content"
             android:layout_width="match_parent">
        <!--2 、AppBarLayout的子view:需要设置app:layout_scrollFlags-->
         <android.support.v7.widget.Toolbar
                 ...
                 app:layout_scrollFlags="scroll|enterAlways"/>

         <android.support.design.widget.TabLayout
                 ...
                 app:layout_scrollFlags="scroll|enterAlways"/>

     </android.support.design.widget.AppBarLayout>

 </android.support.design.widget.CoordinatorLayout>

.
.

好像是那么回事了,来吧,

来一个demo吧

1、布局文件

<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">

    <!--1、AppBarLayout最好是CoordinatorLayout的直接子view -->
    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
        <!--2 、AppBarLayout的子view:需要设置app:layout_scrollFlags-->
        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            android:title="Title"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
            app:layout_scrollFlags="scroll|enterAlways" />

        <ImageView
            android:id="@+id/mIv"
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:scaleType="centerCrop"
            android:background="@mipmap/lf"
            />

    </android.support.design.widget.AppBarLayout>

    <!-- 3、指定behavior属性为AppBarLayout.ScrollingViewBehavior -->
    <android.support.v4.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">
            <TextView
                android:layout_width="match_parent"
                android:layout_height="180dp"
                android:layout_margin="10dp"
                android:background="#6660c6df"
                android:gravity="center"
                android:text="折"
                android:textSize="26dp"
                android:transitionName="zi" />
            <TextView
                android:layout_width="match_parent"
                android:layout_height="180dp"
                android:layout_margin="10dp"
                android:background="#6660c6df"
                android:gravity="center"
                android:text="折叠"
                android:textSize="26dp"
                android:transitionName="zi" />
            <TextView
                android:layout_width="match_parent"
                android:layout_height="180dp"
                android:layout_margin="10dp"
                android:background="#6660c6df"
                android:gravity="center"
                android:text="折叠示"
                android:textSize="26dp"
                android:transitionName="zi" />
            <TextView
                android:layout_width="match_parent"
                android:layout_height="180dp"
                android:layout_margin="10dp"
                android:background="#6660c6df"
                android:gravity="center"
                android:text="折叠示例"
                android:textSize="26dp"
                android:transitionName="zi" />
        </LinearLayout>
    </android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>

2、Activity

public class CoorSimpleActivity extends AppCompatActivity {

    private Toolbar toolbar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_coor_simple);
        toolbar = (Toolbar) findViewById(R.id.toolbar);
        toolbar.setTitle("Title");
        setSupportActionBar(toolbar);
    }
}

3、sytle

<resources>
    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="android:windowTranslucentStatus">true</item> <!--重要-->
    </style>

</resources>

4、效果图


TabLayout.gif

利用我们说的三点,我们在xml里面都做了。效果也实现了。

那么问题来了,ayout_scrollFlags这些值是个什么意思:

scroll:所有想滚动出屏幕的view都需要设置这个flag, 没有设置这个flag的view将被固定在屏幕顶部。

enterAlways:这个flag让任意向下的滚动都会导致该view变为可见,启用快速“返回模式”。

enterAlwaysCollapsed:当你的视图已经设置minHeight属性又使用此标志时,你的视图只能已最小高度进入,只有当滚动视图到达顶部时才扩大到完整高度。

exitUntilCollapsed:滚动退出屏幕,最后折叠在顶端。

注意:
scroll、enterAlways两种模式基本是需要一起使用的
enterAlways、enterAlwaysCollapsed两种模式基本只有在CollapsingToolbarLayout才有用
也就是说,这些flag的使用场景,基本已经固定了。

PS : 所有使用scroll flag的view都必须定义在没有使用scroll flag的view的前面,这样才能确保所有的view从顶部退出,留下固定的元素。

三、AppBarLayout + CollapsingToolbarLayout

在说CollapsingToolbarLayout之前,我们想一想md对于Toolbar我们都经历了什么。
1、你说ActionBar不好,要换成Toolbar,好,我换,从此我有了规范的标题栏。
2、你说利用CoordinatorLayout 可以协调子View,做隐藏或者显示,嗯好,我把最外层换成CoordinatorLayout 。
3、你说AppBarLayout是一个实现了很多material designs特性的垂直的LinearLayout,它能响应滑动事件。好,哥们在Toolbar外面加一层AppBarLayout
4、现在,你说垂直的东西还不够自然,有一个android自己支持的叫做 CollapsingToolbarLayout 可折叠伸缩的Toolbar。好,哥们为了标题栏,为了md,再折腾。

吃完辣条,赶紧翻翻CollapsingToolbarLayout说明书

CollapsingToolbarLayout is a wrapper for Toolbar which implements a collapsing app bar. It is designed to be used as a direct child of a AppBarLayout. CollapsingToolbarLayout contains the following features:

Collapsing title
A title which is larger when the layout is fully visible but collapses and becomes smaller as the layout is scrolled off screen. You can set the title to display via setTitle(CharSequence). The title appearance can be tweaked via the collapsedTextAppearance and expandedTextAppearance attributes.
Content scrim
A full-bleed scrim which is show or hidden when the scroll position has hit a certain threshold. You can change this via setContentScrim(Drawable).
Status bar scrim
A scrim which is show or hidden behind the status bar when the scroll position has hit a certain threshold. You can change this via setStatusBarScrim(Drawable). This only works on LOLLIPOP devices when we set to fit system windows.
Parallax scrolling children
Child views can opt to be scrolled within this layout in a parallax fashion. See COLLAPSE_MODE_PARALLAX and setParallaxMultiplier(float).
Pinned position children
Child views can opt to be pinned in space globally. This is useful when implementing a collapsing as it allows the Toolbar to be fixed in place even though this layout is moving. See COLLAPSE_MODE_PIN.
Do not manually add views to the Toolbar at run time. We will add a 'dummy view' to the Toolbar which allows us to work out the available space for the title. This can interfere with any views which you add.

谷歌大概这么说:

CollapsingToolbarLayout作用是提供了一个可以折叠的Toolbar
(CollapsingToolbarLayout是一个实现了折叠工具栏效果Toolbar的包装器,它被设计为AppBarLayout的直接子View。)

  • 1、 折叠标题 Collapsing title
    当布局完全显示时,标题会变大;当布局滑出屏幕时,标题会变小。你可以通过setTitle()来设置标题,标题的外观可以通过collapsedTextAppearance()和expandedTextAppearance()方法来调整属性。
collapsingToolbarLayout.setTitle("蒙奇-D-路飞");
collapsingToolbarLayout.setExpandedTitleColor(Color.YELLOW); // 标题展示时颜色
collapsingToolbarLayout.setCollapsedTitleTextColor(Color.WHITE); // 标题收缩时的颜色
  • 2、沉浸式内容 Content scrim
    ToolBar被折叠到顶部固定时候的背景,你可以调用setContentScrim(Drawable)方法改变背景或者 在属性中使用 app:contentScrim=”?attr/colorPrimary”来改变背景。
  • 3、沉浸式状态栏 Status bar scrim
    当滚动到一定值时显示或者隐藏在状态栏后面的沉浸式效果,可以通过setStatusBarScrim()
    方法来设置,仅在Android5.0并且设置了适应窗口(fitsSystemWindows="true"
    )时有用。
  • 4、视差滚动 Parallax scrolling children
    该布局中的子View可以选择视察滚动的方式来滚动,详见LayoutParams#COLLAPSE_MODE_PARALLAX
    和LayoutParams#setParallaxMultiplier()。
    CollapsingToolbarLayout滑动时,子视图的视觉差,可以通过属性app:layout_collapseParallaxMultiplier=”0.x”改变。
    设置视差的系数,介于0.0-1.0之间。
  • 5、 顶部悬浮 CollapseMode
    子视图的折叠模式,有两种 “pin” 和 “parallax”.
    • “pin”:固定模式,在折叠的时候最后固定在顶端;
    • “parallax”:视差模式,在折叠的时候会有个视差折叠的效果。
      我们可以在布局中使用属性app:layout_collapseMode=”parallax”来改变。

嗯,大概就是这样,好像很6的样子,看代码吧。

来一份demo

1、布局文件

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
>

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="300dp"
        android:fitsSystemWindows="true"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            app:contentScrim="?attr/colorPrimary"
            app:expandedTitleMarginEnd="64dp"
            app:expandedTitleMarginStart="48dp"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <ImageView
                android:id="@+id/ivImage"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:fitsSystemWindows="true"
                android:transitionName="transition_book_img"
                android:scaleType="centerCrop"
                app:layout_collapseMode="parallax"
                app:layout_collapseParallaxMultiplier="0.7" />

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_collapseMode="pin"
                app:layout_scrollFlags="scroll|enterAlways"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
        </android.support.design.widget.CollapsingToolbarLayout>
    </android.support.design.widget.AppBarLayout>

    <android.support.v4.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <TextView
                android:layout_width="match_parent"
                android:layout_height="180dp"
                android:layout_margin="10dp"
                android:background="#6660c6df"
                android:gravity="center"
                android:text="折"
                android:textSize="26dp"
                android:transitionName="zi" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="180dp"
                android:layout_margin="10dp"
                android:background="#6660c6df"
                android:gravity="center"
                android:text="折叠"
                android:textSize="26dp"
                android:transitionName="zi" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="180dp"
                android:layout_margin="10dp"
                android:background="#6660c6df"
                android:gravity="center"
                android:text="折叠示"
                android:textSize="26dp"
                android:transitionName="zi" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="180dp"
                android:layout_margin="10dp"
                android:background="#6660c6df"
                android:gravity="center"
                android:text="折叠示例"
                android:textSize="26dp"
                android:transitionName="zi" />


        </LinearLayout>

    </android.support.v4.widget.NestedScrollView>

</android.support.design.widget.CoordinatorLayout>

2、Activity

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ImageView imageView = (ImageView) findViewById(R.id.ivImage);
        imageView.setImageResource(R.mipmap.show_op);
        Toolbar toolbar= (Toolbar) findViewById(R.id.toolbar);

        setSupportActionBar(toolbar);

        //设置工具栏标题
        CollapsingToolbarLayout collapsingToolbarLayout= (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);
        collapsingToolbarLayout.setTitle("蒙奇-D-路飞");
    }
}

3、效果图:


CollapsingToolbarLayout.gif

代码和图都看完了。

下面再折腾一下

所谓 沉浸式内容 Content scrim

//设置工具栏标题
        CollapsingToolbarLayout collapsingToolbarLayout= (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);
        collapsingToolbarLayout.setTitle("蒙奇-D-路飞");
        collapsingToolbarLayout.setExpandedTitleColor(Color.YELLOW);
        collapsingToolbarLayout.setCollapsedTitleTextColor(Color.WHITE);
        collapsingToolbarLayout.setContentScrim(getDrawable(R.mipmap.lf)); // 沉浸内容

沉浸内容.gif


.
.
所谓 沉浸状态栏 Status bar scrim

        //设置工具栏标题
        CollapsingToolbarLayout collapsingToolbarLayout= (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);
        collapsingToolbarLayout.setTitle("蒙奇-D-路飞");
        collapsingToolbarLayout.setExpandedTitleColor(Color.YELLOW); 
        collapsingToolbarLayout.setCollapsedTitleTextColor(Color.WHITE); 
        collapsingToolbarLayout.setStatusBarScrim(getDrawable(R.mipmap.lf));  // 沉浸状态栏

沉浸状态栏.gif

.
.
顶部悬浮 CollapseMode
pin和parallax看起来差不多。。

四、TabLayout

回望开头,我们展示的是一张海贼王的 Tab 动态图,在md之前,我们常常可以使用三方开源的PagerSlidingTabStrip去实现,或者viewpagerindicator,现在我们可以使用Design support library库的TabLayout去实现。

同样,我们先翻翻 google TabLayout司机手册

手册这么说

TabLayout 基本描述

TabLayout provides a horizontal layout to display tabs.

Population of the tabs to display is done through TabLayout.Tab instances. You create tabs via newTab(). From there you can change the tab's label or icon via setText(int) and setIcon(int) respectively. To display the tab, you need to add it to the layout via one of the addTab(Tab) methods.

TabLayout提供了一个水平的布局用来展示Tabs。
TabLayout通过 newTab() 可以创建多个tab标签。
可以通过setText()和setIcon分别设置文本和icon,最后通过addTab将newTab处的选项卡添加上去即可 。
但是这个是单一的选项卡使用 一般使用选项卡我们都是和viewpager相结合使用的。

google参考代码:

 TabLayout tabLayout = ...;
 tabLayout.addTab(tabLayout.newTab().setText("Tab 1"));
 tabLayout.addTab(tabLayout.newTab().setText("Tab 2"));
 tabLayout.addTab(tabLayout.newTab().setText("Tab 3"));

除了代码添加tabs,也可以布局添加tabs

 <android.support.design.widget.TabLayout
         android:layout_height="wrap_content"
         android:layout_width="match_parent">

     <android.support.design.widget.TabItem
             android:text="@string/tab_text"/>

     <android.support.design.widget.TabItem
             android:icon="@drawable/ic_android"/>

 </android.support.design.widget.TabLayout>

TabLayout 监听

可以通过 setOnTabSelectedListener(OnTabSelectedListener) 设置tab状态的改变

TabLayout 、ViewPager 一体化

如果你打算将TabLayout和ViewPager一起使用,那么可以通过setupWithViewPager(ViewPager)方法将两者绑定在一起。这种布局将从PagerAdapter自动填充标题。

 <android.support.v4.view.ViewPager
     android:layout_width="match_parent"
     android:layout_height="match_parent">

     <android.support.design.widget.TabLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_gravity="top" />

 </android.support.v4.view.ViewPager>

来一个demo

1、布局文件
tablayout

<?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">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="256dp"
        android:fitsSystemWindows="true"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            app:contentScrim="?attr/colorPrimary"
            app:expandedTitleMarginEnd="64dp"
            app:expandedTitleMarginStart="48dp"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <ImageView
                android:id="@+id/ivImage"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:fitsSystemWindows="true"
                android:scaleType="centerCrop"
                android:transitionName="transition_book_img"
                app:layout_collapseMode="parallax"
                app:layout_collapseParallaxMultiplier="0.7" />

            <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>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        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">
            <android.support.design.widget.TabLayout
                android:id="@+id/sliding_tabs"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                app:tabGravity="fill"
                app:tabMode="fixed">
            </android.support.design.widget.TabLayout>
        </android.support.v4.view.ViewPager>
    </LinearLayout>
</android.support.design.widget.CoordinatorLayout>

fragment 布局

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/tvInfo"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="10dp"
            android:textColor="#212121"
            android:textSize="16sp" />
    </LinearLayout>

</android.support.v4.widget.NestedScrollView>

2、Activity和Fragment
Activity

public class TabLayoutActivity extends AppCompatActivity {

    private ViewPager mViewPager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.tablayout);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                onBackPressed();
            }
        });


        CollapsingToolbarLayout collapsingToolbar = (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);
        collapsingToolbar.setTitle("海贼王");
        collapsingToolbar.setExpandedTitleColor(Color.YELLOW);
        collapsingToolbar.setCollapsedTitleTextColor(Color.WHITE);

        ImageView ivImage = (ImageView)findViewById(R.id.ivImage);
        ivImage.setImageResource(R.mipmap.show_op);

        mViewPager = (ViewPager) findViewById(R.id.viewpager);
        setupViewPager(mViewPager);

        TabLayout tabLayout = (TabLayout) findViewById(R.id.sliding_tabs);
        tabLayout.addTab(tabLayout.newTab().setText("基本资料"));
        tabLayout.addTab(tabLayout.newTab().setText("身世"));
        tabLayout.addTab(tabLayout.newTab().setText("性格"));
        tabLayout.addTab(tabLayout.newTab().setText("家谱"));
        tabLayout.addTab(tabLayout.newTab().setText("海贼团"));
        tabLayout.setupWithViewPager(mViewPager);
    }

    private void setupViewPager(ViewPager mViewPager) {
        MyPagerAdapter adapter = new MyPagerAdapter(getSupportFragmentManager());
        adapter.addFragment(DetailFragment.newInstance(getAsset("book_content.txt")), "基本资料");
        adapter.addFragment(DetailFragment.newInstance(getAsset("book_author.txt")), "身世");
        adapter.addFragment(DetailFragment.newInstance(getAsset("book_menu.txt")), "性格");
        adapter.addFragment(DetailFragment.newInstance(getAsset("lufei_home.txt")), "家谱");
        adapter.addFragment(DetailFragment.newInstance(getAsset("lufei_friend.txt")), "海贼团");
        mViewPager.setAdapter(adapter);
    }

    private String getAsset(String fileName) {
        AssetManager am = getResources().getAssets();
        InputStream is = null;
        try {
            is = am.open(fileName, AssetManager.ACCESS_BUFFER);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new Scanner(is).useDelimiter("\\Z").next();
    }


    static class MyPagerAdapter extends FragmentPagerAdapter {
        private final List<Fragment> mFragments = new ArrayList<>();
        private final List<String> mFragmentTitles = new ArrayList<>();

        public MyPagerAdapter(FragmentManager fm) {
            super(fm);
        }

        public void addFragment(Fragment fragment, String title) {
            mFragments.add(fragment);
            mFragmentTitles.add(title);
        }

        @Override
        public Fragment getItem(int position) {
            return mFragments.get(position);
        }

        @Override
        public int getCount() {
            return mFragments.size();
        }

        @Override
        public CharSequence getPageTitle(int position) {
            return mFragmentTitles.get(position);
        }
    }
}

Fragment

public class DetailFragment extends Fragment {

    public static DetailFragment newInstance(String info) {
        Bundle args = new Bundle();
        DetailFragment fragment = new DetailFragment();
        args.putString("info", info);
        fragment.setArguments(args);
        return fragment;
    }


    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_detail, null);
        TextView tvInfo = (TextView) view.findViewById(R.id.tvInfo);
        tvInfo.setText(getArguments().getString("info"));

        return view;
    }
}

3、assets文件


Paste_Image.png

4、效果


海贼王演示.gif

来一个底部Tab的demo

布局:
1、主布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:layout_collapseMode="pin"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
    </android.support.design.widget.AppBarLayout>



    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/appbar"
        android:orientation="vertical">

        <android.support.v4.view.ViewPager
            android:id="@+id/viewPager"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1.0"
            android:scrollbars="none" />

        <android.support.design.widget.TabLayout
            android:id="@+id/tabLayout"
            app:tabIndicatorColor="?attr/colorAccent"
            app:tabIndicatorHeight="0dp"
            app:tabPaddingStart="12dp"
            app:tabPaddingEnd="12dp"
            app:tabBackground="@color/cardview_light_background"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

    </LinearLayout>

</RelativeLayout>

2、tab 按钮 布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:gravity="center"
    android:layout_height="match_parent">

    <ImageView
        android:layout_marginTop="2dp"
        android:id="@+id/imageView"
        android:src="@mipmap/ic_launcher"
        android:layout_width="25dp"
        android:layout_height="25dp" />

    <TextView
        android:id="@+id/news_title"
        android:layout_marginTop="2dp"
        android:textSize="14sp"
        android:textColor="@drawable/selector_text_color"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

3、fragment_page

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center" />

2、Activity和其他

Activity

public class BottomTabActivity extends AppCompatActivity {

    private ViewPager viewPager;
    private TabLayout tabLayout;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_bottom_tab);

        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        toolbar.setTitle("底部Tab");
        setSupportActionBar(toolbar);
        getSupportActionBar().setHomeButtonEnabled(true);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                onBackPressed();
            }
        });

        viewPager = (ViewPager) findViewById(R.id.viewPager);
        tabLayout = (TabLayout) findViewById(R.id.tabLayout);

        SampleFragmentPagerAdapter pagerAdapter =
                new SampleFragmentPagerAdapter(getSupportFragmentManager(), this);

        viewPager.setAdapter(pagerAdapter);


        tabLayout.setupWithViewPager(viewPager);
        for (int i = 0; i < tabLayout.getTabCount(); i++) {
            TabLayout.Tab tab = tabLayout.getTabAt(i);
            if (tab != null) {
                tab.setCustomView(pagerAdapter.getTabView(i));
            }
        }

//        viewPager.setCurrentItem(1);
        tabLayout.getTabAt(0).getCustomView().setSelected(true);
    }


    public class SampleFragmentPagerAdapter extends FragmentPagerAdapter {
        final int PAGE_COUNT = 3;
        private String tabTitles[] = new String[]{"TAB1", "TAB2", "TAB3"};
        private Context context;


        public View getTabView(int position) {
            View v = LayoutInflater.from(context).inflate(R.layout.custom_tab, null);
            TextView tv = (TextView) v.findViewById(R.id.news_title);
            tv.setText(tabTitles[position]);
            ImageView img = (ImageView) v.findViewById(R.id.imageView);
            //img.setImageResource(imageResId[position]);
            return v;
        }

        public SampleFragmentPagerAdapter(FragmentManager fm, Context context) {
            super(fm);
            this.context = context;
        }

        @Override
        public int getCount() {
            return PAGE_COUNT;
        }

        @Override
        public Fragment getItem(int position) {
            return PageFragment.newInstance(position + 1);
        }

        @Override
        public CharSequence getPageTitle(int position) {
            return tabTitles[position];
        }
    }

    public static class PageFragment extends Fragment {
        public static final String ARG_PAGE = "ARG_PAGE";

        private int mPage;

        public static PageFragment newInstance(int page) {
            Bundle args = new Bundle();
            args.putInt(ARG_PAGE, page);
            PageFragment fragment = new PageFragment();
            fragment.setArguments(args);
            return fragment;
        }

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            mPage = getArguments().getInt(ARG_PAGE);
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            View view = inflater.inflate(R.layout.fragment_page, container, false);
            TextView textView = (TextView) view;
            textView.setText("Fragment   " + mPage);
            return view;
        }
    }
}

selector

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:color="@color/colorAccent" android:state_pressed="true" />
    <!-- pressed -->
    <item android:color="@color/colorAccent" android:state_selected="true" />
    <!-- focused -->
    <item android:color="@color/cardview_dark_background" />
    <!-- default -->

</selector>

底部Tab.gif

至此,把控件的东西说完了,但是还有属性的问题呢。

demo

五、md控件属性参考

属性的好说,下面附上一个比较完整的md控件属性参考

android:fitsSystemWindows="true"
是一个boolean值的内部属性,让view可以根据系统窗口(如status bar)来调整自己的布局,如果值为true,就会调整view的paingding属性来给system windows留出空间...
用于实现状态栏,即 沉浸式状态栏!

Toolbar

  • android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
  • app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
  • app:layout_scrollFlags="scroll|enterAlways" (CoordinatorLayout属性,子布局通过设置该属性确定是否可滑动)

说明:
app:popupTheme,这个属性就是用来自定义我们弹出的菜单的样式,在之前的Actionbar的溢出菜单,我们是不能自定义他的样式的,只能根据你的theme来选择黑白两种,不能自己定义,现在我们可以定义弹出菜单的样式。

CoordinatorLayout

  • app:layout_scrollFlags (子布局设置是否可滑动)
  • android:layout_gravity 属性控制组件在布局中的位置
  • app:layout_behavior="@string/appbar_scrolling_view_behavior" 通知布局中包含滑动组件!

子布局通过app:layout_scrollFlags确定是否可滑动.给需要滑动的组件设置 app:layout_scrollFlags="scroll|enterAlways" 属性。
设置的layout_scrollFlags有如下几种选项:
scroll: 所有想滚动出屏幕的view都需要设置这个flag- 没有设置这个flag的view将被固定在屏幕顶部。
enterAlways: 这个flag让任意向下的滚动都会导致该view变为可见,启用快速“返回模式”。
enterAlwaysCollapsed: 当你的视图已经设置minHeight属性又使用此标志时,你的视图只能已最小高度进入,只有当滚动视图到达顶部时才扩大到完整高度。
exitUntilCollapsed: 滚动退出屏幕,最后折叠在顶端。

CollapsingToolbarLayout

  • app:collapsedTitleGravity 指定折叠状态的标题如何放置,可选值:top、bottom等
  • app:collapsedTitleTextAppearance="@style/TextAppearance.CollapsedTitle"指定折叠状态标题文字的样貌
  • app:expandedTitleTextAppearance="@style/TextAppearance.ExpandedTitle"指定展开状态标题文字的样貌
  • app:contentScrim="?attr/colorPrimaryDark"指定CollapsingToolbarLayout完全被滚出到屏幕外时的ColorDrawableapp:expandedTitleGravity 展开状态的标题如何放置
  • app:titleEnabled指定是否显示标题文本
  • app:toolbarId指定与之关联的ToolBar,如果未指定则默认使用第一个被发现的ToolBar子View
  • app:expandedTitleMarginStart="10dp"
  • app:expandedTitleMargin
  • app:expandedTitleMarginBottom
  • app:expandedTitleMarginEnd 展开状态改变标题文字的位置,通过margin设置
  • app:layout_collapseParallaxMultiplier="0.7" 设置视差的系数,介于0.0-1.0之间。
  • app:layout_collapseMode="pin"(子布局设置折叠模式)有两种“pin”:固定模式,在折叠的时候最后固定在顶端;“parallax”:视差模式,在折叠的时候会有个视差折叠的效果。

CollapsingToolbarLayout主要是提供一个可折叠的Toolbar容器,对容器中的不同View设置layout_collapseMode折叠模式,来达到不同的折叠效果。

Floating Action Button (FAB)

  • app:fabSize="normal" 是用来定义 FAB 的大小的,normal 的意思是在大多数情况下标准尺寸为 56dp 的按钮,但是万一你想使用较小的一个, mini 是另一个选择,它的大小将变成 40dp。
  • app:elevation   为空闲状态下的阴影深度,
  • app:pressedTranslationZ   为按下状态的。
  • app:backgroundTint   是指定默认的背景颜色
  • app:rippleColor   是指定点击时的背景颜色
  • app:border    Width  border的宽度
  • app:fabSize   是指FloatingActionButton的大小,可选normal|mini
  • app:pressedTranslationZ   按下去时的z轴的便宜

TabLayout

  • app:tabIndicatorColor   tab的指示符颜色
  • app:tabSelectedTextColor   选择tab的文本颜色
  • app:tabTextColor   普通tab字体颜色
  • app:tabMode   模式,可选fixed和scrollable fixed是指固定个数,scrollable是可以横行滚动
  • app:tabGravity 对齐方式,可选fill和center

六、参考

参考:
ANDROIID-M
JuheNews系列之二 · ToolBar+AppBarLayout+CoordinatorLayout+CollapsingToolbarLayout
android CoordinatorLayout使用
[Android Material Design 控件常用的属性]
md控件属性参考
使用TabLayout实现底部Tab布局


 “阿敏其人” 简书博客

http://www.jianshu.com/p/1edeff139de5


个人修正:

感谢分享,有几点疑问,
关于这个Demo,三、AppBarLayout + CollapsingToolbarLayout
如果在CollapsingToolbarLayout布局中将ImageView和Toolbar位置调换,
那么沉浸式内容mCollapsingToolbarLayout.setContentScrim(getResources().getDrawable(R.mipmap.quan)); 
这行代码将不生效,收缩和扩展是同一张图片。

本着“代码可以更优雅”的准则,在MainActivity中:
因为ImageView就做了setImageResource一件事,所以可以把相关代码全部砍掉,在xml中直接设置属性android:background。
同样原因对于Toolbar我们可以一行代码搞定,少代码,省下一个引用的内存空间哈。
setSupportActionBar((Toolbar)findViewById(R.id.top_tb_design_collapsing));


如果直接这么做
mCollapsingToolbarLayout.setContentScrim(getDrawable(R.mipmap.quan));
还需要处理@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)之类的问题:
可以通过getResources()做:
mCollapsingToolbarLayout.setContentScrim(getResources().getDrawable(R.mipmap.quan));




四、TabLayout
不带这么玩的,亲~
public class SampleFragmentPagerAdapter extends FragmentPagerAdapter {
final int PAGE_COUNT = 3;
@Override
public int getCount() {
return PAGE_COUNT;
}

干掉PAGE_COUNT ,这么玩~
@Override
public int getCount() {
return mTabTitles.length;
}

这个为什么是静态类,把static去掉吧。
public static class PageFragment extends Fragment {



发布了166 篇原创文章 · 获赞 15 · 访问量 19万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览