Android高级UI开发(二十一)AppBarLayout与CollapsingToolbarLayout一分钟组合出视差效果
阅读原文时间:2021年04月25日阅读:1

今天继续看AppBarLayout的一个强大功能,那就是它结合CollapsingToolbarLayout可以1分钟作出我们常用的滑动视差效果,效果图如下:

1. 布局activity_main.xml

其实实现这个效果我们只需要配置布局文件即可,不需要写复杂的程序代码。接下来我们就来看一下这个神奇的布局文件,我们仍以MainActivity的activity_main.xml布局为例:

<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"
    tools:context=".MainActivity">
    <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:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="match_parent" >

            <android.support.v7.widget.CardView
                android:layout_width="300dp"
                android:layout_height="200dp"
                android:layout_margin="0dp"
                app:cardCornerRadius="20dp"
                app:cardElevation="10dp"
                app:contentPadding="5dp" >

                <ImageView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:scaleType="centerCrop"
                    android:src="@drawable/image2" />
            </android.support.v7.widget.CardView>

            <android.support.v7.widget.CardView
                android:layout_width="300dp"
                android:layout_height="200dp"
                android:layout_margin="0dp"
                app:cardCornerRadius="20dp"
                app:cardElevation="10dp"
                app:contentPadding="5dp" >

                <ImageView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:scaleType="centerCrop"
                    android:src="@drawable/image2" />
            </android.support.v7.widget.CardView>

            <android.support.v7.widget.CardView
                android:layout_width="300dp"
                android:layout_height="200dp"
                android:layout_margin="0dp"
                app:cardCornerRadius="20dp"
                app:cardElevation="10dp"
                app:contentPadding="5dp" >

                <ImageView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:scaleType="centerCrop"
                    android:src="@drawable/image2" />
            </android.support.v7.widget.CardView>

            <android.support.v7.widget.CardView
                android:layout_width="300dp"
                android:layout_height="200dp"
                android:layout_margin="0dp"
                app:cardCornerRadius="20dp"
                app:cardElevation="10dp"
                app:contentPadding="5dp" >

                <ImageView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:scaleType="centerCrop"
                    android:src="@drawable/image2" />
            </android.support.v7.widget.CardView>

            <android.support.v7.widget.CardView
                android:layout_width="300dp"
                android:layout_height="200dp"
                android:layout_margin="0dp"
                app:cardCornerRadius="20dp"
                app:cardElevation="10dp"
                app:contentPadding="5dp" >

                <ImageView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:scaleType="centerCrop"
                    android:src="@drawable/image2" />
            </android.support.v7.widget.CardView>

            <android.support.v7.widget.CardView
                android:layout_width="300dp"
                android:layout_height="200dp"
                android:layout_margin="0dp"
                app:cardCornerRadius="20dp"
                app:cardElevation="10dp"
                app:contentPadding="5dp" >

                <ImageView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:scaleType="centerCrop"
                    android:src="@drawable/image2" />
            </android.support.v7.widget.CardView>

            <android.support.v7.widget.CardView
                android:layout_width="300dp"
                android:layout_height="200dp"
                android:layout_margin="0dp"
                app:cardCornerRadius="20dp"
                app:cardElevation="10dp"
                app:contentPadding="5dp" >

                <ImageView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:scaleType="centerCrop"
                    android:src="@drawable/image" />
            </android.support.v7.widget.CardView>
        </LinearLayout>
    </android.support.v4.widget.NestedScrollView>
    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="256dp"
        android:fitsSystemWindows="true">
        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:contentScrim="#30469b"
            app:expandedTitleMarginBottom="100dp"
            app:expandedTitleMarginStart="100dp"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <ImageView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:scaleType="centerCrop"
                android:src="@drawable/image"
                app:layout_collapseMode="parallax"
                app:layout_collapseParallaxMultiplier="0.7"  />

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


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

 实现了这个效果的过程是这样的:当我们上滑NestedScrollView的时候,AppBarLayout会控制CollapsingToolbarLayout不断让Imageview折叠,直到Toolbar的底部停止。在折叠的时候滑动界面往上移动的速度>Imageview折叠的速度,从而形成了视差效果。我们要为这些控件配置一些属性才能使它们相互配合起来。

1.1  NestedScrollView控件配置: 

      滑动部分,里面内嵌了足够长的控件(Cardview),与Scrollview一样可以滑动;

(1)app:layout_behavior="@string/appbar_scrolling_view_behavior属性:

        配置了app:layout_behavior="@string/appbar_scrolling_view_behavior属性,也就是指定了behavior,behavior用来捕获  NestedScrollView的滑动事件,并处理一些动画效果。这个behavior我们从名字来看它的来头不小,它正是AppbarLayout的一个内部类behavior.所以推测它可以处理appBarLayout内部包含的控件的动画效果,即我们的折叠视差效果。NestedScrollView控件所配置的behavior就是用来控制AppBarLayout内嵌的这个CollapsingToolbarLayout控件的行为,即让CollapsingToolbarLayout内嵌的折叠布局,这里是一张图片与NestedScrollView的滚动形成视差效果。

1.2 CollapsingToolbarLayout(折叠控件)控件配置:

    它里面嵌套了视差图片Imageview与Toolbar控件。它控制内嵌的Imageview的滑动视差效果。在这个例子中配置了如下属性:

 (1)app:contentScrim="#30469b"

        这个用以表示当滑动快到Toolbar的底部边缘时,正在滑动的imageview消失变成了一个色块布局,同时Toolbar的颜色也会            变成相同的颜色,这里是蓝色。

(2)app:expandedTitleMarginBottom="100dp",app:expandedTitleMarginStart="100dp"

       CollapsingToolbarLayout处于展开状态时,CollapsingToolbarLayout布局中的title的位置,距离CollapsingToolbarLayout的左边距是100dp,底部边距也是100dp。关于这个title的文本我们用程序代码去设置,见后面的MainActivity分析,当然我们也可以在CollapsingToolbarLayout XML标签里配置title文本.

(3)app:layout_scrollFlags="scroll|exitUntilCollapsed"

       这个属性决定了折叠动作。让内嵌的折叠布局(Imageivew)可以滑动,直到折叠效果完成(滑动到Toolbar的底边缘)隐藏Imageview. 在这里我们只看到了滑动,和什么时候隐藏,我们并没有看到任何关于视差效果的配置。视差效果的配置是在折叠布局里设置的,在这个例子中是一个Imageview。接下来我们就来看一下Imageview(折叠布局)是如何配置的。

1.3  折叠内容配置(这里是一个Imageview图片):

(1)app:layout_collapseMode="parallax" 这个用于配置折叠隐藏的速度。

      app:layout_collapseParallaxMultiplier="0.7" 这个是视差系数,就是折叠的速度。值越大Imagview折叠的速度越快,例如配置成2的效果是:当NestedScrollView还没有滑动到Toolbar附近,离Toolbar还有好长一段距离时,这时Imageview已经往下移动了好大一截,快要完全隐藏折叠的节奏。这里我们解释了Imageview如何配置成视差效果,我们再看看Toolbar配置了什么。

1.4  Toolbar的配置:

app:layout_collapseMode="pin" 
&nbsp;       表示当完全折叠时,Toolbar保持在顶端不动。

1. 5  总结

好了我们来总结一下这些配置,以便我们在后面修改这些配置来演示其它效果:

NestedScrollView

      app:layout_behavior="@string/appbar_scrolling_view_behavior  //behavior

CollapsingToolbarLayout:

      app:contentScrim="#30469b"       //Toolbar及底部附近的颜色。

      app:expandedTitleMarginBottom="100dp",      app:expandedTitleMarginStart="100dp" //下边距,左边距。

      app:layout_scrollFlags="scroll|exitUntilCollapsed"  //滚动且折叠完后整个折叠布局才隐藏。

Imageview:

  app:layout_collapseMode="parallax"    //这个就是视差效果。 app:layout_collapseParallaxMultiplier="0.7" 折叠布局折叠的速度。

2. MainActivity.java

第1节中activity_main.xml对应的程序代码

package com.example.administrator.collapsingtoolbarlayout;
import android.graphics.Color;
import android.support.design.widget.CollapsingToolbarLayout;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.view.View;

public class MainActivity extends AppCompatActivity {

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

        //Toolbar
        Toolbar toolbar;
        toolbar = (Toolbar)findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onBackPressed();
            }
        });

        /*
        CollapsingToolbarLayout
            使用CollapsingToolbarLayout必须把title设置到CollapsingToolbarLayout上
            扩展title与折叠title会从白色随着滑动折叠自然过渡到绿色
         */

        CollapsingToolbarLayout mCollapsingToolbarLayout = 
(CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar_layout);
        mCollapsingToolbarLayout.setTitle("周星驰");

        //通过CollapsingToolbarLayout修改字体颜色
        mCollapsingToolbarLayout.setExpandedTitleColor(Color.WHITE);//设置还没收缩时状态下字体颜色
        mCollapsingToolbarLayout.setCollapsedTitleTextColor(Color.GREEN);//设置收缩后Toolbar上字体的颜色
    }
}

再上述代码里我们用代码 

mCollapsingToolbarLayout.setTitle("Colla");设置了CollapsingToolbarLayout布局在展开时的标题文本。

setExpandedTitleColor与setCollapsedTitleTextColor分别设置了展开时与折叠时标题颜色的变化。
这里它不会突然从白色变成绿色,而是有一个渐变的过程。在此你可能会想到是不是title也被分为展开时标题和折叠时文本,
两个文本可以设置不同的内容,关于这些尝试性的改动及运行效果我们将在第3节中展示,第3节也会让您加深对各属性的理解。
关于本文的第3节今日恐怕是没有时间了,以后再完善之。

依照惯例,还是给出当前阶段的源码下载地址:https://download.csdn.net/download/gaoxiaoweiandy/10973541

附录:

使用心得

这个app:layout_behavior="@string/appbar_scrolling_view_behavior" 其实就是

AppBarLayout.ScrollingViewBehavior类。

我们完全可以自定义Behavior,让其继承AppBarLayout.ScrollingViewBehavior,关于自定义behavior将在后面两篇文章讲解。这里贴出一个继承代码:

package com.example.administrator.collapsingtoolbarlayout;

import android.content.Context;
import android.support.annotation.NonNull;
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.CoordinatorLayout;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class MyBehavior extends AppBarLayout.ScrollingViewBehavior {

    public MyBehavior(Context arg0, AttributeSet arg1) {
        super(arg0, arg1);
        // TODO Auto-generated constructor stub
    }
    @Override
    public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View directTargetChild, @NonNull View target, int axes, int type) {

        return (axes == ViewCompat.SCROLL_AXIS_VERTICAL)||super.onStartNestedScroll(coordinatorLayout, child, directTargetChild,
                target, axes);

    }

    @Override
    public void onNestedPreScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View target, int dx, int dy, @NonNull int[] consumed, int type) {

        Button btTest = coordinatorLayout.findViewById(R.id.btTest);

        Log.i("onNestedPreScroll","dy="+dy);
        if(dy > 20)
        {
            int color = coordinatorLayout.getContext().getResources().getColor(R.color.white);
            btTest.setBackground(null);
            btTest.setTextColor(color);
        }
        else if(dy < -20)
        {
            int color = coordinatorLayout.getContext().getResources().getColor(R.color.colorAccent);
            btTest.setBackground(null);
            btTest.setTextColor(color);
        }

        super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type);
    }
}

这里是用于监听滑动事件的,其中以下代码表示监听垂直方向VERITCAL上的滑动。

&nbsp; &nbsp; return (axes == ViewCompat.SCROLL_AXIS_VERTICAL)||super.onStartNestedScroll(coordinatorLayout, child, directTargetChild,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; target, axes);

然后在onNestedPreScroll里对按钮btTest做了处理:改变颜色;同时AppBarLayout.ScrollingViewBehavior本身就自带了很多功能,结合折叠控件CollapsingToolbarLayout可以作出折叠视差效果,就是本篇所讲的视差效果。

2. 其它

发现一个demo里floatingActionButton里设置了这样一个属性

app:layout_anchor="@id/appbar"

app:layout_anchorGravity="bottom|right"

表示floatingActionButton与appbar关联在一起,并且浮动在appbar的右下角。

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器